日志总结 - 2018-06-06

Vuex学习笔记

初始化

  1. html引入

        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <script src="https://unpkg.com/vuex@3.0.1/dist/vuex.js"></script>
        <!-- 或者下载下来文件夹引入 -->
    
  2. NPM

      npm install vuex --save
    
      import Vue from 'vue'
      import Vuex from 'vuex'
    
      Vue.use(Vuex)
    

what?

  1. Vuex是一个专为Vue.js应用程序开发的状态管理模式, 采用集中式存储管理应用的所有组件的状态, 并以相应的规则保证状态以一种可预测的方式发生变化
  2. 我的理解: Vuex就是提取各个组件共同需要用的数据和函数, 类似共享属性和方法, 方便在各个组件间的数据通信
  3. 状态自管理应用包含三个部分:
    3.1 state: 驱动应用的数据源;(data)
    3.2 view: 以声明方式将state映射到视图;(template)
    3.3 actions: 响应在view上的用户输入导致的状态变化;(methods)
    3.4 单向数据流: View --> Actions --> State --> View;(多组件共享状态会破坏单向数据流的简洁性)
  4. Vuex基本思想: 把组件的共享状态抽取出来, 以一个全局单例模式管理, 组件树构成一个巨大的"视图"


    Vuex基本思想

