How Vue provide and inject realize two-way binding

In the process of looking at the Vue source code today, I found a good thing, that is, provide and inject

Next go directly to the source code

// 初始化组件的时候,初始话provide属性的方法
function initProvide (vm) {
    var provide = vm.$options.provide;
    if (provide) {
      vm._provided = typeof provide === 'function' // 判断如果传入的方法是provide是函数,执行函数获取到返回的对象,否则直接返回
        ? provide.call(vm)
        : provide;
    }
  }
// vue中处理inject  属性
  function initInjections (vm) {
    var result = resolveInject(vm.$options.inject, vm); // 见下一个函数
    if (result) {
      toggleObserving(false); // 关闭响应式数据定义开关,保证在调用 defineReactive$$1 的时候不对数据进行响应式绑定
      Object.keys(result).forEach(function (key) {
        /* istanbul ignore else */
        {
          defineReactive$$1(vm, key, result[key], function () { // 这里是保证inject属性不能设置成响应式的,否则会发出警告
            warn(
              "Avoid mutating an injected value directly since the changes will be " +
              "overwritten whenever the provided component re-renders. " +
              "injection being mutated: \"" + key + "\"",
              vm
            );
          });
        }
      });
      toggleObserving(true);// 打开响应开关
    }
  }

  function resolveInject (inject, vm) {
    if (inject) {
      // inject is :any because flow is not smart enough to figure out cached
      var result = Object.create(null);
      var keys = hasSymbol
        ? Reflect.ownKeys(inject)
        : Object.keys(inject);

      for (var i = 0; i < keys.length; i++) {
        var key = keys[i];
        // #6574 in case the inject object is observed...
        if (key === '__ob__') { continue }
        var provideKey = inject[key].from;
        var source = vm;
        // 循环向上寻找父节点,直到找到包含有inject key的provide对象
        while (source) {
          if (source._provided && hasOwn(source._provided, provideKey)) {
            result[key] = source._provided[provideKey];
            break
          }
          source = source.$parent;
        }
        if (!source) { // 如果发现父或者父的父没有inject里的key,
          if ('default' in inject[key]) { // 就去找设置的default的值
            var provideDefault = inject[key].default;
            result[key] = typeof provideDefault === 'function'
              ? provideDefault.call(vm)
              : provideDefault;
          } else {
            warn(("Injection \"" + key + "\" not found"), vm);
          }
        }
      }
      return result
    }
  }

    It is not difficult to see that when you mount the data on the entity class vm, you can actually do the reverse operation,

After analyzing the source code, we will go directly to practice

Before going into practice, let’s talk about what problem to solve first.
1. When you want data to flow downward instead of sharing data, and the data and components are deeply nested, 2.
For decoupling when data flows downward, More prominent features of components

This is the parent's main.vue

<template>
  <div>
    第一次构建项目初体验{
   
   {num}} 这是父组件 {
   
   {this.obj.name}}
    <button @click="add">添加</button>
    <every></every>
    <!-- <component :is="compon"></component> -->
  </div>
</template>

<script>
import every from '@/View/textmian/every'
import fors from '@/View/textmian/for'

export default {
  name: "man",
  props: ["num"],
  computed:{
    compon(){
      return this.nums===6?every:fors
    }
  },
  components:{
    every
  },
  provide(){
    return  {
        nul:{
          namess:this.obj//为了触发响应式,所以需要传一个对象,这样父组件更新,子组件也能更新了
        },
        getnul: (ites)=>{this.obj.name=ites.name}//给子组件一个方法,方便子组件修改这个值
    }
  },
  
  data(){
    return {
      obj:{
        name:"1212"
      },
      nums:this.num
    }
  },
  activated(){
    console.log(" min -activated")
  },
  mounted() {
    // this.num = 7;
    // console.log(this.Fibonacci(30))
     console.log(" min -mounted")
  },
  beforeCreate(){
   console.log(" min -beforeCreate")
  },
  created(){
    console.log(" min -created")
  },
  beforeMount(){
    console.log(" min -beforeMount")
  },
  
  beforeUpdate(){
    console.log(" min -beforeUpdate")

  },
  updated(){
    console.log(" min -updated")
  },
  beforeDestroy(){
    console.log(" min -beforeDestroy")
  },
  destroyed(){
     console.log(" min -destroyed")
  },
  methods: {
    add() {
      this.nums += 1;
      this.$emit("update:num", this.nums);
    },
    Fibonacci(n) {
      if (n === 1 || n === 2) {
        return 1;
      }
      let ac1 = 1,
        ac2 = 1;
      for (let i = 2; i < n; i++) {
        [ac1, ac2] = [ac2, ac1 + ac2];
      }
      return ac2;
    }
  }
};
</script>

In order to test more realistically, I will add a grandson component

<template>
  <div>
    这是孙组件{
   
   {this.nul.namess}}
    <button @click="add({name:'王五'})">1111</button>
  </div>
</template>

<script>
export default {
  name: "fors",
  inject: ["getnul", "nul"],
  
  methods: {
    add(el) {
      this.getnul(el)
      // this.nul.namess = el;
    },
  },
};
</script>

This is the end of the code. When the data flows downward, the parent data will synchronize the child data, and the child can modify the parent data to perform data synchronization.

If you have learned it, you might as well come to like , bookmark, comment, forward, add attention, it would be even better if you can give a compliment

Guess you like

Origin blog.csdn.net/qq_36131502/article/details/119179889