vuex

982 阅读3分钟

单词:

dispatch 派遣

Vuex 和单纯的全局对象有以下两点不同:

  • Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

  • 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

实践:先做一个点击加减的计数器

以前的实现方法:

<template>
  <div>
    <h2>首页</h2>

    <div class="box">
      <h1>number:{{count}}</h1>
      <button @click="increase">+</button>
      <button @click="decrease">-</button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    };
  },
  methods: {
    increase() {
      this.count++;
    },
    decrease() {
      this.count--;
    }
  }
};
</script>

<style  scoped>
.box {
  height: 500px;
  width: 500px;
  background-color: #ccc;
  margin: 0 auto;
}
</style>

vuex 实现:

注意 this.$store 一般使用在 script  比如数据呈现this不用加{{$store.count}}就行

去main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import Vuex from 'vuex'

Vue.use(Vuex)
//注意 加上Store
var store = new Vuex.Store({
  state:{
    count:1
  }
})

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

     <h2>仓库中的count:{{$store.state.count}}</h2>
     <button @click="addNum">+</button>
     <button @click="subNum">-</button>

watcher“function(){return this.?state}”回调时出错:“错误:[vuex]不要在变异处理程序之外更改vuex存储状态。”

可以做一些判断

backend 是后端的意思 frontend 是前端的意思

另外一种导入:

安装:npm install vuex --save

scr/store/index.js

import Vuex from 'vuex'
import Vue from 'vue'

// 1.安装
Vue.use(Vuex)
//2.创建对象
const store = new Vuex.Store({
    state:{
        count:1000
    },
    mutations:{
        //方法:
        addEvent(state){//state  就是上面的state对象  默认会传过来   
            // this.state.count++
            state.count++
        },
        subEvent(state){
            // this.state.count--
            //不用加this了
            state.count--
        }
    },
    actions:{

    },

    getters:{

    },
    modules:{

    }
    
})


//导出
export default store
// export default Store 注意这个s的大写有点难看清除

然后在main.js中导入

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

vuex.vue组件

<template>
    <div>
        
        <h2>vuex</h2>
        <hr>
        <h2>计算器:{{$store.state.count}}</h2>
        <button @click = "add">+</button>
        <button  @click = "sub">-</button>

    </div>
</template>
<script>
    export default{
        data() {
            return {
                
            }
        },
        methods: {
            add(){
                //提交 东西给store仓库
                this.$store.commit('addEvent')
                // console.log(111)
                // console.log( this.$store.state.count)
            },
            sub(){
                this.$store.commit('subEvent')
                // console.log(222)
            }
        },
    }
</script>

<style>

</style>

单一状态树

getters =>相当于我们的计算属性

什么时候使用计算属性?

比如说一个data中的变量需要经过一些列的操作才展示在页面上

让count平方在呈现在页面上

filter函数的使用

回调函数

filter()接收的回调函数,其实可以有多个参数。通常仅使用第一个参数,表示Array的某个元素。回调函数还可以接收另外两个参数,表示元素的位置和数组本身:

利用filter,可以巧妙地去除Array的重复元素:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // var arr = [0, 1, 2, 3, 4, 5, 1, 4, 0];
        // var arr_filter = arr.filter(function (x) {
        //     return x % 2 == 0;/* 筛选偶数 */
        // })
        // console.log(arr_filter)

        // var arr = ['0', 1, 2, 3, 4, "", 5, 1, 4, '0', ""];
        // var arr_filter = arr.filter(function (x) {
        //     return x;/* 筛选空格 */
        // })
        // console.log(arr_filter)


        // var arr = [1, '', null, undefined, ' ']
        // console.log(arr.filter(v => v))

        // var arr = ['A','B','C','d'];
        // var arr_filter = arr.filter(function(element,index,self){
        //     console.log(element);/* 依次打印'A','B','C','d' */
        //     console.log(index);/* 依次打印0,1,2,3 */
        //     console.log(self);/* 打印数组本身即arr */
        //     return true;
        // })

        var arr_repeat = ['A','B','A','B','B','C','A','D'];
        var arr_filter = arr_repeat.filter(function(element,index,self){
            return self.indexOf(element) == index;
        })
        console.log(arr_filter);//返回['A','B','C','D']
    </script>