核心

  1. Store
    1. 每一个Vuex应用的核心就是store(仓库), 基本上就是一个容器, 包含应用的大部分状态(state)
      1.1.1 Vuex的状态存储是响应式的
      1.1.2 改变store中的状态的唯一途径就是显式提交(commit) mutation
        var store = new Vuex.Store({
          state: {
            count: 0
          },
          mutations: {
            increment: function(state){
              state.count++
            }
          }
        })
    
        // store.commit('increment')
        // console.log(store.state.count) // -> 1
        // 最基本的Vuex计数应用Demo
        // https://jsfiddle.net/n9jmu5v7/1269/
    
  2. State
    1. 单一状态树: 用一个对象包含全部的应用层级状态, 唯一数据源(每一个应用仅仅包含一个store实例)
    2. 在Vue组件中获取Vuex状态(获取state里面的数据)的方法:
      1. 计算属性: computed
            组件中
            computed: {
              count: function(){
                  return this.$store.state.count
              }
            }
        
      2. 辅助函数: mapState(一个组件获取多个状态时候)
            在组件中
            computed: Vuex.mapState({
              count: function(state){
                return state.count
              },
              countAlias: 'count',
              countPlusLocalState: function(state){
                return state.count+this.localCount
              }
            })
            对象展开运算符
            computed: {
              ...mapState(['state里面的参数','state里面的参数'])
            },
            mounted: function(){
                console.log(this.上面...mapState里面的参数就可以获取到)
            }
        
      3. 注意: 封装成组件的局部状态
  3. Getter
    1. 需要从store中的state中派生出一些状态, 例如对列表进行过滤并计数;
    2. 相当于store的计算属性, 接受state作为第一个参数, 通过store.getters访问;
    3. getters做为第二个参数,调用getters;
    4. 组件中使用: this.$store.getters.参数名
    5. 通过方法访问, 让getter返回一个函数, 实现给getter传参 (在对store里面的数组进行查询时非常有用)
    6. 注意, getter通过方法访问, 每次都会去进行调用, 而不会缓存结果
    7. mapGetters辅助函数: 映射局部计算属性
  4. Mutation
    1. 更改Vuex的store的状态唯一方法是提交mutation, 每一个mutation都有一个字符串的事件类型和一个回调函数, 接受state第一个参数;
    2. 提交载荷: 第二个参数以后为载荷参数或者载荷对象
    3. 遵守响应规则:
      1. 最好提前在store中初始化所需属性;
      2. 添加新属性时, 用Vue.set(obj, 'newProp', 123) 或者以新对象替换老的 state.obj = {...state.obj, newProp:123}
    4. Mutation 必须是同步函数
    5. 组件提交mutation this$store.commit('xxx'), 或者使用mapMutations辅助函数
  5. Action
    1. Action类似于mutation, 不同在于Action提交的是mutation, 而不是直接修改状态, 可以异步操作;
    2. context对象, context.commit , context.state, context.getters
    3. 分发Action: store.dispatch('increament')
    4. 组件分发: this.$store.dispatch('...')
  6. Module
    1. 将store分割成模块, 每个模块拥有自己的state, mutation, action, getter
          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 的状态 */
      
    2. 模块的局部状态:对于模块内部的mutation和getter, 接收的都是模块的局部状态对象;而action通过context.state & context.rootState; getter的根节点状态作为第三个参数暴露
          const moduleA = {
              state: {
                  count: 0
              },
              mutations: {
                  increment(state){
                      /* state 对象是模块的局部状态 */
                      state.count++
                  }
              },
              getters: {
                  doubleCount(state){
                      return state.count*2
                  },
                  sumWithRootCount(state, getters, rootState){
                      return state.count+rootState.count
                  }
              },
              actions: {
                  incrementIfOddOnRootSum({state, commit, rootState}){
                      if((state.count + rootState.count) %2===1){
                          commit('increment')
                      }
                  }
              }
          }
      
    3. 命名空间:默认情况下,模块内部的action、mutation和getter是注册在全局命名空间的——多模块对同一mutation或action做出响应;如果需要封装和复用,添加 namespaced: true, 对getters、actions、mutations有影响
          const store = new Vuex.Store({
              modules: {
                  account: {
                      namespaced: true,
      
                      state: {...}, /* 模块内的状态已经是嵌套的了,使用 namespaced 属性不会对其产生影响 */
                      getters: {
                          isAdmin(){...0}  /* -> getters['account/isAdmin'] */
                      },
                      actions: {
                          login () { ... } /* -> dispatch('account/login') */
                      },
                      mutations: {
                          login () { ... } /* -> commit('account/login') */
                      },
      
                      /* 嵌套模块 */
                      modules: {
                          /* 继承父模块的命名空间 */
                          myPage: {
                              state: { ... },
                              getters: {
                                  profile () { ... } /* -> getters['account/profile'] */
                              }
                          },
      
                          /* 进一步嵌套命名空间 */
                          posts: {
                              namespaced: true,
      
                              state: { ... },
                              getters: {
                                  popular () { ... } /* -> getters['account/posts/popular'] */
                              }
                          }
                      }
                  }
              }
          })
      
    4. 带命名空间的模块内访问全局内容:
      1. 全局state和getter, rootState和rootGetter传入getter, 通过context对象属性传入action
      2. 全局命名空间内分发action或者提交mutation,将{root: true} 作为三参传给dispatch或commit
            commit('somMutation', null, {root: true})
        
    5. 带命名空间模块注册全局action: 添加root:true, 放在函数handler中
          {
              actions: {
                  someOhterAction({dispatch}){
                      dispatch('someAction')
                  }
              },
              modules: {
                  foo: {
                      namespaced: true,
                      actions: {
                          someAction: {
                              root: true,
                              handler(namespacedContext, payload){
                                  ...
                              }
                          }
                      }
                  }
              }
          }
      
    6. 带命名空间的绑定函数
          computed: {
              ...mapState({
                  a: state => state.some.nested.module.a,
                  b: state => state.some.nested.module.b,
              })
          },
          methods: {
              ...mapActions([
                  'some/nested/module/foo',
                  'some/nested/module/bar',
              ])
          }
      
          /* 简化 */
          computed: {
              ...mapState('some/nested/module', {
                  a: state => state.a,
                  b: state => state.b
              })
          },
          methods: {
              ...mapActions('some/nested/module', [
                  'foo',
                  'bar'
              ])
          }
      
          createNamespacedHelpers('some/nested/module')
      
    7. 模块重用: 把state写成函数形式, 避免状态对象模块间数据互相污染
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • 安装 npm npm install vuex --save 在一个模块化的打包系统中,您必须显式地通过Vue.u...
    萧玄辞阅读 2,920评论 0 7
  • State 单一状态树 Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“...
    peng凯阅读 682评论 2 0
  • Vuex是什么? Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件...
    萧玄辞阅读 3,091评论 0 6
  • Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应...
    白水螺丝阅读 4,648评论 7 61
  • Vuex 是什么? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有...
    skycolor阅读 811评论 0 1