Vuex基础使用和双向绑定

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。

1. Vuex介绍

Vuex是官方的状态管理工具,主要概念有State、Getter、Mutation、Action、Module。
文章的开头说过Vue的组件都是一个个Vue实例,Vuex也可以这样来看,具体对比关系如下:

Vuex 主要作用 Vue组件
State 用来保存状态 相当于data属性
Getter 用来对属性进行组合修改 相当于计算属性
Mutation 常用来直接改变State的值 相当于methods
Action 主要用于提交Mutations,并且可以处理异步 -
Module 用于模块化状态管理 模块化Vue组件

使用Vuex,我们用State保存状态,使用Getter来对状态数据进行处理,使用Mutation来直接改变State的值,用Action来提交Mutation,Action不是另类的Mutation,他操作的是Mutation中的函数,按照规范,Action是不能直接修改State的,虽然它可以修改State,如果需要返回一个状态或者一个异步的回调,比如在Actions里面进行了http请求,可以直接返回一个Promise,使用Module,来对庞大的项目进行分组。

2. 对Vuex中State的获取

一般情况下都会把Vuex全局注入到Vue中,这时每一个Vue实例都能访问到,一般都会使用计算属性来接受Vuex的值,代码如下:

//定义一个简单的Vuex
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);

export default new Vuex.Store({
  state: {
      Title: "123",
  },
  mutations: {
    changeTitle(state, newTitle) {
      state.Title= newTitle;
    },
  },
});

//组件中使用


这样就能够在页面上显示Vuex中的Title值了。

除此之外还有一个辅助函数,在本例子中代码改为:

//组件中使用


3. 对Vuex中State的改变

在上述Vuex例子中已经声明了Mutation,只需要把代码改为:

//组件中使用


Vuex基础使用和双向绑定_第1张图片
4.gif

上述代码主要是添加了一个输入框和一个按钮,输入框输入数据后,点击改变按钮,就会触发一个点击事件,这个点击事件中出发函数,函数调用Vuex中Mutation中的方法changeTitle,并传过去了文本框中的值,Mutation中的changeTitle则改变了State中的Title的值,因为组件中获取Vuex的值使用计算属性,因此也会同步到页面。

当然Mutation也有辅助函数,只需在上面修改代码如下:

//组件中使用


4. Vuex中State的双向绑定

Vuex的State的双向绑定通常用在 form表单,当然也有其他需要双向绑定的情况。
本小节主要应用技术是Vue计算属性的get方法和set方法,对上面例子修改后,代码如下:

export default {
 computed: {
    newTitle: {
      get() {
        return this.$store.state.Title;
      },
      set(value) {
        this.$store.commit('changeTitle', value)
      }
    }
  },
}

把提交修改的事件添加到计算属性的set方法中,就可以在值改变的时候触发修改操作,从而改变State的值,这个操作在form表单中是可以行得通的,因为表单一般用v-model绑定数据,而v-model是一个语法糖,它内部拥有input事件,可以触发计算属性的set方法,而不用v-model的时候则不能触发计算属性的set方法,也就无法实现双向绑定,这时候需要使用监听器监听newTitle值的变化,从而触发改变State的Mutation方法,代码如下:

export default {
 computed: {
    newTitle(){
      return this.$store.state.Title;
    }
  },
 watch:{
   newTitle(newd,oldd){
     this.$store.commit('changeTitle', newd)
   }
 }
}

因为监听器是在数据发生变化时执行的,所以能够解决非v-model指令不能触发set方法的问题。

5. Vuex中对象属性的深层监听

本小节是对上个小节的一点拓展。
在对Vuex的日常使用中,一般都不会一个属性设置一个值,一般都会进行分组,而模块过大的时候就会启用Vuex的Module,在一个设置配置的Vuex中,一般有如此配置:

//系统设置
    config: {
      events: true,
      calls: false,
      messages: false,
      notifications: false,
      sounds: false,
      videoSounds: false
    }

我们在组件中使用则会这样用:


