Vue provide与inject到底如何实现双向绑定

今天看Vue源码的过程中发现一个好东西,就是provide与inject

接下来直接上源码

// 初始化组件的时候,初始话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
    }
  }

    不难看出,当你把数据挂载到实体类vm上的时候,其实你也可以反向操作,

分析完源码我们就直接出实践

出实践之前,先来说一个解决什么问题
1. 当你想数据向下流动,而不用数据共享的方式时,且数据和组件嵌套很深时,
2. 为了数据向下流动时解耦,更突显组件的特性

这是父级的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>

为了测试更加真实,我就再加一个孙级的组件

<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>

代码到此结束了,数据向下流动时,父数据会同步子数据,子又可以修改父数据进而进行数据同步

如果你学到了,不妨来个 点赞,收藏,评论,转发,加关注,如果您可以给个赞赏就更好了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

new 前端

请博主喝杯咖啡吧!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值