Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
解决问题:
传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。
采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
参考文档:
- https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart
- https://vuex.vuejs.org/zh-cn/getting-started.html
数据流动
开始
让我们做一个添加列表的功能
目录结构
├── index.css
├── index.js
├── store
│ ├── index.js
│ ├── main.js
│ └── modules
│ └── card.js
└── vue-mods
├── card.vue
└── index.vue
定义store.js
import Vue from 'vue'
import Vuex from 'vuex'
import card from "./modules/card.js";
//初始化store
export default new Vuex.Store({
//store的子模块
modules : {
card
},
//定义状态
state : {
msg : "hello, this msg is from vuex.store",
name : "zhangjian",
location : "zhengjiang"
},
//设置状态的获取,可以做一些特殊的定制
getters : {
detail : state => {
return state.msg + state.name
}
},
//mutation,用来修改state
mutations : {
CHANGE_LOCATION (state, location = "beijing"){
state.location = location;
}
},
//事件处理,主要是由外部触发store
actions : {
changeLocation ({ commit, state }){
commit("CHANGE_LOCATION");//触发mutation
},
changeLocationAsync ({commit, state}, {location}){
setTimeout(function (){
commit("CHANGE_LOCATION", location);
}, 1000);
}
}
});
modules/card.js
,和store.js
和一致,只是输出的是一个模块
let state = {
list : [],
message : "this is card"
}
let getters = {
}
let mutations = {
ADD_CARD (state, card){
state.list.unshift(card)
},
UPDATE_MESSAGE (state, message){
state.message = message;
},
DELETE_CARD_BY_INDEX (state, index){
state.list.splice(index, 1);
}
}
let actions = {
addcard ({commit, state}, card){
let message = state.message;
let time = new Date().getTime();
commit("ADD_CARD", {name : `${message} card - ${time}`})
},
updateMessage ({commit, state}, message){
commit("UPDATE_MESSAGE", message);
},
deleteCard ({commit, state}, index){
commit("DELETE_CARD_BY_INDEX", index);
}
}
export default{
state, getters, mutations, actions
}
入口文件 App.vue
<style lang="less">
</style>
<template>
<div>
<p>{{msg}}</p>
<p>{{name}}</p>
<p>{{location}}</p>
<p>detail : {{detail}}</p>
<button @click="change">change location</button>
<button @click="asyncChange">async change location</button>
<card></card>
</div>
</template>
<script>
import store from "../store/";
import Card from "./card.vue";
export default {
components : {
Card
},
store,
created () {},
computed : {
msg (){
return "msg : " + this.$store.state.msg
},
name (){
return "name :" + this.$store.state.name
},
location (){
return "location :" + this.$store.state.location
},
detail (){
return this.$store.getters.detail
}
},
ready() {
},
methods : {
change (){
this.$store.dispatch("changeLocation")
},
asyncChange (){
this.$store.dispatch("changeLocationAsync", {
location : "china"
});
}
},
watch : {
},
filters: {
}
}
</script>
子模块 card.vue
<style lang="less">
</style>
<template>
<div>
<button @click="add">add card</button>
<input type="text" name="" @input="updateMessage" :value="message">
<span>{{cardCount}}</span>
<div v-for="(index, card) in list">{{card.name}}<span @click="del(index)">x</span></div>
</div>
</template>
<script>
export default {
components : {
},
computed : {
list (){
return this.$store.state.card.list
},
cardCount (){
return this.$store.state.card.list.length;
},
message (){
return this.$store.state.card.message
}
},
created () { },
ready() {
},
methods : {
add (){
this.$store.dispatch("addcard");
},
updateMessage (e){
this.$store.dispatch("updateMessage", e.target.value)
},
del (index){
this.$store.dispatch("deleteCard", index);
}
},
watch : {
},
filters: {
}
}
</script>
附上webpack.config.js
var webpack = require('webpack');
var vue = require('vue-loader')
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');
var ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = {
//插件项
plugins: [
new ExtractTextPlugin("[name].css")
],
//页面入口文件配置
entry: {
index : './src/index.js'
},
//入口文件输出配置
output: {
path: './dist/',
filename: '[name].js'
},
module: {
//加载器配置
loaders: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract("css") },
{ test: /\.less$/, loader: ExtractTextPlugin.extract("css!less") },
{ test: /\.js$/, loader: "babel",query: {presets: ['es2015']},exclude: /node_modules/ },
{ test: /\.vue$/, loader: 'vue'}
]
},
vue : {
loaders: {
css: ExtractTextPlugin.extract("css"),
less: ExtractTextPlugin.extract("css!less")
},
autoprefixer: { browsers: ["ios_saf >= 7", "android >= 4"] }
},
externals: {
vue: "window.Vue",
vuex : "window.Vuex"
}
};
注意:这里,我针对vue和vuex2个仓库,做了一个全局引用,这样打包出来的boundle不会太大。