vue原理之vuex

1、原理

(1)Vuex本质是一个对象
(2)Vuex对象有两个属性,一个是install方法,一个是Store这个类
install方法的作用是将store这个实例挂载到所有的组件上,注意是同一个store实例。
(3)Store这个类拥有commit,dispatch这些方法,
(4)Store类里将用户传入的state包装成data,作为new Vue的参数,从而实现了state 值的响应式。
【引用】:https://zhuanlan.zhihu.com/p/166087818

总结:
(1)Vuex的双向绑定通过调用 new Vue实现,
(2)通过 Vue.mixin 注入到Vue组件的生命周期中,在所有组件的beforeCreate 生命周期注入了设置 this.$store,值就是使用Vuex时所创建的Vuex实例,

2、相关知识

1、方法的简写

var obj = {
  foo: function() {
    /* code */
  },
  bar: function() {
    /* code */
  }
};

被简写成

var obj = {
  foo() {
    /* code */
  },
  bar() {
    /* code */
  }
};

2、关于类里面的方法的问题

类的注意事项
(1)函数声明和类声明之间的一个重要区别在于,函数声明会提升,类声明不会。你首先需要声明你的类,然后再访问它
(2)constructor方法是一个特殊的方法,这种方法用于创建和初始化一个由class创建的对象。一个类只能拥有一个名为 “constructor”的特殊方法
(3)static 关键字用来定义一个类的一个静态方法。调用静态方法不需要实例化 该类,但不能通过一个类实例调用静态方法,使用类名**XX.**调用

(1)在类找那个定义的方法会出现在类的原型
(2)当调用静态或原型方法时没有指定 this 的值,那么方法内的 this 值将被置为 undefined

class Animal {
  //原型方法
  speak() {
    return this;
  }
  //不可以这样定义! 会报错!
  //speak2:function() {
  //   return this;
  // }
  //静态方法
  static eat() {
    return this;
  }
}

let obj = new Animal();
obj.speak(); // Animal {}
let speak = obj.speak;
speak(); // undefined

Animal.eat() // class Animal
let eat = Animal.eat;
eat(); // undefined
提案中:公有实例字段和公共实例方法

公有实例字段
公有实例字段存在于类的每一个实例中。通过声明一个公有字段,我们可以确保该字段一直存在

class ClassWithInstanceField {
  instanceField = 'instance field';
}

const instance = new ClassWithInstanceField();
console.log(instance.instanceField);

公共实例方法
公共实例方法是可以在类的实例中使用的。

class ClassWithPublicInstanceMethod {
  publicMethod() {
    return 'hello world';
  }
}

const instance = new ClassWithPublicInstanceMethod();
console.log(instance.publicMethod());
实验的结果
class A {
  a = 1;
  // 原型方法
  speak() {
    console.log(this.a);
  }
  // 静态方法
  static cry() {
    console.log("cry", this.a);
  }
  eat = function () {
    console.log(this);
  };
  sleep = () => {
    console.log(this);
  };
}

let a = new A();
let a2 = new A();
console.log("A", A);
console.log("a", a);
console.log("a", a2);
A.cry();
a.cry();

在这里插入图片描述

3、关于解构赋值的一些问题

解构对象时会查找原型链(如果属性不在对象自身,将从原型链中查找)

// 声明对象 和 自身 self 属性
var obj = {self: '123'};
// 在原型链中定义一个属性 prot
obj.__proto__.prot = '456';
// test
const {self, prot} = obj;
// self "123"
// prot "456"(访问到了原型链)

3、实现vuex

准备

src\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')

src\views\Home.vue

<template>
  <div class="home">
    <div>这里是:{{ name }}</div>
    <div>时间是{{ time }}</div>
    <div>我的年纪是 {{ age }}</div>
    <div>我的积分是:{{score}}</div>
    <div>{{ allScore }}</div>
    <button @click="addScore">点击积分+1</button>
    <button @click="reduceScore">点击积分-1</button>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from "@/components/HelloWorld.vue";

export default {
  name: "Home",
  components: {
    HelloWorld,
  },
  mounted() {
    // setInterval(() => {
    //   //函数体
    //   this.$store.state.age++;
    // }, 3000);
  },
  computed: {
    name() {
      return this.$store.state.name;
    },
    age() {
      return this.$store.state.age;
    },
    score() {
      return this.$store.state.score;
    },
    time() {
      return this.$store.state.time;
    },
    allScore() {
      return this.$store.getters.allScore;
    },
  },
  methods:{
    addScore(){
      this.$store.commit("addScore",1)
    },
    reduceScore(){
      this.$store.dispatch("reduceScore",1)
    }
  }
};
</script>

核心

vuex.js

let Vue;

//优化封装
// 取出配置的方法名 和 方法
//obj  配置对象,cb回调
const ForEachFn = (obj, cb) => {
  Object.keys(obj).forEach((key) => {
    //key是方法名,obj[key]是方法
    cb(key, obj[key]);
  });
};

