美文网首页前端知识点
Vue组件通信—Vuex基础使用和双向绑定

Vue组件通信—Vuex基础使用和双向绑定

作者: Wermdany | 来源:发表于2019-07-29 17:09 被阅读30次

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

    1. Vuex介绍

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

    Vuex 主要作用 Vue组件
    State 用来保存状态 相当于data属性
    Getter 用来对属性进行组合修改 相当于计算属性
    Mutation 用来改变State的值 相当于methods
    Action 主要用于异步改变 相当于处理函数的函数
    Module 用于模块化状态管理 模块化Vue组件

    使用Vuex,我们用State保存状态,使用Getter来对状态数据进行拼接和处理,使用Mutation来定义函数,改变State的值,用Action来处理异步操作,Action不是另类的Mutation,他操作的是Mutation中的函数,使用Module,来对庞大的项目进行分组,Vuex状态的改变都是调用Mutation或Action的函数来改变,也就是Vuex这一家人的事,不允许其他外部干涉,想要改变,只能调用我里面声明的方法改变,这样开发数据流动方向更加明确,这也是为什么专门开发一个Vuex来管理状态的一个原因,其他数据流动方式过于混乱。

    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;
        },
      },
    });
    
    
    //组件中使用
    <template>
    <div class="test">{{NewState}}</div>
    </template>
    <script>
    export default {
      computed: {
      NewState(){
        return this.$store.state.Title
      }
      },
    //其他必要代码
    }
    </script>
    

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

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

    //组件中使用
    <template>
    <div class="test">{{Title}}</div>
    </template>
    <script>
    import { mapState } from 'vuex'
    export default {
      computed: {
     ...mapState(['Title']),
      },
    //其他必要代码
    }
    </script>
    

    3. 对Vuex中State的改变

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

    //组件中使用
    <template>
    <input type="text" v-model="newTitle">
    <div class="test">{{Title}}</div>
    <button @click="changeTitle">改变Vuex中的title</button>
    </template>
    <script>
    import { mapState } from 'vuex'
    export default {
      data(){
      return{
      newTitle:"",
      } },
      computed: {
     ...mapState(['Title']),
      },
     methods:{
     chageTitle(){
      this.$store.commit('changeTitle',this.newTitle)
     },
    },
    //其他必要代码
    }
    </script>
    
    4.gif

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

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

    //组件中使用
    <template>
    <input type="text" v-model="newTitle">
    <div class="test">{{Title}}</div>
    <button @click="changeTitles">改变Vuex中的title</button>
    </template>
    <script>
    import { mapState,mapMutations } from 'vuex'
    export default {
      data(){
      return{
      newTitle:"",
      } },
      computed: {
     ...mapState(['Title']),
      },
     methods:{
        ...mapMutations(['changeTitle']),
        changeTitles() {
          this.changeTitle(this.newTitle)
        },
        // changeTitle() {
        //   this.$store.commit('changeTitle', this.newTitle)
        // },
    },
    //其他必要代码
    }
    </script>
    

    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
        }
    

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

    <script>
    import { mapState } from 'vuex'
    export default {
      name: 'Drawer',
      data() {
        return {
          docked: false,
          position: 'left'
        }
      },
      computed: {
          ...mapState(['config'])
       }
    }
    </script>
    

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

    <script>
    import { mapState } from 'vuex'
    export default {
     computed: {
         ...mapState(['config']),
       },
      watch: {
        config: {
          handler(newValue, oldValue) {
            this.$store.commit('changeConfig', newValue)
          },
          deep: true
        },
      },
    }
    </script>
    

    这样就对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类似。

    相关文章

      网友评论

        本文标题:Vue组件通信—Vuex基础使用和双向绑定

        本文链接:https://www.haomeiwen.com/subject/kohbrctx.html