• Vuex笔记


    1. Vuex

    • 状态管理

    2.Vuex管理些什么

    • 用户登录状态, token , 头像 ,地理位置等
    • 商品收藏,购物车中的东西

    3. Vuex安装

    • 使用npm安装Vuex

      npm install vuex --save
      
    • 在项目的src目录下面创建一个store目录,并在该目录下面创建一个index.js

      index.js内容如下:

      import Vue from 'vue'
      import Vuex from 'vuex'
      
      // 1. 安装插件
      Vue.use(Vuex)
      // 2. 创建对象
      const store = new Vuex.Store({
          state:{},
          mutations:{},
          actions:{},
          getters:{},
          modules:{}
      })
      
      // 3. 导出store独享
      export default store
      
    • 在main.js中挂载vuex

      import Vue from 'vue'
      import App from './App.vue'
      import store from "./store";
      Vue.config.productionTip = false
      
      new Vue({
        render: h => h(App),
        store
      }).$mount('#app')
      
      

    4. Vuex的基本使用

    4.1 state

    • 在state中定义一个变量之后,全局都可以使用.而且还是响应式的,使用起来很方便
    const store = new Vuex.Store({
        state:{
            counter: 1000  // 定义一个counter
        },
        mutations:{},
        actions:{},
        getters:{},
        modules:{}
    })
    
    • 在组件中使用counter
      <div class="hello">
        <h2>{{$store.state.counter}}</h2>
      </div>
    

    4.2mutations

    • mutations是对state中的状态数据进行管理.

      const store = new Vuex.Store({
          state: {
              counter: 1000
          },
          mutations: {
              // 提供一个increment方法,供组件进行调用
              increment(state) {
                  state.counter++;
              },
                // 提供一个increment方法,供组件进行调用
              decrement(state) {
                  state.counter--
              }
          },
          actions: {},
          getters: {},
          modules: {}
      })
      
    • 组件调用mutations中的方法

      <script>
          export default {
              name: 'HelloWorld',
              props: {
                  msg: String
              },
              methods: {
                  add() {
                      this.$store.commit('increment')  // 调用increment方法
                  },
                  sub() {
                      this.$store.commit('decrement') // 调用decrement方法
                  }
              }
          }
      </script>
      
    • 示例2:

      • 需求: 对counter每次添加一个任意数

      • mutations方法定义incrementNum

            mutations: {
                // 定义一些方法
                increment(state) {
                    state.counter++;
                },
                decrement(state) {
                    state.counter--
                },
                // 每次添加x
                incrementNum(state, number) {
                    return state.counter += number
                }
            },
        
      • 组件调用mutations中的incrementNum方法

         <button @click="addNum(5)">+5</button>
         <button @click="addNum(10)">+10</button>
        
        methods: {
                    add() {
                        this.$store.commit('increment')
                    },
                    sub() {
                        this.$store.commit('decrement')
                    },
                    addNum(number) {
                        this.$store.commit('incrementNum',number)
                    }
                }
        
      • 看得出来,mutations中方法传参很方便. 当然也可以使用对象传参.

    • 示例3. 响应式新增/删除属性

      •  state: {
                info: {
                    name: 'jet',
                    age: 19,
                    gender: 'female'
                }
            },
        
      •   mutations: {
                updateInfo(state) {
                    // 给info添加一个address属性.
                    // state.info.address='bj'  // 这种方式可以修改state中的info属性,但是info不会响应式更新组件
                    Vue.set(state.info, 'address', 'Bj')  // 使用这种方式,可以响应式的更新info中的属性.
        
                    // 删除属性
                    // delete state.info.age  // 不是响应式
                    Vue.delete(state.info,'age')  // 响应式的删除info中的age属性
                }
            },
        

    4.3 getters

    • 如果想要获取state中数据产生的变异结果,就可以使用getters,它相当于vue中的计算属性

    • 示例1

      const store = new Vuex.Store({
          state: {
              counter: 1000
          },
          mutations: {
              increment(state) {
                  state.counter++;
              },
              decrement(state) {
                  state.counter--
              }
          },
          actions: {},
          getters: {
              powerCounter(state) {  // 定义一个方法
                  return state.counter * state.counter
              }
          },
          modules: {}
      })
      
    • Vue组件如何调用getters方法

       <h2>演示getters方法: {{$store.getters.powerCounter}}</h2>
      
    • 示例2

      const store = new Vuex.Store({
          state: {
              counter: 1000,
              students:[
                  {id:1,name:'kobe',age:30},
                  {id:2,name:'jet',age:18},
                  {id:3,name:'kk',age:39},
                  {id:4,name:'jj',age:26},
              ]
          },
          mutations: {
              // 定义一些方法
              increment(state) {
                  state.counter++;
              },
              decrement(state) {
                  state.counter--
              }
          },
          actions: {},
          getters: {
              powerCounter(state) {  // 定义一个方法
                  return state.counter * state.counter
              },
              // 获取年纪大于20的student
              ageGt20(state) {
                  return state.students.filter(x => x.age > 20);
              }
          },
          modules: {}
      })
      
      <h2>HelloWorld,演示getters方法: {{$store.getters.ageGt20}}</h2>
      
      <h1>APP 演示getters{{$store.getters.ageGt20}}</h1>
      

      可以看到在使用getters的好处是,定义一个方法,在项目中任一组件中都可以方便的调用. -

    • 示例2也可以使用计算属性进行实现

     computed: {
                ageMore20() {
                    return this.$store.state.students.filter(x => x.age > 20)
                }
            },
    
    <h2>HelloWorld,使用计算属性: {{ageMore20}}</h2>
    

    但是,使用计算属性有个缺点,那就是在哪个组件中声明就只能在那个组件中使用.

    • getters中定义的方法还可以传入getters作为入参

          getters: {
              powerCounter(state) {  // 定义一个方法
                  return state.counter * state.counter
              },
              // 获取年纪大于20的student
              ageGt20(state) {
                  return state.students.filter(x => x.age > 20);
              },
              // 获取年纪大于20岁的student的个数
              ageGt20Count(state,getters) {
                  return getters.ageGt20.length
              }
          },
      

      总结 : getters中定义的方法可以有两个入参,第1个是state,第2是getters本身.

    • 示例3 (高级版)

      • 需求: 获取年纪大于x岁的学生信息

      • vuex中getters中的代码

        const store = new Vuex.Store({
            state: {
                counter: 1000,
                students:[
                    {id:1,name:'kobe',age:30},
                    {id:2,name:'jet',age:18},
                    {id:3,name:'kk',age:39},
                    {id:4,name:'jj',age:26},
                ]
            },
            mutations: {
                // 定义一些方法
                increment(state) {
                    state.counter++;
                },
                decrement(state) {
                    state.counter--
                }
            },
            actions: {},
            getters: {
                powerCounter(state) {  // 定义一个方法
                    return state.counter * state.counter
                },
                // 获取年纪大于20的student
                ageGt20(state) {
                    return state.students.filter(x => x.age > 20);
                },
                // 获取年纪大于20岁的student的个数
                ageGt20Count(state,getters) {
                    return getters.ageGt20.length
                },
                
                // 获取年纪大于x岁的student
                ageGtx(state) {
                    return function (x) {
                        return state.students.filter(stu=> stu.age > x)
                    }
                }
            },
            modules: {}
        })
        
      • 组件调用ageGtx

                <h2>HelloWorld,演示getters使用,获取年纪大于x岁的: {{$store.getters.ageGtx(10)}}</h2>
        
        
      • 说明

        •   ageGtx(state) {
                      return function (x) {
                          return state.students.filter(stu=> stu.age > x)
                      }
                  }
          

          看这段代码 ,ageGtx返回的是一个function,且这个function还是一个带参的function

        • {{$store.getters.ageGtx(10)}}
          

          {{$store.getters.ageGtx}}这段代码的结果其实就是ageGtx返回的function, 而(10)就是调用这个function,并且入参是10.

        • 通过这种方式实现,感觉很巧妙呀.

        • 上面的ageGtx可以用箭头函数进行简写

           ageGtx(state) {
                    return x => {
                          return state.students.filter(stu => stu.age > x)
                      }
                  }
          

    4.4 actions

    • 所有的异步操作都在actions中完成.

    • 示例1

      • Vue组件---> Actions----> Mutations----> State ---> 响应到Vue组件.

      • Mutations中定义的方法,直接操作State

         mutations: {
                updateInfo(state) {
                    // 给info添加一个address属性.
                    // state.info.address='bj'  // 这种方式可以修改state中的info属性,但是info不会响应式更新组件
                    Vue.set(state.info, 'address', 'Bj')  // 使用这种方式,可以响应式的更新info中的属性.
        
                    // 删除属性
                    // delete state.info.age  // 不是响应式
                    Vue.delete(state.info,'age')  // 响应式的删除info中的age属性
                }
            },
        
      • Actions中定义一个aUpdateInfo方法,方法内部的逻辑是异步执行.

           actions: {
                aUpdateInfo(context) {
                	// 异步方法
                    setTimeout(() => {
                        context.commit('updateInfo')  // 在actions中调用mutations中的updateInfo方法,对state中的info进行修改
                    }, 1000);
                }
        
            },
        
      • Vue组件调用Actions中的方法

         methods: {
                 
                    updateInfo() {
                        // this.$store.commit('updateInfo')// 这个通过Mutations操作state
                        this.$store.dispatch('aUpdateInfo') // 这个通过Actions操作Mutations,再通过Mutations操作state
                    }
                }
        
      • 注意: 操作Mutations中方法用commit方法,操作Actions中方法用dispatch

    • 示例2(传参)

      • Vue组件在调用Actions中的方法时,传参,跟调用Mutations中的方法一样, 可以直接传对象

      • Vue组件的methods属性中定义方法updateXXX

        updateXXX() {
        	this.$store.dispatch('updateXXX', '测试传参');// 调用Actions中的方法
        }
        
      • Vuex中Actions定义的updateXXX

         updateXXX(context,msg) {
                    setTimeout(()=>{
                        console.log(msg);  // 测试传参
                    },1000)
                }
        
    • 示例3(回调)

      • 需求: 以示例2为基础,如果Actions中的updateXXX方法,打印msg成功之后,给Vue组件发个通知(回调函数)

      • Vue组件的methods属性中定义方法updateXXX

        updateXXX() {
                        this.$store.dispatch('updateXXX', {
                            msg:'测试传参',
                            callback: ()=>{
                                console.log("传参成功,回调打印...")
                            }
                        });
                    }
        
      • Vuex中Actions定义的updateXXX

         updateXXX(context,payload) {
                    setTimeout(()=>{
                        console.log(payload.msg);
                        payload.callback()  // 执行回调函数
                    },1000)
                }
        
      • 如果不传参,在Vue组件的updateXXX方法中,可以直接传函数

         updateXXX() {
                
                this.$store.dispatch('updateXXX',()=>{
                	console.log("传参成功,回调打印...")
                })
           }
        
    • 示例4(回调,使用Promise,推荐.)

      • Actions中定义updateXXX方法

         updateXXX(context, msg) {
                    return new Promise((resolve, reject) => {
                        setTimeout(() => {
                            console.log(msg);
                            resolve("action方法执行完毕,这是一条回调信息")
                        }, 1000)
                    })
                }
        
      • Vue组件methods中定义调用action的方法

          updateXXX() {
                        this.$store
                            .dispatch('updateXXX', '我是一条msg')
                            .then(res=>{
                                console.log('即将打印action的回调信息');
                                console.log(res)
                            });
                    }
        
      • 总结 action中的updateXXX返回的是一个Promise对象,所以调用方使用then去接收回调信息.

    4.5 module

    • 使用示例

      • 声明一模块a

        // 定义一个模块a
        const a = {
            state: {
                name: 'kobe'
            },
            mutations: {},
            actions: {},
            getters: {}
        }
        
      • 将模块a挂到Vuex.Store的module中

            modules: {
                a
            }
        
      • Vue组件中如何调用a模块中的name属性呢

          <h2>模块a中的name : {{$store.state.a.name}}</h2>
        
    • 示例2: 如何操作模块a中的mutations方法

      • 先在module a 的mutations中定义一个updateName方法

        // 定义一个模块a
        const a = {
            state: {
                name: 'kobe'
            },
            mutations: {
                // 这个state是模块a的state,并非全局的state
                updateName(state, payload) {
                    state.name = payload;
                }
            },
            actions: {},
            getters: {}
        }
        
      • 在Vue组件中的methods中定义一个updateName方法,操作mutations中的updateName方法

         updateName() {
                        this.$store.commit('updateName', '小明')
                    }
        
      • 结论: 跟操作全局的mutations方法一样的.

    • 示例3, 如何操作模块a中的getters方法

      • 先在模块a定义一个getters方法 say

            getters: {
                say(state) {
                   return  "i like " + state.name
                }
            }
        
      • Vue组件使用say方法

            <h2>{{$store.getters.say}}</h2>
        
      • 结论: 跟操作全局的getters方法一样.

    • 示例4, 操作全局的state

      • getters方法可以有3个入参:
        • 第1个: 本模块的state
        • 第2个: 本模块的getters
        • 第3个: 全局的state
          getters: {
              say(state) {
                 return  "i like " + state.name
              },
              // state : 本模块的state, getters: 本模块的getters
              say2(state, getters) {
                  return getters.say + ' en, but --------'
              },
              // 全局的state
              say3(state, getters, rootState) {
                  return getters.say2 + rootState.students[0].name
              }
          }
      
    • 示例5, 如何操作模块a中的actions方法

      • 先定义一个actions方法

            mutations: {
                // 这个state是模块a的state,并非全局的state
                updateName(state, payload) {
                    state.name = payload;
                }
            },
            actions: {
                aUpdateName(context,param) {
                    setTimeout(()=>{
                        console.log(context);
                        // 操作本模块mutaions中的updateName方法
                        context.commit('updateName',param)
        
                    },1000)
                }
            },
        
      • Vue组件调用模块a中的actions方法

        asyncUpdateName() {
        	this.$store.dispatch('aUpdateName','jet')
        }
        
      • 结论 跟调用全局actions方法一样

      • 注意 context与全局的context对像不一样, 可以console.log打印, 可知,模块actions中context包含了rootGetters和rootState

    5. 核心概念

    • State , 单一状态树 , 一个项目中只建一个store对象.

    • Getters , 相当于计算属性, 用于获取State中变异的数据.

    • Mutations , 操作state状态 , 同步方法. 如果是异步方法,devtools就会监控失效.

    • Action , 类似于Mulations一样,用来替代Mulations, 进行异步操作

    • Module , 模块. Vuex推荐使用单一state, 但是如果state中的数据太多,也可以按模块进行划分. 而每个模块里面又可以包含state,mutations, actions,getters

      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 的状态
      

    6. 目录结构

    ​ Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:

    1. 应用层级的状态应该集中到单个 store 对象中。
    2. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
    3. 异步逻辑都应该封装到 action 里面。

    只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。

    ├── index.html
    ├── main.js
    ├── api
    │   └── ... # 抽取出API请求
    ├── components
    │   ├── App.vue
    │   └── ...
    └── store
        ├── index.js          # 我们组装模块并导出 store 的地方
        ├── actions.js        # 根级别的 action
        ├── mutations.js      # 根级别的 mutation
        └── modules
            ├── cart.js       # 购物车模块
            └── products.js   # 产品模块
    

    7.表单处理

    • 需求: input框是store的state获取数据显示 ,如果input框中的值发生改变,更新state中的值.

    • 解决方案: 使用计算属性

      <input v-model="message">
      
      computed: {
        message: {
          get () {
            return this.$store.state.obj.message
          },
          set (value) {  // 这个value就是input框中更新的值.
            this.$store.commit('updateMessage', value)
          }
        }
      }
      
      mutations: {
        updateMessage (state, message) {
          state.obj.message = message
        }
      }
      

      很赞呀!

  • 相关阅读:
    Silverlight 5 系列学习之一
    WPF中数据绑定问题
    细说ASP.NET Forms身份认证 别人写的不过很透彻就转来了以后用时再看
    再学IHanlder 类----------------关于Asp.net与iis原理网上看博客收获写一个验证码用一般处理程序记的好长时间前就写过不过现在再看有点不一样的感觉
    Oracle常用查看表结构命令
    尝试加载 Oracle 客户端库时引发 BadImageFormatException。如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题。(遇到了这个问题网上查了下保存下来)
    TxetBox PasswordChar 模式解除
    屏幕抖动一 下
    oracle 日期问题 网上找到自己查阅时方便
    day5-Dns
  • 原文地址:https://www.cnblogs.com/z-qinfeng/p/13055066.html
Copyright © 2020-2023  润新知