class Store {
  // 构造函数,在new的时候执行的
  // 创建类的实例
  constructor(options = {}) {
    // this.state = options.state;
    // state的数据响应式
    // 同时处理了get set操作以及更新
    this.s = new Vue({
      data() {
        return { state: options.state };
      },
    });

    let getters = options.getters;
    this.getters = {};
    /* 
            this.getter 代理对 options.getters的操作
            getters是一个对象
        */
    // Object.keys(getters).forEach((getterName) => {
    //   // 通过循环,拿出键值,绑定get劫持对象的所有属性
    //   Object.defineProperty(this.getters, getterName, {
    //     get: () => {
    //       return getters[getterName](this.state);
    //     },
    //   });
    // });

    ForEachFn(getters, (getterName, getter) => {
      Object.defineProperty(this.getters, getterName, {
        get: () => {
          return getter(this.state);
        },
      });
    });

    let mutations = options.mutations;
    this.mutations = {};
    // Object.keys(mutations).forEach((mutationName) => {
    //   //在原方法的基础上 改造
    //   this.mutations[mutationName] = (payload) => {
    //     // 传入了响应式的 this.state
    //     mutations[mutationName](this.state, payload);
    //   };
    // });

    ForEachFn(mutations, (mutationName, mutation) => {
      // 原来方法的基础上传入 state
      this.mutations[mutationName] = (payload) => {
        mutation(this.state, payload);
      };
    });

    let actions = options.actions;
    this.actions = {};
    ForEachFn(actions, (actionName, action) => {
      // 原来方法的基础上传入 this
      this.actions[actionName] = (payload) => {
        action(this, payload);
      };
    });
  }

  commit = (mutationName, payload) => {
    this.mutations[mutationName](payload);
  };

  dispatch = (actionName, payload) => {
    this.actions[actionName](payload);
  };

  get state() {
    return this.s.state;
  }
}

const install = function (_Vue) {
  // _Vue  Vue的构造函数
  Vue = _Vue;
  Vue.mixin({
    // 混入的生命周期 会在组件的生命周期函数执行之前执行
    beforeCreate() {
      // new  Vue的时候一次
      // 渲染APP的时候走一次
      if (this.$options && this.$options.store) {
        // 根实例
        this.$store = this.$options.store;
      } else {
        // 子实例,从父实例上取得
        this.$store = this.$parent && this.$parent.$store;
      }
    },
  });
};

export default {
  install, //提供注册的方法 Vue.use的时候调用
  Store,
};

store\index.js

import Vue from "vue";
// import Vuex from 'vuex'
import Vuex from "../vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    name: "自己的vuex",
    time: "2022-07-26",
    age: 1,
    score:20
  },
  mutations: {
    addScore(state, val) {
      state.score += val;
    },
    reduceScore(state, val){
      state.score -= val;
    }
  },
  actions: {
    reduceScore({commit},val){  
      setTimeout(()=>{
        commit("reduceScore",val)
      },1000)
    }
  },
  getters: {
    allScore(state) {
      return `我的积分x3倍是${state.score * 3}`;
    },
  },
  modules: {},
});

优化的方法:

是指上是从每个对象里面取出来所有key,再对这个key使用指定的回调,会叫的参数是key (方法名)和对象的value(方法)

const ForEachFn = (obj, cb) => {
  Object.keys(obj).forEach((key) => {
    //key是方法名,obj[key]是方法
    cb(key, obj[key]);
  });
};

原始的mutations和getters

    let getters = options.getters;
    this.getters = {};
    //this.getter 代理对 options.getters的操作
    //getters是一个对象
    Object.keys(getters).forEach((getterName) => {
      // 通过循环,拿出键值,绑定get劫持对象的所有属性
      Object.defineProperty(this.getters, getterName, {
        get: () => {
          return getters[getterName](this.state);
        },
      });
    });

    let mutations = options.mutations;
    this.mutations = {};
    Object.keys(mutations).forEach((mutationName) => {
      //在原方法的基础上 改造
      this.mutations[mutationName] = (payload) => {
        // 传入了响应式的 this.state
        mutations[mutationName](this.state, payload);
      };
    });

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue中使用Vuex进行状态管理是非常常见的,它可以帮助我们更好地组织和管理应用程序的状态。下面是一个简单的例子,演示如何在Vue中使用Vuex进行传值。 1. 安装Vuex 首先,我们需要安装Vuex。可以使用npm或yarn来安装: ``` npm install vuex --save ``` 或者 ``` yarn add vuex ``` 2. 创建store 在Vue中使用Vuex需要先创建一个store。在store中,我们可以定义和管理应用程序的所有状态。 ``` import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment(state) { state.count++ } } }); export default store; ``` 在这个例子中,我们定义了一个名为“count”的状态和一个名为“increment”的mutation,当我们调用“increment”mutation时,它会增加“count”状态的值。 3. 在Vue组件中使用store 现在我们已经创建了一个store,接下来让我们在Vue组件中使用它。我们需要使用Vuex提供的“mapState”和“mapMutations”辅助函数来访问store中的状态和mutations。 ``` <template> <div> <h1>{{ count }}</h1> <button @click="increment">Increment</button> </div> </template> <script> import { mapState, mapMutations } from 'vuex'; export default { computed: { ...mapState(['count']) }, methods: { ...mapMutations(['increment']) } } </script> ``` 在这个例子中,我们使用了“mapState”辅助函数来将“count”状态映射到组件的计算属性中,并使用“mapMutations”辅助函数将“increment”mutation映射到组件的方法中。这样,在组件中就可以直接使用“count”状态和“increment”mutation了。 以上就是使用Vuex进行状态管理的基本过程。在实际开发中,我们通常需要定义更多的状态和mutations,并使用actions和getters等高级特性来管理更复杂的状态。但基本的使用方法和原理都是相似的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值