最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Vue基础知识巩固之全面了解Vuex,比官方更易懂(上)

    正文概述 掘金(十里青山)   2021-03-27   796

    前言

    写项目很久了,偶尔用到Vuex也是用一些很浅显的功能,就是简单的存储一下用户信息,用的时候取一下,很少深入的使用,现在静下心来想给自己写个项目,在写的过程中,顺便把以往忽略的基础知识学习巩固一下,这篇文章就是记录一下学习Vuex的知识,既然是巩固知识,那那些基础的就直接一笔带过了。

    本文面向对象也主要是初学者,所以用词更偏向于易懂,所以建议大家理解之后还是去看一下官方文档,熟悉一下专业术语,并且本文主要挑重点的讲,大家也可以去看一下官方文档查漏补缺。

    介绍

    什么是Vuex?

    在日常的项目开发中,我们经常会遇到一些需要全局存储的变量,需要多个地方使用,比如用户信息,购物车等,在之前,我们采取的方案可能就是设置公共组件或者利用 cookielocalstorage 等本地存储方式进行存储,但这样的方法无疑会带来很多弊端,例如:

    • 需要在多个模块频繁引用
    • 存储格式限制,取值时候需要格式转换
    • 存储结构不够清晰
    • 不是响应式的
    • 无法形成统一规范,接受别人代码需要一定时间理解
    • 无法追踪值的修改记录
    • ……

    以上这些问题Vuex都可以统统为我们解决掉,下面我们就来看看Vuex官方是如何解释vuex的

    以上是vuex官方文档对于vuex的解释,但对于初级vue开发者来说,这样的解释无疑太过官方,过于拗口也难以理解,其实用白话文解释一下,大致就是Vuex是一个仅能在Vue.js环境下使用的一个公共状态存储仓库,这个仓库里可以存储你所经常使用的全局变量,并且为你指定了规定的方式去修改仓库里的变量,并且如果你用这种方式修改仓库里的变量,那么所有的修改记录都可以被保存。

    安装及使用

    像Vue一样,我们也可以通过script标签引入的方式和模块安装的方式使用Vuex,通常我们会通过Vue-cli新建Vue项目,如果你选择了的话,Vue-cli会自动为我们的新项目安装并引入Vuex,此处不在赘述,后续的内容讲解以在此情况下展开。

    Vuex核心概念

    简述

    Vuex的核心概念如下所示,包括state,Getters,mutations和Actions,下面我们就来分别深入了解他们的作用。

    import Vue from 'vue'
    import Vuex from 'vuex'
    import getters from './getters'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
      },
      mutations: {
      },
      actions: {
      },
      getters
    })
    
    

    state

    state 就是我们在 Vuex 中存储数据的地方,state 中的数据和 Vue 实例中的 data 一样,也必须以键值对的形式存在。

    我们可以事先在state中定义好一个数据

    export default new Vuex.Store({
      state: {
        count: 0
      }
    })
    
    

    由于我们之前已经在Vue实例中通过 store 选项从根组件“注入”到每了一个子组件中,所以我们可以在所有的子组件中通过this.$store 访问store实例中的的内容

    Vuex有一种官方推荐的使用方法,因为 Vuex 的状态存储是响应式的,所以Vuex鼓励我们使用Vue的计算属性去从store实例中读取state

    <template>
      <div id="app">
        <div class="message">{{ count }}</div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'App',
      computed: {
        count () {
          return this.$store.state.count
        }
      }
    }
    </script>
    

    还有的同学会选择在 data 中去读取state中的值

    <template>
      <div id="app">
        <div class="message">{{ count }}</div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'App',
      data () {
        return {
          count: this.$store.state.count
        }
      }
    }
    </script>
    

    这样子看上去显示正常,但会有一个隐患,那就是在 data 中获取store实例中的值,不是响应式的,data 中的值存储的只是 created 时候store实例中对应的值的字面量,后续该值发生任何变化,data 中的值都不会发生变化。下面我们可以来看一个例子。

    <template>
      <div id="app">
        <div class="message">{{ count }}</div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'App',
      data () {
        return {
          count: this.$store.state.count
        }
      },
      mounted () {
        setTimeout(() => {
          this.$store.commit('increment', 10)
        }, 2000)
      }
    }
    </script>
    

    Vue基础知识巩固之全面了解Vuex,比官方更易懂(上)

    可以看到,虽然我们在进入页面两秒后对store实例中的值进行了修改,我们的页面上却并没有跟着变化。

    当然官方也没有推荐直接在模板中使用,虽然那样做一样可以达到效果。我也不知道为啥,有知道有什么区别的同学可以在评论区留言。

    <template>
      <div id="app">
        <div class="message">{{ this.$store.state.count }}</div>
      </div>
    </template>
    

    getters

    getters官方讲的比较简单,这里就直接搬过来展示了。

    有时候我们需要对取到的值进行计算之后进行展示,例如对列表进行过滤并计数

    computed: {
      doneTodosCount () {
        return this.$store.state.todos.filter(todo => todo.done).length
      }
    }
    

    如果有多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。

    Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

    Getter 接受 state 作为其第一个参数:

    const store = new Vuex.Store({
      state: {
        todos: [
          { id: 1, text: '...', done: true },
          { id: 2, text: '...', done: false }
        ]
      },
      getters: {
        doneTodos: state => {
          return state.todos.filter(todo => todo.done)
        }
      }
    })
    

    Getter 也可以接受其他 getter 作为第二个参数:

    getters: {
      // ...
      doneTodosCount: (state, getters) => {
        return getters.doneTodos.length
      }
    }
    

    然后我们就可以在组件中直接使用了

    computed: {
      doneTodos () {
        return this.$store.getters.doneTodos
      },
      doneTodosCount () {
        return this.$store.getters.doneTodosCount
      }
    }
    

    有时候我们会想给getter 传参,以便让它按照我们不同的需求返回不同的数据。

    getters: {
      // ...
      getTodoById: (state) => (id) => {
        return state.todos.find(todo => todo.id === id)
      }
    }
    
    store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
    

    Mutations

    Mutation的基本使用

    注意:为了防止误解,特注明,Mutatios里的每一个函数都称为一个Mutation,所以当我们说一个Mutation的时候指的是Mutations中的一个函数

    前面说了,Vuex给为我们指定了规定的方式去修改仓库里的变量,也就是state里的值,那就是去提交 mutation。因为Vuex 也集成到 Vue 的官方调试工具 devtools,所以我们可以很方便的通过devtools去查看Vuex里的值和相应的变化。

    当你安装了vue-devtools之后,可以打开控制台,找到vue标签,点击第二个图标,即可开始Vuex的调试。 Vue基础知识巩固之全面了解Vuex,比官方更易懂(上)

    那我们如何去通过Mutation去修改state里的值呢?Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,还可以接收第二个可选参数:

    const store = new Vuex.Store({
      state: {
        count: 1
      },
      mutations: {
        testMutation (state, obj) {
          state.count = obj.num
        }
      }
    })
    

    当我们在组件内调用时,需要通过commit方法去触发mutation,commit方法接受两个参数,第一个为要触发的mutation的名字,第二个参数为我们要传递过去的参数(可选),如果我们要传递多个参数,则可以将多个参数放入一个对象传递过去

    this.$store.commit('increment', {num: 10,remarks: '测试' })
    

    当然,我们还有另一种写法,这两种写法除了风格不同,作用完全相同

    this.$store.commit({
      type: 'increment',
      num: 10,
      remarks: '测试'
    })
    

    Mutation 需遵守 Vue 的响应规则

    既然 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:

    1. 最好提前在你的 store 中初始化好所有所需属性。
    2. 当需要在对象上添加新属性时,你应该
    • 使用 Vue.set(obj, 'newProp', 123), 或者
    • 以新对象替换老对象。例如,利用对象展开运算符我们可以这样写:
    state.obj = { ...state.obj, newProp: 123 }
    

    Mutation与devtools

    在上面的示例中,我们已经知道如何通过devtools查看store实例里的值,而且我们也说了,通过官方指定的操作方式去修改state的值,会留下操作记录,那操作记录是什么样的呢,下面我们就直接来操作一下。

      state: {
        count: 5
      },
      mutations: {
        increment (state) {
          // 变更状态
          state.count++
        }
      }
    
      mounted () {
        setInterval(() => {
          this.$store.commit('increment', {
            remarks: '位于首页的计数器'
          })
        }, 5000)
      }
    

    Vue基础知识巩固之全面了解Vuex,比官方更易懂(上)

    可以看到,我们每次调用commit都能留下一条操作记录,操作记录里包含了我们触发的Mutation,触发的时间,触发之后的state,我们甚至还可以在其中留下一些‘登记信息’,以便我们不知道这个值是被哪个页面修改的时候进行调试,我们只要单击任意一条记录,便可查看该次触发的详细信息。

    并且当我们点击这个小图标时,调试工具包括页面上引用的store实例状态将马上变回此次触发Mutation后store实例的状态,并且我们还可以随时点击最新的记录,以便回到最新的状态。

    Vue基础知识巩固之全面了解Vuex,比官方更易懂(上)

    不要直接进行赋值操作

    看,通过调用commit触发Mutation的方法对于我们的调试来说是不是如此之方便,那如果我们使用直接赋值的方式进行操作会怎么样呢?

      mounted () {
        setInterval(() => {
          this.$store.state.count++
        }, 5000)
      }
    

    Vue基础知识巩固之全面了解Vuex,比官方更易懂(上)

    虽然store实例里的值确实被修改了,但却没有留下任何操作记录,我们也无法在调试记录里看到最新的state的值,这对于我们的调试将十分不利,并且对我们的代码语义化也十分不利,它将变得更难以阅读、难以理解。

    严格模式

    如果你想在项目中仅通过Mutation去修改state里面的值,你可以开启严格模式。在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。

    开启严格模式,仅需在创建 store 的时候传入 strict: true

    const store = new Vuex.Store({
      // ...
      strict: true
    })
    

    不要在发布环境下启用严格模式! 严格模式会深度监测状态树来检测不合规的状态变更——请确保在发布环境下关闭严格模式,以避免性能损失。

    类似于插件,我们可以让构建工具来处理这种情况:

    const store = new Vuex.Store({
      // ...
      strict: process.env.NODE_ENV !== 'production'
    })
    

    不要在Mutation中进行异步操作 当我们在Mutation中进行异步操作时,Vuex将无法知道我们此次的异步操作将在何时完成,也就无法在操作记录里留下正确的数据,这也就违背了Mutation设计的初衷,下面我们通过实操来看一下

      mutations: {
        increment (state) {
          // 变更状态
          setTimeout(() => {
            state.count++
          })
        }
      }
    

    Vue基础知识巩固之全面了解Vuex,比官方更易懂(上)

    可以看到,虽然store实例中的数据可以跟着变化,但我们在每次修改内容的操作记录中却无法记录到正确的值,所以我们只能在Mutation中进行同步操作,那如果我们想要进行异步操作怎么办呢,比如我想把登录的操作放在Vuex中进行怎么办呢?Vuex针对异步操作,也贴心的为我们准备了下一个核心概念——action

    actions

    注意:为了防止误解,特注明,actions里的每一个函数都称为一个action,所以当我们说一个action的时候指的是action的一个函数

    此处官方文档内容比较简单易懂,直接搬过来。

    Action 类似于 mutation,不同在于:

    • Action 提交的是 mutation,而不是直接变更状态。
    • Action 可以包含任意异步操作。

    让我们来注册一个简单的 action:

    const store = new Vuex.Store({
      state: {
        count: 0
      },
      mutations: {
        increment (state) {
          state.count++
        }
      },
      actions: {
        increment (context) {
          setTimeout(() => {
            context.commit('increment')
          }, 2000)
        }
      }
    })
    
    this.$store.dispatch('increment')
    

    由于Mutation和Action的触发方式不同,Mutation的名字可以和Action重名

    由于action中可以进行任意异步操作,所以我们可以在action中进行异步操作(比如调用api接口)之后再调用commit调用Mutation。

    action和Mutation不同的地方在于,Mutation的触发方式为commit,action的触发方式为 dispatch,另外Mutation的第一个参数为state,action的第一个参数为context(上下文对象),相同的是他们都可以用第二个参数接收用户传入的参数。

    Vue基础知识巩固之全面了解Vuex,比官方更易懂(下)


    起源地下载网 » Vue基础知识巩固之全面了解Vuex,比官方更易懂(上)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元