29

Vuex与组件通信

 4 years ago
source link: https://www.tuicool.com/articles/aaIzqyF
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

概述

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: '
<app />'
})

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 中的数据就会重新初始化。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK