亲宝软件园·资讯

展开

[vue]初探vue生态核心插件Vuex

rencoo 人气:0

为什么会有 Vuex 这个东西 ?

一个应用内部运行的机制,事件 -> 状态 -> UI,我们的前端常常会因为这两个过程而产生大量代码,从而变得难以维护。

vue的声明式渲染,解决了从 状态 和 UI 的同步问题,从而使我们不需要由于状态发生改变去写大量的命令式改变 dom 的代码。

而类似于 vuex 这类状态管理的库,则解决了 事件 -> 状态 这个过程的维护问题。这类库所做的事情就是管理从 事件源映射到状态变化 这个过程(将这个映射过程从视图组件中剥离出来,组织好这一部分的代码,在组件外部进行状态的管理)

Vuex与全局对象的区别

其实,vuex 与全局对象有一定的共同之处,那就是状态会被全局共享,无论是嵌套多少组件…

每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:

  1. Vuex 的状态存储是 响应式 的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到 **高效更新 **。
  2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

Vuex常见的应用场景

管理状态与共享状态

应用简单时,可以使用 propevent 来完成 父子组件 的通信。使用 global event bus(event bus)来实现 简单的非父子组件之间的跨组件 通信。但对于 **多层级组件嵌套 **等较为复杂的场景,使用 vuex 能更好地应对。(使用 event bus 的缺点是当状态较复杂,调用组件非常多,要挨个依次通知所有组件更新;每个组件对这个组件进行的状态更新都要通知所有组件;这样会变得非常复杂)

vuex 状态管理模型,拥有一个统一的数据中心Store,Store用来维护状态数据;每个组件进行更新的时候就通知数据中心,数据中心改变后,再去触发每一个调用它的组件进行更新(相当于由数据中心来统筹状态变化以及状态变化的分发,而不是由每个vue组件直接去操作state)

vuex 是通过将 state 作为数据中心,各个组件 共享 state 来实现跨组件通信的, 此时的数据完全独立于组件。(点击不同模块的操作,不再需要去发送乱七八糟的事件, 只是去调用事件中心里的 mutation 动作, 从而实现模块间共享状态的功能)

需要构建一个中大型单页应用时,很可能会考虑如何更好地 在组件外部 管理状态

vuex更多地用于解决 **跨组件通信 **(多层嵌套组件之间的通信问题)以及作为 数据中心集中式存储数据 (管理应用中错综复杂的状态关系)

vuex 作为数据存储中心

vuexstate在单页应用的开发中本身具有一个 数据库 的作用,可以将组件用到的数据存储在 state中,并在 actions中封装数据读写的逻辑。目前主要有两种数据会使用 vuex进行管理

  1. 组件之间 全局共享 的数据
  2. 通过后端异步请求的数据

实际项目开发中更多的是用到第二种,即把通过后端异步请求的数据都纳入 vuex 状态管理,在 actions 中封装数据的增删改查等逻辑,这样可以在一定程度上对前端的逻辑代码进行分层,使组件中的代码更多地关注页面交互与数据渲染等 视图层 的逻辑,而异步请求与状态数据的持久化等则交由 vuex 管理

一般全局数据,会使用到 vuex 来管理。比如 用户数据,系统数据 等,这些数据很多组件中都会使用,我们当然可以每次使用的时候都去请求,但是出于程序员的“洁癖”、“抠”等等优点,还是希望一次请求,到处使用。

这时候很自然的想到存储在 localStorage 中,但是有个问题是,这些数据可能会变,如果没能及时 同步 的话,就会用到不正确的数据,即使做了数据同步,但是 localStorage 中的数据不是响应式的,不能自动更新使用到这些数据的地方。这时候就想要开始使用 vuex了。

Vuex代码的组织方式

vue-router 类似,有非模块化写法与模块化写法(其实无论何种写法本质上是一样的,目的就是导出一份 router或者 store 的配置数据)

以管理 count 与 用户信息 userinfo 为例,介绍 vuex代码的组织方式

核心概念 state,getter,mutation,action,module

vuex 需要遵守的规则

应用层级的状态应该集中到 单个 store 对象中

mutation是直接操作state的方法(唯一能改变状态的方法),过程要求必须同步

action 通过commit去触发mutation,从而间接修改状态,优点是允许异步逻辑,

非模块化写法
// 1.安装 vuex

// 2.在入口文件中引入
// main.js
import Vuex from 'vuex'

// 3.Vue使用 vuex 插件
Vue.use(Vuex)