</body>

</html>

现在在state中定义了数组对象:

在不同的组件中使用 就要这样:

现在有个需求: 大于年龄20 岁的 20不能写死 是动态传过来的

mutation

需求现在是 点击按钮加5加10

<button @click = "addFive">+5</button>
 <button @click = "addTen">+10</button>

那能不能通过 一个发放代替 这两个两个方法呢? 可以的

  <button @click = "addNum(5)">+5</button>
  <button @click = "addNum(10)">+10</button>
addNum(num){
                this.$store.commit('addNum',num)
            }
mutations:{
   
       addNum(state,num){
           state.count += num
       }
   },

传入的参数 只有一个 我要传对象呢?

 <h2>{{$store.state.students}}</h2>
 <button @click="addStudents">添加学生</button>
 
 
     addStudents(){
                let stu = {name :"chenbo",id:52}
                this.$store.commit('addStu',stu)
            }
   
  // mutation:   
    addStu(state,payload){
            state.students.push(payload)
        }

两种提交风格

一.普通的提交: this.$store.commit('addNum',num) 二.特殊的提交风格:

所以第二个参数 payload 是一个对象了

mutation 的响应规则

方法参数提示怎么实现?

通过set方法实现响应式:

js中删除一个对象中的属性 方法是delete 也是做不了响应式的

提交给仓库的名称 和 仓库mutation触发的方法名字 如果统一就避免了 手打代码的错误

导入方式:

//对象中的方法可以这样写
        ['fangfa'](){
            xxx
        }

这种是官方推荐的形式

mutation的异步操作

没有跟踪到 从而引出 actions

action

修改state 一定是要经过mutation

上面也是错误的 为啥 跳过了commit这一步

外面派发事件给 actions 也是可以携带参数的
需求 :携带参数 并且执行完成后返回值给到前台

success为回调函数 什么是回调函数? 就是一个方法执行完要调用的函数 现在函数作为参数传值 把这个函数传递过去 它会在某一时刻(触发)被执行就会它里面的要呈现的信息返回

里面已经王完成是写在回调函数里面的

携带的参数 和回调的函数写在了一坨

不雅观

现在通过new promise()的方式 还可以从后台携带参数传递给前台 而且返回前台需要的信息 只需要传递携带信息就行

ps:

问题: vue中打印this 输出一个VueComponent 我怎么知道它是哪一个

函数看作一个对象(JavaScript 中的所有函数都 是对象)所以可以这样 then({})

module

模块里面的mutation 在组件中也是正常提交的

之前在actions中的 上下文context可以理解为store 是因为 在组件中store.commit 给到actions 再由actions发起 context.commit提交给mutations

ps:

但是在子模块中注意的是 在他里面做的异步操作 context.commit也只提交到自己模块中的actions中

  • 子模块的context:
  • 跟模块中的context:

好像也没什么区别

项目结构

没有抽离的代码:

//store/index.js
import Vuex from 'vuex'
import Vue from 'vue'
import { ADDTOWNUM, YIBU } from './mutation_type.js'

// 1.安装
Vue.use(Vuex)

