create-vue 与 Pinia 上手试玩
导言
不得不说前端是真的卷,Vue-cli 的核心开发者这又出了一个新的 cli,create-vue,基于 Vite2 和 Vue3 的脚手架工具。目前虽然还只是在开发中,很多功能都不太完善,但可以想象到未来 create-vue 大概率会逐渐替代掉 vue-cli 的...
一、create-vue
1. 安装
安装很简单,只需要一行 npm 语句,不过需要注意下,create-vue 只能安装在非中文路径、中文名称的文件夹下。
npm init vue@next
一些配置:
项目名称
是否安装 TS
是否安装 JSX
是否安装 router
是否安装 vuex
是否安装 Cypress 测试
文件目录配置也没有太大区别
进入文件夹后首先安装配置文件
npm install
运行
npm run dev
首页:
2. 简单体验
其实使用上与 Vue-cli+Vue3 没区别,只是这个脚手架组件页面的 template、script、style 三者标签顺序有改变。
App.vue
嵌套路由
页面展示
二、Pinia
官网:
pinia.esm.dev/
Pinia 是 Vuex 团队成员新开发的一个 Vue 的状态管理方案。
在 Pinia 中减去了 mutations 以及 module 两个概念,转而使用 actions 代替 mutations 完成同异步方法。
同时 Pinia 中的每个 store 都拥有自己的 id,是互相独立的状态库,且在 store 中可以通过 id 直接导入其它的 store 使用。
其优点:
完整的 TypeScript 支持。
及其轻巧(体积大约 1kb)
Store 中的 Actions 配置项既可以直行同步方法也可以支持异步方法。
模块不需要嵌套,可以声明多个 Store。
支持 Vue DevTools、SSR 和 Webpack 代码拆分。
**Tips:**Pinia 不是用来代替 Vuex 的,它们的应用场景不同。
Pinia 该什么时候使用?
Pinia 是轻量级的,体积小,更加适合中小型项目,如果是大型项目还是更加适合 Vuex。
Pinia 中无论同步还是异步改变 state,都用 Actions,如果在 Vuex 中分辨不清 mutations 和 Actions 的概念可以使用 Pinia。
Pinia 中完整支持 TypeScript,不会给 Vuex 添加 TypeScript,就用 Pinia。
1. 安装和配置 Pinia
安装:
npm i pinia@next
在入口文件中挂载 Pinia
import { createApp } from 'vue' import App from './App.vue' import router from './router' // 引入 Pinia import { createPinia } from 'Pinia' const app = createApp(App) // 使用 Pinia app.use(createPinia()) app.use(router) app.mount('#app') 复制代码
在 src/stores/index.js 文件夹中声明 store。
Pinia 通过 defineStore 定义 store,这个 API 拥有两个参数,第一个参数是它的唯一性 id,通过这个唯一性 id,我们可以在其它仓库去引用它。
第二个参数就是常规的 store、getters、actions 可选项。
defineStore('id', {options})
// 引入 Pinia 定义 import { defineStore } from 'pinia' // 定义 export const useUserStore = defineStore('user', { state: () => { return { name: 'achens' } } }) 复制代码
在组件页面引入并使用
<script setup> // 引入 useUserStore import { useUserStore } from './stores'; // 使用 useUserStore const store = useUserStore() // 输出:achens console.log(store.name) </script> 复制代码
2. state 与 getters 的使用
1.使用 storeToRefs 引入 state
使用 Pinia 中的 storeToRefs 去解构引入的 store。
storeToRefs 会将 store 中的 state、getters、actions 转换为 ref 响应式对象。
// 引入 storeToRefs import { storeToRefs } from 'pinia' // 引入 useUserStore import { useUserStore } from './stores'; // 使用 storeToRefs 解构式拿出 useUserStore 中的 state const { name } = storeToRefs(useUserStore()) // 输出: ref 对象 console.log(name) // 输出:张三 console.log(name.value) 复制代码
将其放到页面中也是直接使用
<template> <h1>Hello achens!</h1> <!-- <p>直接使用 store:{{ store.name }}</p> --> <p>使用 storeToRefs:{{ name }}</p> <router-link to="/home">首页</router-link> <router-link to="/about">关于页</router-link> <router-view></router-view> </template> 复制代码
页面呈现
2. Pinia 中的 Getters
1. 简单使用 Getters
定义 getters 与 Vuex 没有什么太大的区别。
import { defineStore } from 'pinia' export const useUserStore = defineStore('user', { state: () => { return { name: '张三', count: 5 } }, getters:{ // 以箭头函数的方式声明一个 getters,使 state.count 的值永远乘以2。 // getters 的第一个参数永远是 state,这点与 Vuex 相比没有区别。 doubleCount: state => state.count * 2 } }) 复制代码
<template> <h1>Hello achens!</h1> <!-- <p>直接使用 store:{{ store.name }}</p> --> <p>使用 storeToRefs:{{ name }}</p> // 使用 getters <p>{{ count }} -- {{ doubleCount }}</p> <router-link to="/home">首页</router-link> <router-link to="/about">关于页</router-link> <router-view></router-view> </template> 复制代码
页面呈现
2. 访问自己 store 中的其它 Getters
如果想要在 getters 中互相访问,就必须得将箭头函数改为普通函数的形式,在通过 this 调用相同 store 中的其它 getters。
import { defineStore } from 'pinia' export const useUserStore = defineStore('user', { state: () => { return { name: '张三', count: 5 } }, getters:{ doubleCount(state){ return state.count * 2 }, // 在 getters 中使用其它 getters doubleCountPlus(state){ return this.doubleCount + 1 } }) 复制代码
<template> <h1>Hello achens!</h1> <!-- <p>直接使用 store:{{ store.name }}</p> --> <p>使用 storeToRefs:{{ name }}</p> <p>{{ count }} -- {{ doubleCount }} -- {{ doubleCountPlus }}</p> <router-link to="/home">首页</router-link> <router-link to="/about">关于页</router-link> <router-view></router-view> </template> 复制代码
页面呈现
3. 给 Getters 传递参数
想要给 getters 传参,稍微有那么点麻烦,如果传了参数,则必须在其内部用箭头函数接收并使用它,最后将其返回出去。
// ...多余代码不粘贴了 doubleCountPlus(state, a){ // 使用箭头函数拿到这个参数并在使用完后返回 return a => { return this.doubleCount + a } } 复制代码
<!-- 多余代码不粘贴了 --> <p>{{ count }} -- {{ doubleCount }} -- {{ doubleCountPlus(5) }}</p> 复制代码
页面呈现
4. 访问其它 store 中的 Getters
在 src/store 下新建 default.js 文件夹声明一个新的 store。
import { defineStore } from 'pinia' export const useDefaultStore = defineStore('default', { state: () => { return { time: 2 } }, getters:{ calcTime(state){ return state.time + 2 } }, }) 复制代码
在 index.js 中引用 default.js 中的 useDefaultStore。
import { defineStore } from 'pinia' // 引入同文件夹下的 useDefaultStore import { useDefaultStore } from './default' export const useUserStore = defineStore('user', { state: () => { return { name: '张三', count: 5 } }, getters:{ doubleCount(state){ return state.count * 2 }, doubleCountPlus(state, a){ return a => { return this.doubleCount + a } }, addDefault(state){ // 拿到 useDefaultStore const defaultStore = useDefaultStore() return state.count + defaultStore.calcTime } } }) 复制代码
<p>{{ count }} -- {{ doubleCount }} -- {{ doubleCountPlus(5) }}</p> <p>{{ addDefault }}</p> 复制代码
页面呈现:
3. 使用 actions 处理同异步任务
1. 处理同步任务
在 actions 中如果要修改 state 中的值的话,得使用 this.xxx 来获取 state 中的数据并进行修改。
// ... 其它代码省略 actions:{ addCount(num){ this.count += num } } 复制代码
而且不能使用 storeToRefs 引用 actions 方法。
// 在 useUserStore 中拿出方法 const { addCount } = useUserStore() 复制代码
页面中也如正常方式一样使用就可以。
<p>{{ count }}</p> <button @click="addCount(2)">点击</button> 复制代码
每次点击 count 加 2.
2. 处理异步任务
添加定时器设置为异步任务也没有任何问题。
actions:{ addCount(num){ setTimeout(() => { this.count += num }, 1000) } } 复制代码
现在页面会在延迟一秒再去更新数据。
4. 品牌管理案例
这里只提供思路。
1. 渲染数据
v-for 渲染使用 storeToRefs 结构出来的 state(brandList)。
2. 添加数据
v-model 双向绑定 state 中的数据对象(brand)。 v-on 绑定 actions 点击事件 addBrand(),将 brand 值加入(使用 push) brandList 中。并清空 brand 的值。
3. 删除数据
v-on 绑定 actions 点击事件 delBrand(id),并在点击时将本行 brand 的 id 传入。然后通过 id 删除(filter)指定 brand。 this.brandList = this.brandList.filter(item => itme.id ! == id)
id 不等于就返回
id 等于就不返回
4. 搜索数据
在 state 中添加一个 keywords 搜索字段,并使用 v-model 与其对应的 input 进行双向绑定。 在之后定义一个 searchResult 计算属性,并对 brandList 中的每一项品牌名称都进行一遍过滤,返回包好关键字的每一项。 state.brandList.filter(item => item.name.includes(state.keywords)) 最后将 v-for 中的 brandLIst 替换成 searchResult。
三、结语
总的来说 create-vue 与 Vue-cli 使用并无大异,只是说一个是用 Webpack5 作为打包工具,一个则是使用 Vite2 打包工具。且 Vue-cli 可选 Vue2、3 的版本,而 Create-vue 则是默认 Vite2 + Vue3 +
四、坑
1. 坑一,create-vue 安装路径不能有中文。
2. 坑二,项目配置名称中不能带加号
如图必须是:create-vue-pinia。
而不能是:create-vue+pinia。
否则就会报错:
作者:achens
链接:https://juejin.cn/post/7066061740257214472