Vue3 中的 Vue-Router 和 VueX详解
John是橘红 人气:0Vue3 中的 Vue-Router 和 VueX
先使用 vue create 指令来创建 vue 工程项目,并选择自定义,将 Router 和 VueX 勾上。
勾上以后看主入口 main.js,可以看到项目自动帮我们注册了 vue-router 和 VueX。
// main.js createApp(App).use(store).use(router).mount('#app')
1. Vue-Router 路由的理解和使用
路由是指根据 url 的不同,展示不同的内容。
查看 src 文件夹里的 router,这就是来处理路由的地方。
其中,index.js 有关键的代码
const routes = [ { path: '/', name: 'home', component: HomeView }, { path: '/about', name: 'about', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue') } ]
定义了两个路由项。当访问根目录,就加载 HomeView 这个组件。如果访问 /about
,则懒加载 AboutView 这个组件。
import(...)
是异步加载路由的方法。因为如果一口气全部组件加载出来,主页的加载的性能将会很低,为了提高组件的加载性能,使用懒加载按需加载,等进入 /about 或其他的页面再加载响应部分的代码。但是异步加载代码也有相应的问题,就是去其他的页面可能会有卡顿(其实就是加载的时间分摊了)。
因此,vue-router 就是根据 url 不同来显示不同组件的特性。
现在查看根组件 App.vue,上面有关键的代码:
<template> <nav> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> </nav> <router-view/> </template>
router-link 是跳转路由的标签,点击后就会跳转到相应的路由。
router-view 负责展示当前路由对应的组件内容。例如上面的代码,当跳转到根路径上时,router 会进行搜索,当搜索到匹配项时,便显示相应的组件 HomeView。
2. VueX 语法详解
在文首就看到了,注册了 VueX,接下来看 src 的 store 目录,这里边的 index.js 可以看到以下内容,稍后会讲。
export default createStore({ state: { }, getters: { }, mutations: { }, actions: { }, modules: { } })
2.1 VueX 是什么
VueX 是数据管理框架。之前的数据传递都是父子之间的传递,虽然也有 provider 之类的方法进行跨级传递,但是可维护性也不会特别高。
VueX 提供了一个全局都可以使用的数据管理仓库,不用考虑父子传值之类的问题,并且可以跨页面传递数据。提高了可维护性。
使用方法
提供数据:在 store 里的 state 里定义一些数据
// VueX 创建了一个全局唯一的仓库,用来存放全局的数据 export default createStore({ state: { name: "John", }, getters: { }, mutations: { }, actions: { }, modules: { } })
在需要用数据的地方通过 this.$store
获取即可
<template> <div>{{ myName }}</div> </template> <script> export default { name: "LoginView", computed: { myName() { return this.$store.state.name; }, }, }; </script>
2.2 VueX 数据修改流程
讲一下 VueX 的修改规范,因为全局的数据是不能随意更改的,因此 VueX 有一套机制流程,并不能直接用赋值的方法进行修改。
修改流程
在组件里提交一个 action 到 store,dispatch 的第一个参数是 action 名称,后面可自定义参数。
// LoginView.vue <template> <div>{{ myName }}</div> <button @click="handleClick">click</button> </template> <script> export default { name: "LoginView", computed: { myName() { return this.$store.state.name; }, }, methods: { handleClick() { // 1. 想改变数据,VueX 要求第一步,必须派发一个 action,action 名称为 actions 里的方法名 this.$store.dispatch("change"); }, }, }; </script>
store 感知到 action,执行 actions 下面对应的方法
actions 对应的方法 commit 信息后传递给 mutations。commit 的信息为 mutations 里的方法名。
mutations 里对应的方法执行修改数据的操作。
import { createStore } from "vuex"; // VueX 创建了一个全局唯一的仓库,用来存放全局的数据 export default createStore({ state: { name: "John", }, getters: { }, mutations: { // 4. 接收到 commit 信息后,触发对应的 mutation change(state) { // 5. 在 mutation 里修改数据 state.name = "Modified Name"; }, }, actions: { // 2. 接收到 action 后执行相应的方法 change(store) { // 3. commit 后发送给 mutations store.commit("change"); }, }, modules: {}, });
从上面的流程来看,VueX 创建了一个全局唯一的仓库,用来存放全局的数据,同时里面设置了一系列的数据操作流程。
这流程下来有点麻烦啊,为啥不直接 commit 过去呢?同步代码看起来是如此,但是如果有异步操作的话,这些步骤就很有必要了。
注意mutations 和 actions 里的方法第一个参数各不相同。
actions 里面第一个参数是 store,因为需要用 store.commit 方法来提交给 mutations。
mutations 里边的方法第一个参数是 state,因为 store 是用来修改 store 里 state 的方法。
可见,vue 官方在代码层面都是推荐分离的。
其他细则 mutations 里面只允许写同步代码,不许写异步代码actions 里面允许写异步操作
优点在于,将两种功能分离,mutations 里做数据的改变,actions 里做主要的逻辑书写,维护的时候会更加方便。
getter 是啥
store 里的数据有时候并不能直接拿来用,还需要经过一些小处理。一般就会想,在组件内处理不就完事了?但是呢,万一有很多的组件都有着需求呢,挨个写就不合适。getter 就相当于 store 里的 computed 属性,对 state 进行了一定的处理。
使用方法:
设置 getter
getter 接收两个参数,然后返回一个值。
state,必选,是 store 里的数据getters,可选,是 store 里的所有 getters
例如,我要计算得到大写后的 name:
// store/index.js getters: { upperCasedName: (state) => { return state.name.toUpperCase(); } },
组件获取 store 里的 getter
<template> <div>{{ upperCasedName }}</div> <button @click="handleClick">click</button> </template> <script> export default { name: "LoginView", computed: { upperCasedName() { return this.$store.getters.upperCasedName; }, }, methods: { handleClick() { // 1. 想改变数据,VueX 要求第一步,必须派发一个 action this.$store.dispatch("change"); }, }, }; </script>
通过 computed 获取到 getter 后,点击按钮改变了 store 里的 name,上边显示的仍然是大写的,因为获取的是全部字母大写后的 name。
2.3 Composition API 使用 VueX
composition API 使用 useStore 获取 store 即可。
<template> <div>{{ name }}</div> </template> <script> import { useStore } from "vuex"; export default { name: "LoginView", setup() { const store = useStore(); const name = store.state.name; return { name, }; }, }; </script>
用 toRefs 解构的方法也行:
<template> <div>{{ name }}</div> <button @click="handleClick">Click</button> </template> <script> import { toRefs } from "@vue/reactivity"; import { useStore } from "vuex"; export default { name: "LoginView", setup() { const store = useStore(); const { name } = toRefs(store.state); const handleClick = () => { store.commit("changeName"); }; return { name, handleClick, }; }, }; </script>
加载全部内容