• Vuex与组件通信


    我们在开发一些比较大型的项目中,既有父子组件通信又有兄弟组件通信,甚至无关联的组件间也要通信,这时单靠前面文章中讲的$emit,$on,$refs等方式管理数据显得比较混乱,那么我们可以使用Vuex来管理组件间的数据通信。

    查看演示:https://www.helloweba.net/demo/2019/vuexTodo

    下载源码:https://www.helloweba.net/down/615.html

    概述

    Vuex是一个专为 Vue.js 应用程序开发的状态管理模式。也就是说 Vuex 用于单页面应用组件之间的数据共享,在组件嵌套很多层的情况下,Vue 中父子组件的通信过程就变得很麻烦,此时使用 Vuex 方便了组件间的通信。

    vuex官网上说是一个vue的状态管理工具。其实我们可以简单地把状态理解成为vue的data里面的变量。当组件之间的data变量关系复杂一点的时候,就把其中的变量抽离出来管理。

    Vuex提供了一个数据仓库,存放着各种数据data。谁要用谁去请求num的值,谁想改就改该多好是吧,vuex就是干这个的,有点全局变量的意思。任何组件需要拿,改东西,都可以找他。

    Vuex主要涉及到state,getters,mutations,actions。

    state:是驱动应用的数据源,是惟一的数据载体,跟仓库一样。

    mutations:更改state的唯一方法,意思是修改、增加等处理state的方法,

    getters:从state中派生出的一些状态,如获取数据的数组的长度,方便其他组件获取使用。简单来说,就是过滤,计算,组合!

    actions:用来提交mutations,通过commit再去触发对应的mutations,而不是直接变更state状态。

    稍微简单点的vuex管理就使用statemutations这两个就行。复杂的vuex管理还会涉及到modules等辅助方法。

    应用实例:Todo-list

    本文旨在通过一个简单的todo list例子,熟悉vuex常见的方法,了解组件间数据共享机制。

    本文示例中,分为父组件Main.vue,两个子组件List.vue和Add.vue,父组件包含两个子组件,实时显示列表长度,子组件Add.vue负责添加列表项,List.vue负责显示列表,以及删除列表项。在子组件添加和删除列表项时,相应的组件会联动:父组件会实时计算列表长度,List组件会增减列表项。大家可以先观看效果:Demo

    1. 准备

    本实例采用Vue2 + Vue Router + Vuex + vue-ydui实现。 我们事先已经建立了Vue webpack模板,并安装相关组件。

    npm install --save vuex
    npm install --save vue-router
    npm install --save vue-ydui
    

    2. 建立数据仓库

    在src目录下建立文件夹store/,并在store/目录下新建index.js文件。

    import Vue from 'vue'
    import Vuex from "vuex"
    Vue.use(Vuex)
    
    const store = new Vuex.Store({
        state: {
            message: '',
            todoList: [{id: 0, value: 'default'}]
        },
        getters: {
            //计算list长度
            listCount(state) {
                return state.todoList.length;
            }
        },
        mutations: {
            //新增
            addTodo(state, item) {
                state.todoList.push(item);
            },
            //删除
            delTodo(state, index) {
                state.todoList.splice(index, 1);
            },
            //设置错误提示信息
            showError(state, msg) {
                state.message = msg;
            }
        },
        actions: {
            //提交addTodo
            addTodo(context, item) {
                if (item.value == '') {
                    context.commit('showError', '请输入内容');
                } else {
                    context.commit('addTodo', item);
                    context.commit('showError', '');
                }
            },
            //提交delTodo
            delTodo({commit}, index) {
                commit('delTodo', index);
            }
        },
        modules: {}
    });
    
    export default store;
    

    如上代码和注释,我们在store/index.js中设置了数据以及修改这些数据的方法。

    3. main.js

    在main.js中将store.js加进来。示例中我们还用到了UI库:vue-ydui,也一起加进来。

    import Vue from 'vue'
    import App from './App'
    import router from './router'
    import store from './store'
    
    import YDUI from 'vue-ydui';
    import 'vue-ydui/dist/ydui.rem.css';
    
    Vue.use(YDUI);
    
    Vue.config.productionTip = false
    
    new Vue({
      el: '#app',
      router,
      store,
      components: { App },
      template: ''
    })
    

    4. 设置路由

    在router/index.js加入路由设置,让页面直接访问父组件Main.vue。

    import Vue from 'vue'
    import Router from 'vue-router'
    import Main from '@/components/Main'
    
    Vue.use(Router)
    
    export default new Router({
      routes: [
        {
          path: '/',
          name: 'Main',
          component: Main
        }
      ]
    })
    

    5. Main.vue

    现在我们来看父组件:

    <template>
      <yd-layout>
        <p>这是一个Todo-List示例</p>
        <hw-add></hw-add>
        <hw-list></hw-list>
        <p>todoList 总数:{{listCount}}</p>
        <p>{{msg}}</p>
      </yd-layout>
    </template>
    
    <script>
    import hwAdd from "./Add.vue";
    import hwList from "./List.vue";
    
    export default {
      components: {
        hwAdd,
        hwList
      },
      data(){
        return {
          
        }
      },
      computed: {
        listCount() {
          return this.$store.getters.listCount;
        },
        msg() {
          let message = this.$store.state.message;
          if (message !== '') {
            this.$dialog.toast({
                mes: message,
                timeout: 1500
            });
          }
        }
      }
    }
    </script>
    

    Main.vue用来展示列表和添加列表项等子组件,已经显示列表长度和错误信息提示。我们看到在computed中获取到数据仓库中的数据,并显示在页面上。

    6. Add.vue

    Add.vue用来添加列表项。

    <template>
        <yd-layout>
            <yd-cell-group>
                <yd-cell-item>
                    <yd-icon slot="icon" name="discount" size=".35rem"></yd-icon>
                    <input type="text" slot="right" placeholder="请输入内容" v-model="value" @keyup.enter="addItem">
                    <yd-button slot="right" type="warning" @click.native="addItem">新增</yd-button>
                </yd-cell-item>
            </yd-cell-group>
    
        </yd-layout>
    </template>
    
    <script>
    export default {
        data() {
            return {
                value: '',
                id: 0
            }
        },
        methods: {
            addItem() {
                let item = {
                    value: this.value,
                    id: ++this.id
                }
                this.value = '';
                this.$store.dispatch('addTodo', item);
            }
        }
    }
    </script>
    

    在添加列表项的addItem方法中,我们使用this.$store.dispatch('addTodo', item);告诉vuex的addTodo,我们要往todo list中添加新的列表项。

    7. List.vue

    List.vue用来展示列表项,并且提供删除列表项功能。

    
    <template>
        <yd-layout>
            <yd-cell-group title="Todo列表">
                <yd-cell-item v-for="(item,index) in todoList" :key="index" class="list">
                    <span slot="left">{{index+1}}.{{item.value}}</span>
                    <span slot="right">
                        <yd-icon slot="icon" name="delete" size=".36rem" @click.native="del(index)"></yd-icon>
                    </span>
                </yd-cell-item>
            </yd-cell-group>
        </yd-layout>
    </template>
    
    <script>
    import {mapState} from 'vuex';
    
    export default {
        data() {
            return {
                
            }
        },
        computed: {
            ...mapState([
                'todoList'
            ])
        },
        methods: {
            del(index) {
                this.$store.dispatch('delTodo', index);
            }
        }
    }
    </script>
    

    上述代码中的

    computed: {
            ...mapState([
                'todoList'
            ])
        },
    

    其实相当于:

    computed: {
            todoList() {
                 return this.$store.state.todoList;
            }
        },
    

    小结

    通过示例我们可以知道,使用Vuex来管理数据共享,各组件无需关注组件间的数据通信传输,一切数据的读取和更新都是各组件与Vuex数据仓库间的操作,避免了复杂项目中数据管理混乱的情况发生。

    Vuex的使用还有很多优化的写法,比如mapState、mapGetters、mapActions,本站后面会有文章讲解。

    当然,如果是小型的项目,我们直接用$emit, props等就能解决组件间的数据通信问题,不必使用vuex这个伤脑筋的工具。

    注意:Vuex 是将数据存储在了内存中,每一次刷新页面,之前存在 Vuex 中的数据就会重新初始化。

     

    https://www.helloweba.net/demo/2019/vuexTodo/#/

  • 相关阅读:
    PHP数组函数
    sublime常用快捷键
    PHP中array_merge函数与array+array的区别
    【转】2017PHP程序员的进阶之路
    phpmyadmin上传sql文件大小限制问题解决方案
    二. python的os模块
    一. python的collections模块
    一. python进阶(文件的读写编码)
    七. python进阶(内置函数和高阶函数)
    六. python进阶(递归)
  • 原文地址:https://www.cnblogs.com/116970u/p/14482548.html
Copyright © 2020-2023  润新知