Vue3 中的 Vue-Router 和 VueX
先使用 vue create 指令来创建 vue 工程项目,并选择自定义,将 Router 和 VueX 勾上。
勾上以后看主入口 main.js,可以看到项目自动帮我们注册了 vue-router 和 VueX。
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',
component: () => import( '../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 里定义一些数据
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() {
this.$store.dispatch("change");
},
},
};
</script>
-
store 感知到 action,执行 actions 下面对应的方法 -
actions 对应的方法 commit 信息后传递给 mutations。commit 的信息为 mutations 里的方法名。 -
mutations 里对应的方法执行修改数据的操作。 import { createStore } from "vuex";
export default createStore({
state: {
name: "John",
},
getters: {
},
mutations: {
change(state) {
state.name = "Modified Name";
},
},
actions: {
change(store) {
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:
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() {
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>
|