//3.创建module对象
const moduleA ={
    state:{
        name:'lumigqing'
    },
    mutations:{
        upMyName(state,payload){
            state.name = payload
        }
    },
    actions:{
        // asyncName(context,payload){
        asyncName(context){//这里的context 可以用对象的结构写法
            console.log(context)
            setTimeout(()=>{
                // 这里的context  自会调用自己模块的mutation  
                //提交 mutation本来就有的方法 
                // context.commit('upMyName',payload)//payload = 大番薯
                context.commit('upMyName','dafanshu')//
            },1000)
        }
    },
    getters:{
        fullName(state){
           return  state.name + '11111111'
        },
        fullName2(state,getters){
           return  getters.fullName + '22222'
        },
        //第三个参数 为根state
        fullName3(state,getters,rootState){
           return  getters.fullName2 + '根'+rootState.count
        }
    },
    modules:{

    }

}
const moduleB ={
    state:{
        
    },
    mutations:{
       
    },
    actions:{

    },
    getters:{

    },
    modules:{

    }

}
const moduleC ={
    state:{
      
    },
    mutations:{
     
    },
    actions:{

    },
    getters:{

    },
    modules:{

    }

}
//2.创建对象
const store = new Vuex.Store({
    state: {
        //用于异步操作
        actionData: 25,
        count: 1000,
        students: [
            { name: 'lulu', id: 12 },
            { name: 'lulu', id: 120 },
            { name: 'yige', id: 35 }
        ],

    },
    mutations: {
        //方法:
        addEvent(state) {//state  就是上面的state对象  默认会传过来   
            // this.state.count++
            state.count++
        },
        subEvent(state) {
            // this.state.count--
            //不用加this了
            state.count--
        },
        // addNum(state,num){
        //     console.log(num);

        //     state.count += num
        // },
        addNum(state, payload) {
            console.log(payload.num);//10
            console.log(payload.age);//30

            state.count += payload.num

        },
        //添加一个对象 在student中
        //注意是 在mutation这里的第二个参数 才叫做负载  payload
        addStu(state, payload) {
            state.students.push(payload)
        },
        updataName(state) {
            state.students[2].name = "love"
        },
        addUserName(state) {
            // state.students[2]['address'] = "天河区"
            // set(参数1 obj/arr 2 key :string|number,value:)
            Vue.set(state.students[2], 'address', '天河区')
        },
        deleteUser(state) {
            // delete state.students[2].name
            //为啥可以这样用?
            Vue.delete(state.students[2], 'name')
        },
        // //对象中的方法可以这样写
        // ['fangfa'](){
        //     xxx
        // }
        [ADDTOWNUM](state) {
            state.count += 2
        },
        [YIBU](state) {
            //不能在这里进行异步操作
            setTimeout(() => {
                state.students[2].id = "123"
            }, 2000)

        },
        // 异步用的方法:
        yibuFun(state) {
            state.actionData = '福利来咯'
        }


    },
    actions: {
        // context上下文  暂时理解为store
        // actionDataFun(context){
        //     setTimeout(()=>{
        //         context.commit('yibuFun')
        //     },2000)
        // }

        // actionDataFun(context,payload){//携带参数
        //     setTimeout(()=>{
        //         context.commit('yibuFun'),
        //         console.log(payload.message),//
        //         payload.success()//
        //     },2000)
        // }

        actionDataFun(context, payload) {//携带参数
            console.log(context)
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    context.commit('yibuFun'),
                        // console.log(payload),  结束不能加逗号
                        console.log(payload)//我是携带的信息
                        // resolve() 里面可以携带参数
                        resolve('这是resolve的传递参数')


                }, 2000)
            })
        }



        // actionDataFun(context){
        //     setTimeout(()=>{
        //         // 错误写法
        //         context.state.actionData = '日了狗了'
        //         
        //     },2000)
        // }
    },

    getters: {

    },
    modules: {
        //把state 划分成不同的模块
        a:moduleA,
        b:moduleB,
        c:moduleC,
        
    }

})


//导出
export default store
// export default Store 注意这个s的大写有点难看清除

组件Vuex:

