安装好脚手架服务跑起来后,在src下新建vuex文件夹,vuex文件夹下新建js文件并配置:
我命名为index.js:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({//创建仓库实例
state:{//仓库中存放数据的地方
count: 1
}
})
export default store;
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './vuex' //这是利用了文件默认查找机制,找到./vuex/index.js文件
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,//告诉vue使用了仓库,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。
components: { App },
template: '<App/>'
})
创建一个单文件组件(pages/User.vue文件):
<template>
<div class="user">
<button @click="handleCount">改变count</button>
{{count}}
</div>
</template>
<script>
export default{
data(){
return {
}
},
computed: {
count(){//如果去仓库拿数据,通过仓库实例对象 $store
return this.$store.state.count;
}
}
}
</script>
<style>
.user{
background: red;
}
</style>
说一下利用webpack的require.ensure实现异步组件+代码抽离(router/index.js):
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
//异步组件的抽离,建立一个异步组件
//webpack的require.ensure webpack会将require.ensure中引入的代码从主boundle中抽离
// import Login from '@/pages/Login'
const Login = r => require.ensure([], () => r(require('@/pages/Login.vue')), 'login')
const User= r => require.ensure([], () => r(require('@/pages/User.vue')), 'login')
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},{
path: '/login',
name: 'Login',
component: Login
},{
path: '/user',
name: 'User',
component: User
}
]
})
获取数据:
辅助函数(语法糖)
当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState
辅助函数帮助我们生成计算属性,让你少按几次键:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({//创建仓库实例
state:{//仓库中存放数据的地方
count: 2,
products: [{
title: "东风标致", id: 8, buy: false
},{
title: "广州本田", id: 9, buy: true
},{
title: "一汽大众", id: 6, buy: true
},{
title: "东风悦达", id: 7, buy: true
},{
title: "长安铃木", id: 5, buy: false
}]
},
getters: {//配置从state中衍生出来的数据
tobuy(state){//默认第一个参数就是store的state
return state.products.filter(v => v.buy);
},
nottobuy(state){
return state.products.filter(v => !v.buy)
}
}
})
export default store;
获取tobuy、nottobuy数据:
<template>
<div class="user">
<button @click="handleCount">改变count</button>
{{count}}
<hr/>
<ul>
<li style="background:green">我要买的:</li>
<li v-for="(v, i) in tobuy">{{v.title}}</li>
</ul>
<ul>
<li style="background:orange">我不买的:</li>
<li v-for="(v, i) in nottobuy">{{v.title}}</li>
</ul>
</div>
</template>
<script>
import {mapState, mapGetters} from 'vuex';//引入语法糖对象
export default{
data(){
return {
}
},
computed: {
// count(){
// return this.$store.state.count;
// }
// 当计算属性的key和store的state的属性名相同时可以用mapState,都需要es7...对象扩展运算符:
...mapState(['count'])//数组语法
// 当计算属性的key和srote的state的属性名不相同时:用对象语法,此时计算属性名称为counter
// ...mapState({
// counter: state => state.count
// })
,
tobuy(){//同样state的衍生状态也可以使用语法糖,引入mapGetters,语法跟mapState一样
return this.$store.getters.tobuy;
},
nottobuy(){
return this.$store.getters.nottobuy;
}
},
methods: {
handleCount(){
console.log(this.count)
}
}
}
</script>
<style>
.user{
background: red;
}
</style>
渲染的结果:
改变数据:
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
你不能直接调用一个 mutation handler。这个选项更像是事件注册:“当触发一个类型为 increment
的 mutation 时,调用此函数。”要唤醒一个 mutation handler,你需要以相应的 type 调用 store.commit 方法:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({//创建仓库实例
state:{//仓库中存放数据的地方
count: 2,
products: [{
title: "东风标致", id: 8, buy: false
},{
title: "广州本田", id: 9, buy: true
},{
title: "一汽大众", id: 6, buy: true
},{
title: "东风悦达", id: 7, buy: true
},{
title: "长安铃木", id: 5, buy: false
}]
},
getters: {//配置从state中衍生出来的数据
tobuy(state){//默认第一个参数就是store的state
return state.products.filter(v => v.buy);
},
nottobuy(state){
return state.products.filter(v => !v.buy)
}
},
mutations: {
changeCount(state, payload){//第二个参数就是组件中传递过来的载荷
state.count += payload;
}
}
})
export default store;
<template>
<div class="user">
<button @click="handleCount">改变count</button>
{{count}}
<hr/>
<ul>
<li style="background:green">我要买的:</li>
<li v-for="(v, i) in tobuy">{{v.title}}</li>
</ul>
<ul>
<li style="background:orange">我不买的:</li>
<li v-for="(v, i) in nottobuy">{{v.title}}</li>
</ul>
</div>
</template>
<script>
import {mapState, mapGetters} from 'vuex';//引入语法糖对象
export default{
data(){
return {
}
},
computed: {
// count(){
// return this.$store.state.count;
// }
// 当计算属性的key和store的state的属性名相同时可以用mapState,都需要es7...对象扩展运算符:
...mapState(['count'])//数组语法
// 当计算属性的key和srote的state的属性名不相同时:用对象语法,此时计算属性名称为counter
// ...mapState({
// counter: state => state.count
// })
,
tobuy(){//同样state的衍生状态也可以使用语法糖,引入mapGetters,语法跟mapState一样
return this.$store.getters.tobuy;
},
nottobuy(){
return this.$store.getters.nottobuy;
}
},
methods: {
handleCount(){
this.$store.commit("changeCount", 5)//提交一个名为changeCount的mutation,第二个可选参数表示载荷,也可以是一个对象传入,也可以将type和载荷写成一个对象传入{type: 'changeCount', payload: 5}
console.log(this.count)
}
}
}
</script>
<style>
.user{
background: red;
}
</style>
使用常量替代 Mutation 事件类型
使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。这样可以使 linter 之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然:
可以单独新建一个js文件命名为mutation-types.js专门用来配置要用到的事件类型名称的常量(变量大写是规范,不过这里最好值也大写,不然在后面用mapMutations的数组语法糖时会报出常量未定义的错):
export const CHANGECOUNT = 'CHANGECOUNT';
并更改mutation事件属性名,es6对象的动态属性写法:
mutations: {
[CHANGECOUNT](state, payload){//第二个参数就是组件中传递过来的载荷
state.count += payload;
}
}
然后在store文件中和其他用到的组件页引入:
import {CHANGECOUNT} from './mutation-types';
同样更改触发
mutation事件的事件属性名:
methods: {
handleCount(){
this.$store.commit(CHANGECOUNT, 5)//提交一个名为changeCount的mutation,第二个可选参数表示载荷,也可以是一个对象传入,也可以将type和载荷写成一个对象传入{type: 'changeCount', payload: 5}
console.log(this.count)
}
}
同时mutation的所有事件函数中不能有异步,因为vue要监视状态的改变,数据和对应的状态必须一致。