目录
1.Vue Router 进阶
1.导航守卫
正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中:全局的,单个路由独享的,或者组件级的。
1.全局前置守卫
你可以使用 router.beforeEach
注册一个全局前置守卫:
const router = createRouter({ ... })
router.beforeEach((to, from) => {
// ...
// 返回 false 以取消导航
return false
})
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。
每个守卫方法接收两个参数:
to
: 即将要进入的目标from
: 当前导航正要离开的路由
index.js
// 全局守卫
router.beforeEach((to, from, next) => {
console.log(to)
console.log(from)
next()//通行证,执行完上面的函数后,就可以执行此函数
})
eg.有一个在用户未能验证身份时重定向到/login
// GOOD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
2. 路由独享的守卫
可以直接在路由配置上定义
beforeEnter
守卫。
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
beforeEnter
守卫 只在进入路由时触发,不会在 params
、query
或 hash
改变时触发。
{
path: '/about',
component: About,
// 每路守卫(路由独享的守卫)
// 在进入这个组件之前要做一些什么
beforeEnter: (to, from, next) => {//token
console.log(to)
console.log(from)
if (123 == 123325) {//条件不成立的话,则不会进入此页面
// 放行
next()
}
}
},
3.组件内的守卫
可以在路由组件内直接定义路由导航守卫(传递给路由配置的)。
可用的配置 API
可以为路由组件添加以下配置:
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
export default {
data () {
return {
age: 10
}
},
beforeRouteEnter (to, from, next) {//拿不到实例对象,通过next的回调函数
console.log(to)
console.log(from)
// console.log(this.age)//报错,拿不到这个age
// 需要通过next才能拿到age
next((vm) => {
console.log(vm.age)//10
})
console.log('路由进入组件之前')
},
beforeRouteUpdate () {
console.log('路由更新组件之前')
},
beforeRouteLeave () {
console.log('路由离开组件之后')
}
}
2.路由懒加载
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效。
Vue Router 支持开箱即用的动态导入,这意味着你可以用动态导入代替静态导入:
// 将
// import UserDetails from './views/UserDetails'
// 替换成
//将页面进来的时候,才会进行加载
const UserDetails = () => import('./views/UserDetails')
const router = createRouter({
// ...
routes: [{ path: '/users/:id', component: UserDetails }],
})
// 静态导入,一次性加载
// import Home from "../views/Home.vue"
//路由懒加载,用到时再加载
const Home=()=>import('../views/Home.vue')
{
path: '/home',
name: 'home',
component: Home
},
2.Vue其他知识点
1.vue3中如何设置状态管理
vuex的方式
provide/inject的方式
src/store/index.js
// 状态集中管理
// 1.数据实现响应式
// ref reactive -->定义响应式对象,对象中存储着状态msg,age,counter
import { reactive } from "vue";
const store={
state:reactive({//定义状态
msg:'zz'
}),
updateMsg:function () {
this.state.msg='nihao'
}
}
// 2.如何在App组件中通过provide提供
export default store
App.vue
<script >
import Home from './views/Home.vue'
import store from "./store"
// vue3中如何设置状态管理
// provide/inject跨级通信
export default {
provide: {
store
},
components: {
Home
}
}
</script>
<template>
<div>
<Home/>
</div>
</template>
src/views/Home.vue
<template>
<div>
<div>{{ store.state.msg }}</div>
<button @click="updateMsg">改变msg</button>
</div>
</template>
<script>
export default {
inject: ['store'],
methods: {
updateMsg: function () {
this.store.updateMsg()
}
}
}
</script>
案例
<template>
<div>
<div>{{ store.state.msg }}</div>
<button @click="updateMsg">改变msg</button>
<ul>
<li v-for="item in bannersList" :key="item.targetId">
<!-- 把轮播图的数据渲染出来 -->
<img :src="item.imageUrl" alt="" />
</li>
</ul>
</div>
</template>
<script>
export default {
inject: ['store'],
data () {
return {
bannersList: []
}
},
// fetch//原生js,时http数据请求的一种方式
created () {
// http://localhost:3001/banner 轮播图的本地文件
// fetch返回promise对象
fetch('http://localhost:3001/banner').then((res) => {//默认执行get请求
console.log(res)
//json()将响应的body,解析json的promise
console.log(res.json())
return res.json()
}).then((res) => {
console.log(res)//拿到banner的数据
// {banners:Array(10),code:200}
this.bannersList = res.banners//只拿Array(10)数组就可以了,所以直接把数组res.banners赋值给bannersList
})
},
// axios
methods: {
updateMsg: function () {
this.store.updateMsg()
}
}
}
</script>
如果轮播图的数据,不止在Home.vue需要用,其他地方也要用,放在状态集中管理,来实现
src/store/index.js
const store={
state:reactive({//定义状态
bannersList:[]
}),
}
Home.vue
created () {
}).then((res) => {
//改变数据,最好在index.js里面定义一个方法,方便管理
store.state.bannersList=res.banners//不好
})
},
src/store/index.js
const store={
updateBannersList:function (value) {
this.state.bannersList=value
},
}
Home.vue
<ul>
<li v-for="item in store.state.bannersList" :key="item.targetId">
<!-- 把轮播图的数据渲染出来 -->
<img :src="item.imageUrl" alt="" />
</li>
</ul>
// store.state.bannersList=res.banners直接在组件中修改不好,应该在index.js中集中管理
this.store.updateBannersList(this.banners)
2.使用axios获取数据
1.安装
npm install axios
2.引入
import axios from 'axios'
3.使用
// axios:是基于promise的http库
axios.get('http://localhost:3001/banner').then((res) => {
console.log(res)
})
案例:猫眼电影
获取hot数据,把请求url放在axios进行获取
axios.get('https://i.maoyan.com/api/mmdb/movie/v3/list/hot.json?ct=%E6%9D%AD%E5%B7%9E&ci=50&channelId=4').then((res) => {
console.log(res)
})
报错:Access to XMLHttpRequest at 'https://i.m。。。' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
已被CORS策略阻止:请求的资源上不存在“Access Control Allow Origin”标头。
域名不相同,处于跨域请求,但是猫眼电影不允许跨域请求。
在vite.config.js配置中转服务器
vite.config.js
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server: {//中转服务器
proxy: {//通过代理实现跨域
// https://i.maoyan.com
'/path': {
target: 'https://i.maoyan.com',//替换的服务端地址
changeOrigin: true,//开启代理,允许跨域
rewrite: path => path.replace(/^\/path/, '')//设置重写的路径(访问到path之后,就会将后面的代码进行拼接)
}
}
}
})
//得到res
//{data: {…}, status: 200, statusText: 'OK', headers: {…}, config: {…}, …}
3.通过Vue-Cli创建项目
1.安装
可以使用下列任一命令安装这个新的包:
npm install -g @vue/cli
# OR
yarn global add @vue/cli
安装之后,你就可以在命令行中访问 vue
命令。你可以通过简单运行 vue
,看看是否展示出了一份所有可用命令的帮助信息,来验证它是否安装成功。
你还可以用这个命令来检查其版本是否正确:
vue --version
2.创建一个项目
vue create
运行以下命令来创建一个新项目:
vue create hello-world
Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n)
路由器使用历史模式?(需要为生产中的索引回退进行适当的服务器设置)(是/否)
因为路由存在两者模式,一种是历史模式history,一种是hash模式。
3.启动项目
cd hello-world
npm run serve
3.Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
1.什么是“状态管理模式”?
让我们从一个简单的 Vue 计数应用开始:
const Counter = {
// 状态
data () {
return {
count: 0
}
},
// 视图
template: `
<div>{{ count }}</div>
`,
// 操作
methods: {
increment () {
this.count++
}
}
}
createApp(Counter).mount('#app')
这个状态自管理应用包含以下几个部分:
- 状态(State),驱动应用的数据源;
- 视图(View),以声明方式将状态映射到视图;
- 操作(Actions),响应在视图上的用户输入导致的状态变化。
以下是一个表示“单向数据流”理念的简单示意:
但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
对于问题一,传参的方法对于多层·嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。
对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
Vuex 背后的基本思想:通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
2.什么情况下我应该使用 Vuex?
Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
3.安装
npm
npm install vuex@next --save
4.了解
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:
-
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
-
你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
src/store/index.js
import { createStore } from "vuex"
// 创建store实例
const store = createStore({
// 仅需要提供一个初始 state 对象和一些 mutation
state () {//是存储的单一状态,是存储的基本数据
return {
count: 0
}
}
})
// 导出
export default store
main.js
// 引入src/store/index.js
import store from './store'
// $router,$store安装了这个store就会有这个$store
createApp(App).use(router).use(store).mount('#app')
// 使用src/store/index.js
Home.vue
<template>
<div class="home">
<!-- 可以通过 this.$store 访问store实例。现在我们可以从组件的方法提交一个变更 -->
<!-- 模板中不需要this -->
<h2>{{ $store.state.count }}</h2>
</div>
</template>
<button @click="$store.state.count++"></button> 不要这样去更改store仓库中的数据,因为vuex跟踪不到数据的变化
通过提交 mutation 的方式,而非直接改变 store.state.count
,是因为我们想要更明确地追踪到状态的变化。这个简单的约定能够让你的意图更加明显,这样你在阅读代码的时候能更容易地解读应用内部的状态改变。此外,这样也让我们有机会去实现一些能记录每次状态改变,保存状态快照的调试工具。有了它,我们甚至可以实现如时间穿梭般的调试体验。
由于 store 中的状态是响应式的,在组件中调用 store 中的状态简单到仅需要在计算属性中返回即可。触发变化也仅仅是在组件的 methods 中提交 mutation。
src/store/index.js
mutations:{//通过store.commit方法触发对应函数状态变更
//mutations是同步函数
increment (state){//state:表示上面state返回的对象
state.count++
}
}
mutation 必须是同步函数
在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录,devtools 都需要捕捉到前一状态和后一状态的快照。然而,如果在 mutation 中的异步函数中的回调让这不可能完成:因为当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的。
Home.vue
<button @click="addCount">count++</button>
methods: {
addCount () {
this.$store.commit('increment')//使用store.commit方法改变state的状态
}
},
如果需要传参的话
Home.vue
<button @click="addCount(5)">count++</button>
addCount (num) {
this.$store.commit('increment',num)//使用store.commit方法改变state的状态
}
store/index.js
mutations:{
increment (state,value){//value:表示传过来的参数
state.count+=value
}
}
5.Getter
如果有多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。
src/store/index.js
state () {//是存储的单一状态,是存储的基本数据
return {
count: 0,
msg:'hello'
}
},
//如果state的状态需要过滤或者其他的操作
getters: {//认为store中的计算属性
reverMsg: function (state) {
return state.msg.split('').reverse().join('')
}
},
Home.vue
<h2>{{ $store.getters.reverMsg }}</h2>
1.通过属性访问
Getter 会暴露为 store.getters
对象,你可以以属性的形式访问这些值:
store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
Getter 也可以接受其他 getter 作为第二个参数:
getters: {
// ...
doneTodosCount (state, getters) {
return getters.doneTodos.length
}
}
store.getters.doneTodosCount // -> 1
我们可以很容易地在任何组件中使用它:
computed: {
doneTodosCount () {
return this.$store.getters.doneTodosCount
}
}
注意,getter 在通过属性访问时是作为 Vue 的响应式系统的一部分缓存其中的。
//store/index.js
reverMsgLength:function(state,getters){
//gettters表示当前store中的getters对象
return getters.reverMsg.length
}
//Home.vue
<h2>{{ $store.getters.reverMsgLength}}</h2>
6.Action
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
案例:猫眼电影:有跨域问题
actions:{
getHot:function(){
fetch('https://i.maoyan.com/api/mmdb/movie/v3/list/hot.json?ct=%E6%9D%AD%E5%B7%9E&ci=50&channelId=4').then((res)=>{
console.log(res)
})
}
}
通过Dispatch派生。
1.分发 Action
Action 通过
store.dispatch
方法触发。
store.dispatch('increment')
乍一眼看上去感觉多此一举,我们直接分发 mutation 岂不更方便?实际上并非如此,还记得 mutation 必须同步执行这个限制么?Action 就不受约束!我们可以在 action 内部执行异步操作:
Home.vue
mounted () {
this.$store.dispatch('getHot')
},
解决跨域问题
vue.config.js
devServer: {
proxy: {//通过代理实现跨域
'/path': {
target: 'https://i.maoyan.com',//替换的服务端地址
changeOrigin: true,//开启代理,允许跨域
// rewrite: path => path.replace(/^\/path/, '')//设置重写的路径(vite)
pathRewrite:{
'^/path':''
}
}
}
}
src/store/index.js
fetch('path/api/m...
如果出问题,重启项目。
如果要传递参数
//index.js
hotList:[]
actions: {
getHot: function (context) {//context:对象,与store实例具有相同的属性和方法的对象
fetch('/path/api/mmdb/movie/v3/list/hot.json?ct=%E6%9D%AD%E5%B7%9E&ci=50&channelId=4').then((res) => {
console.log(res.json())
console.log(context)
console.log(context.state.hotList)
})
}
}
//Home.vue
mounted () {
this.$store.dispatch('getHot','hhh')
},
console.log(context)得到store实例
console.log(context.state.hotList):得到空数组,现在要进行赋值。
使用axios
import axios from "axios";
axios.get('/path/api/mmdb/movie/v3/list/hot.json?ct=%E6%9D%AD%E5%B7%9E&ci=50&channelId=4').then(res => {
//不需要像上面一样还要.then
//1.获取数据
console.log(res)
console.log(context)
// 2.进行赋值,但是不可以这样写,应该在mutations里面写一个方法,进行改变
// context.state.hotList = res.data.data.hot
// console.log(context.state.hotList)
})
mutations: {
updateHotList:function(state,value){
state.hotList=value
}
},
getHot: function (context, payload) {
axios.get('/path/api/mmdb/movie/v3/list/hot.json?ct=%E6%9D%AD%E5%B7%9E&ci=50&channelId=4').then(res => {
context.commit('updateHotList', res.data.data.hot)
console.log(context.state.hotList)
//Proxy {0: {…}, 1: {…}, 2: {…}, 3: {…}, 4: {…}, 5: {…}, 6: {…}, 7: {…}, 8: {…}, 9: {…}, 10: {…}, 11: {…}} 可以获得数据
//传参
console.log(payload)//hhh
})
}
7.Module
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
src/store/index.js
const moduleA = {
state () {//通过$store.state.模块名.状态名,获取
return {
userName: 'zz'
}
},
getters: {//通过$store.getters可以直接获取
// state局部状态
userNameAge: function (state) {
return state.userName + '18岁'
}
},
mutations:{//触发提交函数,直接通过$store.commit即可,actions也是一样
// state局部状态
updateUserNAme:function(state){
state.userName='用户'
}
}
}
const store = createStore({
modules:{
a:moduleA
}
})
Home.vue
mounted () {
console.log(this.$store)//userNameAge属于子模块a的
},
Home.cue
<!-- 用户模块 -->
<h2>{{ $store.getters.userNameAge }}</h2>//zz18岁
<h2>{{ $store.state.a.userName }}</h2>//zz
<button @click="changeName">改变名字</button>
methods: {
changeName(){
this.$store.commit('updateUserNAme')
}
},
1.模块的局部状态
对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象。
const moduleA = {
state: () => ({
count: 0
}),
mutations: {
increment (state) {
// 这里的 `state` 对象是模块的局部状态
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
同样,对于模块内部的 action,局部状态通过
context.state
暴露出来,根节点状态则为context.rootState
:
const moduleA = {
// ...
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
}
}
}
对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:
const moduleA = {
// ...
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}
getters: {
// state局部状态
userNameAge: function (state, getters, rootState) {
console.log(getters)//获取的是Fstore实例的getters对象
console.log(rootState)//第三个参数获取根节点实例的state状态
return state.userName + '18岁'
}
},
在store创建用户模块的文件夹,将子模块分开存放。
src/store/index.js
import user from './user'
const store = createStore({
modules: {
a: user
}
})
src/store/user/index.js
const user = {
state () {
return {
userName: 'zz'
}
},
getters: {
// state局部状态
userNameAge: function (state, getters, rootState) {
console.log(getters)//获取的是Fstore实例的getters对象
console.log(rootState)//第三个参数获取根节点实例的state状态
return state.userName + '18岁'
}
},
mutations: {
// state局部状态
updateUserNAme: function (state) {
state.userName = '用户'
}
}
}
export default user
8.mapState
辅助函数
当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用
mapState
辅助函数帮助我们生成计算属性,让你少按几次键。
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给
mapState
传一个字符串数组。
computed: mapState([
// 映射 this.count 为 store.state.count
'count'
])
案例:直接获取store里面的状态
<h2>{{ count }}</h2>
import { mapState } from 'vuex'
computed: mapState({
法一:
count: state => state.count
法二:
count1: 'count'
})
法三:
computed: mapState(['count'])
但是,如果此子组件的私有数据也需要用到计算属性的话,就需要两个computed,但是不能这样。需要下面方法。
9.对象展开运算符
mapState
函数返回的是一个对象。我们如何将它与局部计算属性混合使用呢?通常,我们需要使用一个工具函数将多个对象合并为一个,以使我们可以将最终对象传给computed
属性。但是自从有了对象展开运算符,我们可以极大地简化写法:
computed: {
localComputed () { /* ... */ },
// 使用对象展开运算符将此对象混入到外部对象中
...mapState({
// ...
})
}
案例: 辅助函数的使用方法
<h2>{{ addNum }}</h2>//100
<h2>{{ count }}</h2>//5
<h2>{{ reverMsg }}</h2>hello->olleh
<button @click="addCount(5)">count++</button>
import { mapState,mapMutations,mapGetters,mapActions } from 'vuex'
data() {
return {
num:10
}
},
methods: {
addCount (num) {
// this.$store.commit('increment', num)
this.increment(num)
},
...mapMutations(['increment']),
...mapActions(['getHot'])
},
mounted () {
// this.$store.dispatch('getHot','hhh')
this.getHot()
console.log(this.count)
},
computed: {
addNum: function () {
return this.num * 10
},
...mapState(['count']),
...mapGetters(['reverMsg'])
}
}
10.命名空间
默认情况下,模块内部的 action 和 mutation 仍然是注册在全局命名空间的——这样使得多个模块能够对同一个 action 或 mutation 作出响应。Getter 同样也默认注册在全局命名空间,但是目前这并非出于功能上的目的(仅仅是维持现状来避免非兼容性变更)。必须注意,不要在不同的、无命名空间的模块中定义两个相同的 getter 从而导致错误。
如果希望你的模块具有更高的封装度和复用性,你可以通过添加
namespaced: true
的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。
onst store = createStore({
modules: {
account: {
namespaced: true,
// 模块内容(module assets)
state: () => ({ ... }), // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响
getters: {
isAdmin () { ... } // -> getters['account/isAdmin']
},
actions: {
login () { ... } // -> dispatch('account/login')
},
mutations: {
login () { ... } // -> commit('account/login')
},
// 嵌套模块
modules: {
// 继承父模块的命名空间
myPage: {
state: () => ({ ... }),
getters: {
profile () { ... } // -> getters['account/profile']
}
},
// 进一步嵌套命名空间
posts: {
namespaced: true,
state: () => ({ ... }),
getters: {
popular () { ... } // -> getters['account/posts/popular']
}
}
}
}
}
})
//src/store/user/index.js
const user = {
namespaced:true,
}
getters: {
// state局部状态
userNameAge: function (state, getters, rootState) {
console.log(getters)//获取的是Fstore实例的getters对象
console.log(rootState)//第三个参数获取根节点实例的state状态
return state.userName + '18岁'
}
},
//Home.vue
<h2>{{ $store.getters["a/userNameAge"] }}</h2>
<h2>{{ $store.state.a.userName }}</h2>
changeName () {
// this.$store.commit('updateUserNAme')//unknown mutation type: updateUserNAme
this.$store.commit('a/updateUserNAme')//可以更改用户名
this.updateUserNAme()//也可以更改用户名
},
...mapMutations('a',['updateUserNAme']),