前端:Vue学习-4
- 1. 组件缓存 keep-alive
- 2. 状态管理工具 - Vuex
- 2.1 vuex 提供数据&使用数据 - mapState
- 2.2 mutations 修改数据 - mapMutations
- 2.3 actions - 异步操作 - mapActions
- 2.4 getters - 计算属性 - mapGetters
- 3. Vuex 模块 modules - state,mutations,actions,getters
1. 组件缓存 keep-alive
keep-alive是vue的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。keep-alive是一个抽象组件:它自身不会渲染成一个dom元素,也不会出现在父组件当中。
keep-alive的优点是,在组件切换过程中,把切换出去的组件保留在内存中,防止重复渲染dom,减少加载时间及性能消耗,提高用户体验。
keep-alive三个属性:include被缓存的组件、exclude不被缓存的组件、max最多可以缓存的组件实例。
<template><div id="app"><keep-alive :include="p"><router-view></router-view></keep-alive></div>
</template><script>export default {name: 'App',data(){return{p:['Home']}},components: {}
}
</script>
<script>
export default {name:'Home',created(){console.log('组件被加载');},mounted(){console.log('组件dom渲染完了');},destoryed(){console.log('组件被销毁');},activated(){console.log('组件被激活时触发!');},deactivated(){console.log('组件失活时被触发!');}
}
</script>
运行结果:
不过上述这个运行结果中keep-alive起是起作用了,但是存在一个问题就是回到列表组件时,重新刷新了以下当前页面,不知道什么原因?。。。
组件被缓存后,created、mounted、destoryed函数就不会被触发。所以提供了activated和deactivated,activated表示组件被激活时触发,而deactivated是组件失活时触发。
2. 状态管理工具 - Vuex
vue2 vue-router3 vuex3
vue3 vue-router4 vuex4
vuex是一个vue的状态管理工具,状态就是数据,可以管理vue通用的数据(多组件共享的数据)。
安装命令为:
npm install vuex@3
项目下创建目录store,并在该目录下创建文件index.js
,index.js里的代码如下:
import Vue from "vue"
import Vuex from "vuex"Vue.use(Vuex);
// 插件安装
const vuex = new Vuex.Store();
// 创建仓库export default vuex
// 导出
在mian.js中导入即可。
import store from '@/store/index'new Vue({render: h => h(App),store
}).$mount('#app')
2.1 vuex 提供数据&使用数据 - mapState
提供数据在Vuex.Store对象添加state属性即可。
const store = new Vuex.Store({state:{count:101}
});
使用数据$store.state.xxx
<p>{{$store.state.count}}</p>
或
created(){console.log(this.$store.state.count);}
mapState
另外可以通过辅助函数来使用数据。mapState,可以帮助我们把store中的数据自动映射到组件的计算属性上。
import {mapState} from 'vuex'computed:{...mapState(['count'])}
// 计算属性<p>{{count}}</p>
// 页面上进行渲染
2.2 mutations 修改数据 - mapMutations
vuex遵循单向数据流,组件中不能直接修改仓库的数据。
this.$store.state.count = 102
// 错误代码
上述代码vue并不会报错,可以在vuex配置中添加strict:true严格模式,这样就可以看到报错信息了。
const store = new Vuex.Store({strict:true
});
因为不能直接修改store中的数据,那么也就是说需要在store中定义修改数据的方法,然后在组件中调用这个方法即可,直接在store对象上添加属性mutations对象,在这个下面定义方法即可。
const store = new Vuex.Store({state:{count:101},strict:true,mutations:{setCount(state){state.count = 102 }}
});
组件中调用使用 $store.commit(‘方法名’)
<button @click="$store.commit('setCount')">修改</button>
运行结果:
mutations传参,在mutations下定义方法,第一参数为:state,第二个参数就是我们需要传递的参数。调用方法时,使用 $store.commit(‘xxx’,参数)
setCount(state,n){state.count += n
}
<button @click="$store.commit('setCount',2)">修改</button>
mutations下定义的方法有且只能有一个,如果需要传递多个,那么参数类型可以为对象或者数组。
mapMutations
把位于mutations中的方法提取出来,映射到组件methods中。
import {mapMutations} from 'vuex'methods:{...mapMutations(['setCount'])},
<button @click="setCount(2)">修改</button>
2.3 actions - 异步操作 - mapActions
mutations必须是同步,修改state中的数据必须调用经过mutations,因此如果有异步操作需要修改state中值,那么需要在actions中调用mutations下的方法。调用actions下的方法使用 $store.dispatch(‘方法名’,参数)
const store = new Vuex.Store({state:{count:101},strict:true,mutations:{setCount(state,n){state.count += n }},actions:{setAsycCount(context,n){setTimeout(()=>{context.commit('setCount',n);},1000);}}
});
<button @click="$store.dispatch('setAsycCount',4)">1秒后修改数据</button>
运行结果:
mapActions
同mapState、mapMutations类似,直接在methods中添加对应映射即可。
import {mapActions} from 'vuex'
methods:{...mapActions(['setAsycCount'])},
<button @click="setAsycCount(4)">1秒后修改数据</button>
2.4 getters - 计算属性 - mapGetters
getters类似于计算属性,getters函数的第一个参数是state;函数必须有返回值。
const store = new Vuex.Store({state:{list:[1,2,3,4,5,6,7,8,9,10]},getters:{filterList(state){return state.list.filter(x => x > 5)}}
});
<p>{{($store.getters.filterList).join(',')}}</p>
mapGetters
computed:{...mapGetters(['filterList'])}
<p>{{filterList.join('|')}}</p>
3. Vuex 模块 modules - state,mutations,actions,getters
由于vuex使用单一状态树,应用的所有状态会集中到一个较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿。
某个模块 store/modules/user.js
const state = {}
const mutations = {}
const actions = {}
const getters = {}
export default {state,mutations,actions,getters
}
使用 store/index.js
import user from './modules/user.js'const store = new Vuex.Store({modules:{user}
})
1.state
分模块之后,子模块的状态是会挂载到根级别的state中,属性名就是模块名。
使用模块中的数据:
- 使用 $store.state.模块名.xxx
- 通过mapState映射,默认根级别的映射 mapSate([‘xxx’]),子模块的映射为mapState(‘模块名’,[‘xxx’]),需要开启命名空间
export default {namespaced:true, // 开启命名空间state,mutations,actions,getters
}
const state = {name:'zs'
}
使用原生方式进行访问
<p>{{$store.state.user.name}}</p>
使用mapState进行访问
computed:{...mapState('user',['name'])}
<p>{{name}}</p>
2.getters
使用模块中getters中的数据
- 直接通过 $store.getters[‘模块名/xxx’]
- 通过mapGetters映射,子模块的映射为mapGetters(‘模块名’,[‘xxx’]) - 需要开启命名空间
const getters = {upperName(state){return state.name.toUpperCase();}
}
原生方式进行访问
<p>{{$store.getters['user/upperName']}}</p>
使用mapGetters进行访问
computed:{...mapGetters('user',['upperName'])}
<p>{{upperName}}</p>
3.mutations
默认模块中的mutations和actions会被挂载到全局,需要开启命名空间,才会挂载到子模块中。
- 直接通过store调用 $store.commit(‘模块名/xxx’,参数)
- 通过mapMutations映射,子模块的映射mapMutations(‘模块名’,[‘xxx’]),需要开启命名空间
const mutations = {setName(state,newName){state.name = newName;}
}
使用原生进行修改
<button @click="$store.commit('user/setName','zl')">更新名字</button>
使用mapMutations进行修改
methods:{...mapMutations('user',['setName'])}
<button @click="setName('lz')">更新名字2</button>
运行结果:
4.actions
默认模块中的mutations和actions会被挂载到全局,需要开启命名空间,才会挂载到子模块中。
- 通过 $store.dispatch(‘模块名/xxx’,参数)
- 通过mapActions,子模块的映射为mapActions(‘模块名’,[‘xxx’]) - 需要开启命名空间
const actions = {setSyncName(context,n){setTimeout(()=>{context.commit('setName', n);},1000);}
}
使用原生进行修改
<button @click="$store.dispatch('user/setSyncName','hh')">1秒后修改名字</button>
使用mapActions进行修改
methods:{...mapActions('user',['setSyncName'])}
<button @click="setSyncName('ll')">1秒后修改名字2</button>