<template>
    <div>

        <h2>vuex</h2>
        <hr>
        <h2>计算器:{{$store.state.count}}</h2>
        <button @click="add">+</button>
        <button @click="sub">-</button>
        <!-- <button @click = "addFive">+5</button>
        <button @click = "addTen">+10</button> -->
        <button @click="addNum(5)">+5</button>
        <button @click="addNum(10)">+10</button>
        <hr>
        <hr>
        <h2>{{$store.state.students}}</h2>
        <button @click="addStudents">添加学生</button>
        <hr>
        <hr>
        <h2>{{$store.state.students[2]}}</h2>
        <p>点击按钮把‘yige’修改成love</p>
        <button @click="updateName">修改用户信息</button>
        <button @click="addName">添加用户信息</button>
        <button @click="deleteUser">删除用户信息</button>

        <hr>
        <hr>
        <h2>常量方法加2 :{{$store.state.count}}</h2>
        <button @click="addTow">+2</button>

        <hr>
        <hr>
        <h3>mutation的异步操作 是跟踪不到的</h3>
        <h2>{{$store.state.students[2]}}</h2>
        <button @click="editId">修改用户id</button>
        <hr>
        <hr>
        <h3>action 模拟异步操作</h3>
        <h3>action:{{$store.state.actionData}}</h3>
        <button @click=" handlerActionData">修改数字</button>
        <hr>
        <hr>
        <h2>modules 中的模块</h2>
        <h2>我的名字:{{$store.state.a.name}}</h2>
        <button @click = "upMyName">修改名字</button>
        <h3>getters :{{$store.getters.fullName}}</h3>
        <h3>getters :{{$store.getters.fullName2}}</h3>
        <h3>getters :{{$store.getters.fullName3}}</h3>
        <button @click = "asyncName">异步修改名字</button>

    </div>
</template>
<script>
    import { ADDTOWNUM, YIBU } from '../store/mutation_type.js'
    export default {
        data() {
            return {

            }
        },
        methods: {
            add() {
                //提交 东西给store仓库
                this.$store.commit('addEvent')
                // console.log(111)
                // console.log( this.$store.state.count)
            },
            sub() {
                this.$store.commit('subEvent')
                // console.log(222)
            },
            addNum(num) {

                // this.$store.commit('addNum',num)

                // 特殊的提交
                this.$store.commit({
                    type: 'addNum',
                    // num:num
                    num,
                    age: 30
                })
            },
            //发送问候
            addStudents() {
                let stu = { name: "chenbo", id: 52 }
                this.$store.commit('addStu', stu)
            },
            updateName() {
                this.$store.commit('updataName')
            },
            addName() {

                this.$store.commit('addUserName')
            },
            deleteUser() {

                this.$store.commit('deleteUser')
            },
            addTow() {
                this.$store.commit(ADDTOWNUM)
            },
            editId() {
                this.$store.commit(YIBU)
            },
            //异步修改数字
            // handlerActionData (){
            //     this.$store.dispatch('actionDataFun',{
            //         message:'我是携带的信息,由内部执行完后打印',
            //         success:()=>{
            //             console.log('里面已经完成了!!!')
            //         }
            //     })//参数搞一个对象  success为回调函数  什么是回调函数? 就是一个方法执行完要调用的函数  现在函数作为参数传值  把这个函数传递过去 它会在某一时刻(触发)被执行就会它里面的要呈现的信息返回
            // }       
            handlerActionData() {
       
                this.$store.dispatch('actionDataFun', '我是携带的信息').then(
                    res=>{
                    console.log(this)
                    console.log('里面已经完成了!!!成功返回')
                    console.log(res)
                    },
                    // console.log(this),//root vue 
                    // // 解决就是在外层定义一个that
                    // // let that = this,//不能再参数中定义 只能是语句
                    // function (res) {
                    //     // console.log(this)//undefined  ? why? 
                    //     console.log(this)//
                    //     console.log('里面已经完成了!!!成功返回')
                    // }

                )
            },
            upMyName(){
                this.$store.commit('upMyName','lisa')
            },
            asyncName(){
                // this.$store.dispatch('asyncName','大番薯')
                this.$store.dispatch('asyncName')
            }
        },
    }
</script>

<style>

</style>