// 4.生成数据管理中心 store
const store = new Vuex.Store({
    state: {
        userinfo: null, // 需要给定初始值
        count: 0
    },
    // 直接通过mutation方法来mutate操作state; 只能以同步的方式; mutation方法需要通过commit来触发
    mutations: {
        userinfo: function (state, payload) {
              state.userinfo = options
            localStorage.userinfo = JSON.stringify(state.userinfo)
        },
        increment: function (state, payload) {
            state.count += payload.amount
        }
    },
    // 通过commit触发mutations里的mutation方法, 以此间接修改 state; 允许异步操作;action方法需要通过dispatch来触发
    actions: {
        increment: function (context, payload) {
            context.commit('increment', payload)
        },
        incrementAsync: function (context) {
            // 异步请求数据
            setTimeout(() => {
                var amount = 10; // 模拟异步请求得到数据
                context.commit('increment', { amount })
            }, 1000)
        },
        async userinfo (context) {
            let response = await getUserInfo() // 异步请求后端数据 方法需要 import
            if (response.ok) {
                let json = await response.json()
                context.commit('userinfo', json)
            }
        }
    },
    getters: {// 处理、过滤数据

    }
})

// 5.通过 store 配置参数注入状态管理,从而任何组件可通过 this.$store 访问状态中心
new Vue({
    el: '#app',
    store, // (*)
    render: function (h) {
        return h(App)
    }
})
模块化写法
// 1.安装vuex

// 2.引入
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
// import ...

// 3.Vue使用 vuex 插件
Vue.use(Vuex)

// 4.分模块生成数据管理中心
// 配置 userinfo 状态模块 (还能再单独拆出一个文件,然后import进来)
const moduleA = {
    state: {
        userinfo: null // 需要初始化响应式数据
    },
    mutations: {
        userinfo: function (state, options) {
            state.userinfo = options
            localstorage.userinfo = JSON.stringify(state.userinfo)
        }
    },
    actions: {
        async userinfo (context) {
            async userinfo (context) {
                let response = await response.json()
                if (response.ok) {
                    let json = await response.json()
                    context.commit('userinfo', json)
                }
            }
        },
        getters: {// 处理、过滤数据

        }
    }
}

// 配置 count 状态模块 (还能再单独拆出一个文件,然后import进来)
const moduleB = {
    state: {
        count: 1,
    },
    mutations: {
        increment:function (state, payload) {
            state.count += payload
        },
    },
    actions: {
        increment: function (context, payload) {
              context.comit('increment', payload)  
        },
          incrementAsync: function (context) {
            // 异步请求数据
            setTimeout(() => {
                var amount = 10; // 模拟异步请求得到数据
                context.commit('increment', { amount })
            }, 1000)
        },  
    },
    getters: {
        doubleCount (state) {
            return state.count * 2
        }
    }
}

export default new Vuex.Store({
    modules: { // 这里与非模块化写法有点不一样;原来整个对象是一份配置...
        a: moduleA,
        b: moduleB,
    }
})

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

在不同组件中使用或操作状态

// 根组件
// App.vue
// 在生命周期中触发全局共享数据的获取
...
mounted () {
    if (!this.$store.state.userinfo) { // this.$store.state.a.userinfo 模块化写法的话
        this.$store.dispatch('userinfo')
    }
}

// 使用 state 的数据
computed: {
    userinfo () {
        return this.$store.state.userinfo
        // return this.$store.state.a.userinfo // 模块化写法的话
    },
    count () {
        return this.$store.state.count
        // return this.$store.state.b.count // 模块化写法的话
    }
}
// 子组件
// NavBar.vue
...
// 改变 state 的数据
methods: {
    // 使用 commit 触发 mutations 中的 mutation 方法,直接修改 state 中的数据
    addOne () {
        this.$store.commit('increment', { amount: this.price })
    },
    // 使用 dispatch 触发 actions 中的 action 方法;异步修改 state 中的数据
    addTenAsync () {
        this.$store.dispatch('incrementAsync')
    }
}

// 使用 state 的数据
computed: {
    userinfo () {
        return this.$store.state.userinfo
        // return this.$store.state.a.userinfo // 模块化写法的话
    }
}
// 路由页面组件
// Manage.vue
...
// 改变 state 的数据
methods: {
    addTwo () {
        this.$store.commit('increment', { amount: this.price })
    }
}

// 使用 state 的数据
computed: {
    count () {
        return this.$store.state.count
        // return this.$store.state.b.count // 模块化写法的话
    }
},

总之,使用了 vuex 来管理状态,点击不同模块的操作,不再需要去发送乱七八糟的事件, 只是去调用事件中心里的 mutation 动作, 从而实现模块间共享状态的功能;修改一处,全局共享(无论是组件还是路由页面组件都能同步)

加载全部内容

相关教程
猜你喜欢
用户评论