本文仅为 vuex 使用方法,如有不对的地方,欢迎指正。
项目使用可以直接拉到后面vuex 实际项目中使用
部分。
首先为啥要用 vuex,用它有什么好处。
- 数据跨组件共享。
- 防止数据意外修改。程序过于庞大或多人开发时,容易不知道是哪改数据, vuex 可以记录哪个组件修改的修改的。
- 调试、测试方便,同上。
vuex 基本描述
文档地址:https://vuex.vuejs.org/zh/
核心思想(流程):
-
state
存储、数据;包含了所有变量也只有变量。 -
mutations
修改数据、追踪;操作 state;vue-devtools
上监控到的就是这一属性,只能有同步操作。
mutation 都有一个字符串的事件类型 (type)
和 一个回调函数 (handler)
。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
mutations: {
add (state) {
// 变更状态
state.count++
}
}
store.commit('add')
调用 mutations 中函数的方法,可以传入参数。
mutations: {
add (state, args) {
state.count += args.n
}
}
// 调用
store.commit('add', {n: 10})
-
actions
封装、组合;操作 mutations,可以有异步和同步操作,数据请求一般放这。
Action 函数接受一个与store
实例具有相同方法和属性的context
对象,因此你可以调用context.commit
提交一个mutation
,或者通过context.state
和context.getters
来获取state
和getters
。
actions: {
add (context) {
context.commit('add')
}
}
store.dispatch('add')
调用 actions 中函数的方法,可以传入参数。
actions: {
add ({commit}, args) {
commit('add', args)
}
}
// 以载荷形式分发
store.dispatch('add', {
n: 10
})
// 以对象形式分发
store.dispatch({
type: 'add',
n: 10
})
-
vue components
可以从 state 读数据,state更新了 vue components 也会更新,vue components只能通过调用 actions 操作数据。
vuex 目录结构
这只是个示例,这目录官网扒的,嘿嘿嘿。
├── index.html
├── main.js
├── api
│ └── ... # 抽取出API请求
├── components
│ ├── App.vue
│ └── ...
└── store
├── index.js # 我们组装模块并导出 store 的地方
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
└── modules
├── cart.js # 购物车模块
└── products.js # 产品模块
vuex 使用前置
vuex
可以直接在 main.js
中直接引入,也可以独立出一个文件,再引入到 main.js
中。
先安装 vuex:npm install vuex
直接在 main.js
中直接引入
main.js 文件:
import Vue from 'vue'
// 第一步 引入
// 在主 js 文件 main.js 中引入
import Vuex from 'vuex';
// 第二步 添加到vue身上
// 把 vuex 的操作方法挂到 vue 上
Vue.use(Vuex);
// 第三步 声明 store 对象
// 必须先 use 才能进行操作,然后把 store 对象挂到 vue 上
const store=new Vuex.Store({
strict: process.env.NODE_ENV!='production', //严格模式:防止直接修改state,打开时会影响性能,只在开发模式打开;process.env.NODE_ENV 是 webpack 配置取的变量
state: {a: 12, b: 5}, //核心:数据
mutations: {
add(state, n){
state.a+=n;
}
},
actions: {
add({commit}, n){
commit('add', n); // 调用 mutations 中的 add
}
},
getters: {},
modules: {}
});
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
vue 文件:
<template>
<div>
a: {{$store.state.a}}<br/>
<input type="button" value="+5" @click="fn()">
</div>
</template>
<script>
export default {
data () {
return {
}
},
methods: {
fn(){
//this.$store.state.a+=5;// 直接改也可以改,但会报错
//this.$store.commit('add', 5);// 使用 mutations 也可以改,但是一般不会用
this.$store.dispatch('add', 5);
}
}
}
</script>
把 vuex 独立到 store 文件夹中
store/index.js 文件:
import Vue from 'vue'
import Vuex from 'vuex';
Vue.use(Vuex);
const store=new Vuex.Store({
strict: process.env.NODE_ENV!='production',
state: {a: 12, b: 5},
mutations: {
add(state, n){
state.a+=n;
}
},
actions: {
add({commit}, n){
commit('add', n);
}
},
getters: {},
modules: {}
});
export default store
main.js 文件:
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
vue 文件无需改动。
vuex 实际项目中使用
项目中使用时就要用到 getters 函数,可以把它看成 store
的计算属性。
vuex 有几个辅助函数,把 vuex 的函数映射成 vue 组件中对应的函数,简化操作
mapState
state -> computedmapActions
actions -> methodsmapGetters
getters -> computed
store/index.js 文件:
import Vue from 'vue'
import Vuex from 'vuex';
Vue.use(Vuex);
const store=new Vuex.Store({
strict: process.env.NODE_ENV!='production',
state: {a: 12, b: 5},
mutations: {
add(state, n){
state.a+=n;
},
addA(state, n){
state.a+=n;
},
addB(state, n){
state.b+=n;
},
setOnline(state, id){
state.users.forEach(user=>{
if(user.id==id){
user.online=true;
}
});
},
setUsers(state, users){
state.users=users;
}
},
actions: {
add({commit}, n){
commit('add', n);
},
addA({commit}, n){
commit('addA', n);
},
addB({commit}, n){
commit('addB', n);
},
setOnline({commit}, id){
commit('setOnline', id);
},
async readUsers({commit}){
let res=await fetch('http://localhost:2021/static/user.txt');
// [{"id":3,"name":"blue","age":18,"online":true},{"id":5,"name":"zhangsan","age":22,"online":false},{"id":11,"name":"lisi","age":25,"online":true}]
let users=await res.json();
commit('setUsers', users);
}
},
getters: {
count(state){
return state.a+state.b;
},
onlineUsers(state){
return state.users.filter(user=>user.online);
}
},
modules: {}
});
export default store
vue 文件:
<template>
<div>
<div>a: {{a}}</div>
<div>b: {{b}}</div>
<div>count: {{count}}</div>
<input type="button" value="a+5" @click="addA(5)" />
<input type="button" value="b+3" @click="addB(3)" />
<br>
<br>
<input type="button" value="法外狂徒出现" @click="setOnline(5)" />
<ul>
<li v-for="user in onlineUsers" :key="user.name">
名字:{{user.name}}
年龄:{{user.age}}
</li>
</ul>
</div>
</template>
<script>
import {mapState, mapActions, mapGetters} from 'vuex';
export default {
async created(){
await this.readUsers();
},
methods: {
...mapActions(['addA', 'addB', 'setOnline', 'readUsers']),
},
computed: {
...mapState(['a', 'b']),
...mapGetters(['count', 'onlineUsers'])
}
}
</script>
vuex 模块化
首先需要在 store/index.js
引入对应子模块,注意子模块的 mutations
和 actions
重名会多次执行。
store/index.js:
import Vue from 'vue'
import Vuex from 'vuex';
import boy from './boy';
import girl from './girl';
Vue.use(Vuex);
const store=new Vuex.Store({
strict: process.env.NODE_ENV!='production',
state: {str: 'liangzai'},
getters: {
couples(state) {
return `${state.boy.str} && ${state.girl.str}`;
}
},
modules: {
boy,
girl
}
});
export default store
store/boy.js:
export default {
state: {
str: 'boy'
},
mutations: {
'boySetStr': function (state, s){
console.log('boy 的 setStr');
state.str=s;
}
},
actions: {
'boySetStr': function ({commit}, s){
commit('boySetStr', s);
}
}
}
store/girl.js:
export default {
state: {
str: 'girl'
},
mutations: {
'girlSetStr': function (state, s){
console.log('girl 的 setStr');
state.str=s;
}
},
actions: {
'girlSetStr': function ({commit}, s){
commit('girlSetStr', s);
}
}
}
vue 文件:
<template>
<div>
str: {{str}}<br>
couples: {{couples}}<br>
a_str: {{str_boy}}<br>
b_str: {{str_girl}}<br>
<input type="button" value="设置 boy" @click="set_boy('aaa')">
<input type="button" value="设置 girl" @click="set_girl('bbb')">
<br>
</div>
</template>
<script>
import {mapState, mapActions, mapGetters} from 'vuex';
export default {
// created(){console.log(this.$store)},
methods: {
...mapActions({
set_boy: 'boySetStr',
set_girl: 'girlSetStr'
})
},
computed: {
...mapState(['str']),
...mapState({
str_boy: state=>state.boy.str,
str_girl: state=>state.girl.str,
}),
...mapGetters(['couples'])
}
}
</script>
参考代码下载:https://github.com/windliang/simpleJS/tree/master/vue/vuexDemo