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不会太大。