文章目录
- Pinia
- 1.使用
- 2. pinia-计数器案例
- 3. getters实现
- 4. 异步action
- 5. storeToRefsx 数据解构保持响应式
- 6. pinia 调试
- 项目起步
- 1.项目初始化和git管理
- 2. 使用ElementPlus
- 3. ElementPlus 主题色定制
- 4. axios 基础配置
- 5. 路由设计
- 6. 静态资源初始化和 Error lens安装
- 7.scss自动导入
- 8. Layout静态模板结构搭建
- 9. Layout字体图标引入
- 10.Layout一级导航渲染
- 11. layout - 吸顶导航
- 12. layout - Pinia优化重复请求
- 小结
Pinia
1.使用
vue专属状态管理库,vuex的替代
优势:
- 提供了更简单的API ,去掉了mutation
- 提供了组合式API
- 去掉了modules,每个store都是独立的模块
- 搭配TS一起使用提供可靠的类型判断
Pinia添加到vue项目中:
- 创建一个新vue项目: create init vue@latest,装依赖,项目跑起来
- 打开pinia官方文档,是个小菠萝。点击开始,有个安装选项
- 我是使用npm安装:npm install pinia
- 按照文档使用 pinia
- 在项目中实际应用(记不住看文档使用即可
2. pinia-计数器案例
看官方文档的基础实例学习如何使用
找和vue3语法相似的语法进行使用
- 创建一个 store( state+action )
在src添加一个stores文件夹,新建文件counter.js
//counter.js // 导入一个方法 defineStore import { defineStore } from 'pinia' import {ref} form 'vue' // 参数:标识 回调函数 //!!变量名字需保持规范:use+函数名 //useCounterStore是一个方法,需执行才能得到真是store实例对象 export const useCounterStore = defineStore('counter', () => { //1.定义数据state const count = ref(0) // 2.定义修改数据的方法(action 同步+异步) const increment = () => { count.value++ } // 3.以对象的方式return供组件使用 return { count, increment } })
- 组件使用 store
3. getters实现
pinia中的getters直接使用computed函数进行模拟
//counter.js // 导入一个方法 defineStore import { defineStore } from 'pinia' import { computed, ref } from 'vue' //定义并暴露一个函数useCounterStore 参数:标识 回调函数 export const useCounterStore = defineStore('counter', () => { //1.定义数据state const count = ref(0) // 2.定义修改数据的方法(action 同步+异步) const increment = () => { count.value++ } // -- -- getters实现 -- -- const doubleCount = computed(() => count.value * 2) // 3.以对象的方式return供组件使用 return { count, increment, doubleCount } })
这时useCountStore中就有了doubleCount这个方法了
{{ counterStore.doubleCount }}
4. 异步action
action中实现异步和组件中定义数据和方法的风格完全一致
安装axios: npm install axios
举个获取数据列表 的栗子,获取数据接口地址:http://geek.itheima.net/v1_0/channels
//counter.js const list = ref([]) //存放列表数据 //异步action const getList = async () => { const res = await axios.get('http://geek.itheima.net/v1_0/channels'); } //返回,让组件可以拿到 return{ list, getList }
看一下网页的网络
给list赋值
//异步action const getList = async () => { const res = await axios.get('http://geek.itheima.net/v1_0/channels'); list.value = res.data.data.channels }
渲染在页面上,使用v-for
{{ counterStore.doubleCount }}
- {{ item.name }}
效果:
5. storeToRefsx 数据解构保持响应式
辅助保持数据(state+getter)的响应式解构
方法可以正常解构赋值哈
const {count,doubleCount} = counterStore
这样解构是不可以的,会造成响应式丢失,也就是数据变化页面不会更新。
我们可以这样写:
const {count,doubleCount} = storeToRefs(counterStore);
6. pinia 调试
使用之前使用的devtools调试工具
项目起步
1.项目初始化和git管理
创建并打开,将项目运行起来(按照绿色的来做):
这样说明成功
下面我们看一下 小兔鲜 需要哪些基础目录,
我们按照下面的图片在刚创建好的项目中创建文件夹。
componsables组合函数文件夹:存放通用的函数
使用git管理项目,手动初始化
执行命令并完成手动提交
git init git add . git commit -m "init"
配置别名路径联想提示
编写代码,一旦输入@/,vscode会立刻联想出src所有的子目录和文件,统一文件路径,不容易出错。
步骤:1.根目录新增jsconfig.json文件
2.添加配置项
2. 使用ElementPlus
我们在这个项目中使用了通用性组件,由ElementPlus提供
步骤:安装 - 按需引入 - 测试组件
看文档
安装elementPlus:npm install element-plus --save
安装两个插件:npm install -D unplugin-vue-components unplugin-auto-import
安装之后我们来依照文档配置这两个插件
//vite.config.js //按需导入element Plus插件 import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ //插件配置文件 vue(), //elementPlus插件 AutoImport({ resolvers: [ElementPlusResolver()], }), Components({ resolvers: [ElementPlusResolver()], }), ],
配置文件写好后,重启项目
做个测试,看看组件能不能使用
elementPlus 生效就OK
3. ElementPlus 主题色定制
小免鲜主题色和elementPlus默认的主题色存在冲突
通过定制主题让elementPlus的主题色和小兔鲜项目保持一致
步骤:
-
安装sass:npm i sass -D
-
准备定制文件 :styles/element/index.scss
/* 只需要重写你需要的即可 */ @forward 'element-plus/theme-chalk/src/common/var.scss' with ( $colors: ( 'primary': ( // 主色 'base': #27ba9b, ), 'success': ( // 成功色 'base': #1dc779, ), 'warning': ( // 警告色 'base': #ffb302, ), 'danger': ( // 危险色 'base': #e26237, ), 'error': ( // 错误色 'base': #cf4444, ), ) )
- 对ElementPlus样式进行覆盖:通知Element使用scss语言,自动导入定制的scss文件覆盖。
//vite.config.js import { fileURLToPath, URL } from 'node:url' import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' //按需导入element Plus插件 import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ //插件配置文件 vue(), //elementPlus插件 AutoImport({ // 1.配置elementPlus采用sass样式配色系统 resolvers: [ElementPlusResolver()], }), Components({ resolvers: [ElementPlusResolver({ importStyle: 'sass' })], }), ], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } }, css: { preprocessorOptions: { scss: { //2.自动导入定制化样式文件进行样式覆盖 additionalData: `@use "@/styles/element/index.scss" as *;` } } } })
4. axios 基础配置
安装:npm i axios
配置基础实例(统一接口实例)
在utils创建一个http.js
//axios基础封装 import axios from "axios"; const httpInstance = axios.create({ baseURL: 'http://pcapi-xiaotuxian-front-devtest.itheima.net', timeout: '5000' //5s }) //拦截器,默认先这样写着,后面有需求再配置 // axios请求拦截器 instance.interceptors.request.use(config => { return config }, e => Promise.reject(e)) // axios响应式拦截器 instance.interceptors.response.use(res => res.data, e => { return Promise.reject(e) }) export default httpInstance
扩展:如果项目里面不同的业务模块需要的接口基地址不同,该如何来做?
答:axios.create()方法可以执行多次,每次执行就会生成一个新
的实例
const http1 = axios.create({baseURL:'url1'}) const http1 = axios.create({baseURL:'url2'})
5. 路由设计
-
设计首页和登录页的路由(一级路由)
路由设计规则:找内容切换的区域,如果是页面整体切换,则为一级路由
eslintrc.cjs配置,避免命名报错:
/* eslint-env node */ module.exports = { root: true, 'extends': [ 'plugin:vue/vue3-essential', 'eslint:recommended' ], parserOptions: { ecmaVersion: 'latest' }, rules: { 'vue/multi-word-component-names':0, //不再强制要求组件命名 } }
删除views文件夹下的组件,创建两个新文件夹Login和Layout,分别创建一个index.vue文件,写入一些代码。
我是注册页/首页
打开router文件夹的index.js,删掉默认的代码。导入login和layout组件,在routes中配置path、component属性
import { createRouter, createWebHistory } from 'vue-router' import Login from '@/views/Login/index.vue' import Layout from '@/views/Layout/index.vue' // createRouter:创建router实例对象 // createWebHistory:创建history模式的路由 const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', component: Layout }, { path: '
App.vue中写入一级路由出口组件
项目运行效果:
- 设计分类页和默认Home页路由(二级路由)
路由设计原则:找内容切换的区域,如果是在一级路由页的内部切换,则为二级路由
和上面一样,在views新增两个文件夹,一个Home,一个Category,分别创建一个index.vue,随便写点内容
//router index.js import { createRouter, createWebHistory } from 'vue-router' import Login from '@/views/Login/index.vue' import Layout from '@/views/Layout/index.vue' import Home from '@/views/Home/index.vue' import Category from '@/views/Category/index.vue' // createRouter:创建router实例对象 // createWebHistory:创建history模式的路由 const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', component: Layout, children: [ { path: '', component: Home }, { path: 'category', component: Category } ] }, { path: '/login', component: Login } ] }) export default router
这两个二级路由要在Layout组件里给准备路由出口
我是首页
效果:
6. 静态资源初始化和 Error lens安装
图片资源 - 把images文件夹放到assets目录下
样式资源 - 把common.scss文件放到styles目录下(这个文件在资源里面,自己拿)。
在main.js中引入common.scss
//main.js //引入初始化样式文件 import '@/styles/common.scss'
error lens是一个实时提供错误警告信息的VScode插件,方便开发,在扩展程序里搜索然后安装就可以了。
7.scss自动导入
在项目里一些组件共享的色值会以scss变量的方式统一放到一个名为var.scss 的文件中。
正常组件中使用,需要先导入scss文件,再使用内部的变量,比较繁琐,自动导入可以免去手动导入的步骤,直接使用内部的变量。
配置步骤:
- 新增一个var.scss文件,存入色值变量
$xtxColor: #27ba9b; $helpColor: #e26237; $sucColor: #1dc779; $warnColor: #ffb302; $priceColor: #cf4444;
- 通过vite.config.js配置自动导入文件
css: { preprocessorOptions: { scss: { //2.自动导入定制化样式文件进行样式覆盖 additionalData: ` @use "@/styles/element/index.scss" as *; @use "@/styles/var.scss" as *; `, } } }
8. Layout静态模板结构搭建
Layout文件夹创建一个components文件夹,创建LayoutFooter.vue、LayoutHeader.vue、LayoutNav.vue组件。
小兔鲜 -
首页 -
居家 -
美食 -
服饰
修改一下Layout的index.vue
效果:
9. Layout字体图标引入
这里的图标没有引入,我们使用的是阿里的字体图标库,使用 font-class 引用的方式
将这个加入到index.html文件中
效果:
看下面这个周杰伦旁边的小人儿
它对应的代码如下
10.Layout一级导航渲染
静态结构已经全部搭建好了,我们要使用后端接口渲染 渲染一级导航路由,也就是这:
实现步骤:
- 根据接口文档封装接口函数
- 发生请求获取数据列表
- v-for渲染页面
在apis文件夹下创建layout.js文件,封装接口
import httpInstance from '@/utils/http.js' //获取目录 export function getCategoryAPI() { return httpInstance({ url: '/home/category/head' }) }
来到LayoutHeader组件,引入接口
封装一个函数getCategory,返回的是promise对象,使用async/await。
在挂载完成之后(onMounted)调用函数getCategory。
打印res看一下请求的数据,定义一个响应式空数组categoryList接收后台传入的数据。
将 请求 封装进 函数 中是因为方便书写请求前后的逻辑
获取数据成功之后,使用v-for渲染数据
-
{{ item.name }}
效果:
11. layout - 吸顶导航
需求:浏览器上下滚动过程中,如果距离顶部的滚动距离大于78px,吸顶导航显示,小于78px隐藏
步骤:
- 准备吸顶导航组件
- 获取滚动距离
- 滚动距离作判断条件控制组件盒子展示或隐藏
吸顶导航组件
-
首页 -
居家 -
美食 -
服饰 -
母婴 -
个护 -
严选 -
数码 -
运动 -
杂项
品牌 专题 在Layout文件夹下的index.vue中引入这个组件,使用起来
关键样式(LayoutFixed中):
.app-header-sticky { width: 100%; height: 80px; position: fixed; left: 0; top: 0; //置顶 z-index: 999; background-color: #fff; border-bottom: 1px solid #e4e4e4; // 此处为关键样式!!! // 状态一:往上平移自身高度 + 完全透明 transform: translateY(-100%); //平移出页面 opacity: 0; //透明度为0 // 状态二:移除平移 + 完全不透明 //想让组件显示出来只需要加上class = "show" 即可 &.show { transition: all 0.3s linear; transform: none; opacity: 1; //完全不透明 }
获取滚动距离,不自己写了,使用一个vueUse插件,安装一下
安装:npm i @vueuse/core
滚动使用的是useScroll,解构的这个y就是垂直方向滚动的距离。
import { useScroll } from '@vueuse/core' const { y } = useScroll(window)
当y>78时,show生效,我们使用 vue 的动态类实现方式
12. layout - Pinia优化重复请求
我们要把 吸顶导航 组件也转化成数据动态获取的,修改完后我们发现请求了两次数据
-
{{ item.name }}
品牌 专题 小兔鲜~ -
{{ item.name }}
stores新增category.js
import { ref } from 'vue' import { defineStore } from 'pinia' import { getCategoryAPI } from '@/apis/layout' export const useCategoryStore = defineStore('category', () => { // 导航列表的数据管理 // state 导航列表数据 const categoryList = ref([]) // action 获取导航数据的方法 const getCategory = async () => { const res = await getCategoryAPI() categoryList.value = res.result } return { categoryList, getCategory } })
使用:
Login文件夹的index.vue
删掉(注释)LoginFixed和LoginHeader中相关的代码
-
{{ item.name }}
-
{{ item.name }}
OK,没问题
小结
本篇文章,主要学习了Pinia管理数据,以及Layout的相关知识
私密马赛,图片有亿点糊,我是在typra上面写的,截到csdn上就糊掉了呜呜
祝大家学习顺利!!
-
-
-
- 通过vite.config.js配置自动导入文件
- 新增一个var.scss文件,存入色值变量
- 设计分类页和默认Home页路由(二级路由)
-
- 对ElementPlus样式进行覆盖:通知Element使用scss语言,自动导入定制的scss文件覆盖。
- 组件使用 store
- 创建一个 store( state+action )
- 我是使用npm安装:npm install pinia
转载请注明来自码农世界,本文标题:《【B站 heima】小兔鲜Vue3 项目学习笔记Day02》
还没有评论,来说两句吧...