在组件中就会使用v-model="config.events"来使用,这明显是使用了v-model的对象赋值,但是计算属性并不会检测内部的变化,从而触发set方法,去提交对State修改的Mutation方法。
使用Vue的监听器设置deep:true,监听器默认也不会监听内部变化,设置deeptrue可以监听内部变化,代码如下:


这样就对config的值进行了深层双向绑定,而不是重复书写这几个配置属性的getset方法

6. Getter

前文提到过,Getter就像计算属性。比如一个列表属性,有时我们只需要其中一条数据我们可以这样做:

export default new Vuex.Store({
  state: {
    list: [
      { id: 1, text: '我是1'},
      { id: 2, text: '我是2'},
      { id: 3, text: '我是3'}
    ]
  },
  getters: {
    getone: state => {
      return state.list.filter(id=> id===1)
    }
  }
})

这样调用时,就只会返回第一条数据。
在组件中使用:

computed: {
 getOnes () {
    return this.$store.getters.getone
  }
}

值得注意的是,虽然Vuex中Geeter类似于组件中的计算属性,但是Getter并没有像计算属性那样混入实例(按照计算属性类比的话,Vuex调用Getter需要使用this.$store.state.getone),但是Getter调用还是要this.$store.getters.getone

同样可以使用助手函数:

computed: {
    ...mapGetters([
      'getone'
    ])
  }

7. Action

Action是Vuex中的异步调用解决方法,因为Mutation只能使用同步方法,Action操作的是Mutation中的函数,下面有一个例子:

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    add(state) {
      state.count+=1
    }
  },
  actions: {
    increment (context) {
      context.commit('add')
    }
  }
})

在使用的时候可以这样操作:

export default {
 methods:{
 addCount(){
  this.$store.dispatch('add')
 },
},
//其他必要代码
}

同样可以使用助手函数:

import { mapActions } from 'vuex'
export default {
 methods:{
 ...mapActions(['add']),
},
//其他必要代码
}

如果需要在Action中传递值需要绕一下,代码如下:

import { mapActions } from 'vuex'
export default {
 data(){
  return{
    value:'',
  };
 },
methods: {
    changeTitles() {
      this.$store.dispatch('change',value)
    },
//其他必要代码
}
//vuex
export default new Vuex.Store({
  state: {
    Title: "test",
  },
  mutations: {
    changevalue(state, newTitle) {
      state.Title = newTitle;
    }
  },
  actions: {
    change(context, value) {
      context.commit("changeTitle", value);
    }
  },
});

Action和Mutation类似,都是第二个值才是传入的值,因为Action是对Mutation的操作,所以传值需要多绕一下,但是还是可以达到预期效果的。

8. Module

当你的系统非常庞大时,把不同模块的State和Mutation写在一起会非常的乱,因此Vuex还提供了模块化。

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

上面代码是引用Vuex官方文档的代码,只需要在引用方法和操作时加上模块名,就可以正确读取到相应模块的值和方法。

操作方法 非模块化 模块化
获取State this.$store.state.value; this.$store.state.[模块名].value
mapState ...mapState(['value]) ...mapState(['[模块名]/value'])
Mutation this.$store.commit('event') this.$store.[模块名].commit('event')
mapMutation ...mapMutation(['event]) ...mapMutation(['[模块名]/event'])

Action和Getter类似。

使用webpack批量导入Modules

require.context是webpack的一个用来管理依赖的一个函数,使用它可以批量导入,详细查看文档
https://webpack.docschina.org/guides/dependency-management/#require-context

具体使用:

import Vue from "vue";
import Vuex from "vuex";
import getters from "./getters";
Vue.use(Vuex);

// 引入modules下的所有文件
const modulesFiles = require.context("./modules", false, /\.js$/);

const modules = modulesFiles.keys().reduce((modules, path) => {
  // ./app.js => app
  const name = path.replace(/^\.\/(.*)\.\w+$/, "$1");
  // 如果文件是空的则,下面这句取不出来结果
  const value = modulesFiles(path);
  modules[name] = value.default;
  return modules;
}, {});
const store = new Vuex.Store({
  modules,
  getters
});
export default store;

你可能感兴趣的:(Vuex基础使用和双向绑定)