资讯专栏INFORMATION COLUMN

【Vue原理】Props - 源码版

light / 2403人阅读

写文章不容易,点个赞呗兄弟
专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧
研究基于 Vue版本 【2.5.17】

如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧

【Vue原理】Props - 源码版

今天记录 Props 源码流程,哎,这东西,就算是研究过了,也真是会随着时间慢慢忘记的。

幸好我做了详细的文章,忘记了什么的,回忆起来必然是很快的。

好的,回到正题,Props

请你在读这篇之前,先去看看我的白话版

【Vue原理】Props - 白话版

在上面这篇文章中,也已经清楚地解决了一个问题

父组件 如何 把数据 当做 props 传给子组件

所以今天,我们只需记录 Props 的处理流程源码即可

初始化

在创建Vue实例的过程中,会调用 initState 处理options,比如 props,computed,watch 等

只要你 new Vue 创建实例之后,很快就会处理options

function Vue(){
    ... 其他处理
    initState(this)

    ...解析模板,生成DOM 插入页面

}

function initState(vm) {    

    var opts = vm.$options;    

    if (opts.props) {

        initProps(vm, opts.props);
    }

    ... 处理 computed,watch,methods 等其他options

}
initProps

你看到处理 Props ,主要用到了一个方法 initProps,他就是本场的焦点了,让我们来采访下源码本码

function initProps(vm, propsOpt) {    
   // 这是父组件给子组件传入的 props 的具体值

   var propsData = vm.$options.propsData || {};    

   var props = vm._props = {};    

   for (var key in propsOpt){        

       // 给 props 的 key 设置 响应式

       defineReactive(props, key,  propsData[key]);        

       if (! (key in vm)) {            

           // 转接访问,访问 vm 属性,转到访问 vm._props 属性
           proxy(vm, "_props", key);
       }
   }
}

上面的代码主要做了三件事

1、遍历 props

2、给 props 设置响应式

3、给 props 设置代理

我们主要讲两件事

1、给 props 设置响应式
defineReactive(props, key,  propsData[key])

defineReactive 在这里就不给太多源码了,你只需要记住他就是给 props 设置响应式的

function defineReactive(obj, key) {    

    Object.defineProperty(obj, key, {  

        get() { ...依赖收集 },
        set(newVal) { ....依赖更新 }
    });
}

如果你想了解响应式,就可以看我这篇文章

【Vue原理】响应式原理 - 白话版

Props 设置响应式,也是旨在数据改变时动态更新。

怎么设置响应式吗?看这里

【Vue原理】依赖收集 - 源码版之基本数据类型

【Vue原理】依赖收集 - 源码版之引用数据类型

数据是直接从 父组件上传过来的,没有进行拷贝等处理,原样传过来

怎么传的?也可以看

【Vue原理】Props - 白话版

如果props 是基本类型

在 子组件实例上设置这个 props 属性为响应式,跟 data 本质一样,作用是监听 props 修改

如果 props 是对象

也会在 子组件实例上 设置这个 props 属性为响应式,作用也是监听 props 修改

但是!

【不会递归对象】给对象内所有属性设置响应式,因为该对象【已经在父组件中】完成响应式设置了

也就是说

如果你在 子组件中直接修改 props 对象内的数据,父组件也会跟着修改

在记录的途中,我发现了一个问题,发现没有想象中的那么简单,所以现在郑重记录

当 父组件数据 改变,子组件怎么更新?

分类型的,说得比较详细,可能有点绕?

1、 如果是基本类型,是这个流程

父组件数据改变,只会把新的数据传给子组件

子组件拿到新数据,就会直接替换到原来的 props

替换就是直接等哈,看下源码,重要语句标红

updateChildComponent 是子组件内部更新时会调用到的一个函数,这是其中更新 props 的一个片段

function updateChildComponent(

    vm, propsData

) {    

    if (propsData && vm.$options.props) {        

      // 保存 props 的地方,用于访问转接,具体看文章下面

      var props = vm._props;        

      // 所有子组件上设置的 props 的 key

      var propKeys = vm.$options._propKeys || [];        

      for (var i = 0; i < propKeys.length; i++) {            

        var key = propKeys[i];

        props[key] = propsData[key]
      }
     vm.$options.propsData = propsData;
   }
}

而 props 在子组件中也是响应式的,【直接 等号 替换】导致触发 set,set 再通知 子组件完成更新

数据是 基本类型,然后设置定时器修改数据

watcher1 是父组件,watcher2 是子组件

父组件内的 data num 通知 watcher1 更新
子组件内的 props child_num 通知 watcher2 更新

2、如果是对象,是这个流程

条件

父组件传 对象 给 子组件,并且父子组件 页面都使用到了这个数据

结果

那么这个对象,会收集到 父子组件的 watcher

所以

当 对象内部被修改的时候,会通知到 父和子 更新。

例子

父组件设置 obj 对象,并传给子组件


定时修改父组件数据 obj.name ,可以看到是 obj.name 通知 父子更新

当然,如果对象被整个替换了,而不是修改内部,那么跟 基本类型一样

区别是什么?

1、基本类型是,子组件内部 props 通知 子组件更新的

2、引用类型是,父组件的数据 data 通知 子组件更新的

2、给 props 设置代理

在白话版中,我已经说得很清楚了, Props 有个移花接木的暗箱操作,就是访问转移

Data 也是这么做的

[
【Vue原理】代理 Data - 源码版 ]( https://mp.weixin.qq.com/s?__... )

你在项目中,会使用 http://this.xxx去访问 props,props 已经当成了 实例的属性,所以可以直接访问

但是其实你访问的是 【this._props.xxx】

为什么 Vue 要这么弄,目的就是为了方便开发啊,让我们直接简短了相关代码

而 React,访问 props,还要 this.props.xxxx,写这么长,不嫌麻烦吗?

那么,是怎么设置代理的呢,就是下面这行

proxy(vm, "_props", key);

proxy 是什么也不要急,瓜就在下面,拿凳坐好

function proxy(

    target, sourceKey, key

) {    

  Object.defineProperty(target, key, {

      get() {            

          return this[sourceKey][key]

      },

      set(val) {            

          this[sourceKey][key] = val;

      }
  });
}

这段代码做了2 个事

1、使用 props 在 vm 上占位,使得可以通过 http://vm.xxx 的形式访问到 props

2、设置 [Object.defineProperty] 的 get 和 set ,间接获取和赋值 vm._props

所有访问赋值 props,转接到 vm._props 上,直观如下图


上个实例,方便大家看

说完收工

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105379.html

相关文章

  • Vue原理Props - 白话

    摘要:写文章不容易,点个赞呗兄弟专注源码分享,文章分为白话版和源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于版本如果你觉得排版难看,请点击下面链接或者拉到下面关注公众号也可以吧如果你觉得排版难看,请点击下面公众号 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基...

    Carl 评论0 收藏0
  • Vue原理】Slot - 源码之作用域插槽

    摘要:通过函数参数传递的形式,让插槽的变量,在解析时,先访问函数变量。那么这两个有什么关系呢外壳节点保存着所有父组件里给这个子组件绑定的数据,比如,插槽等。 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请点击 下面链接 或者 拉到 下面...

    tolerious 评论0 收藏0
  • Vue原理】NextTick - 源码 之 服务Vue

    写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧 【Vue原理】NextTick - 源码版 之 服务Vue 初次看的兄弟可以先看 【Vue原理】NextTick - 白话版 简单了解下...

    Acceml 评论0 收藏0
  • Vue原理】Mixins - 源码

    写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧 【Vue原理】Mixins - 源码版 今天探索的是 mixins 的源码,mixins 根据不同的选项类型会做不同的处理 篇幅会有些长,...

    gotham 评论0 收藏0
  • Vue原理】VModel - 源码 之 表单元素绑定流程

    摘要:首先,兄弟,容我先说几句涉及源码很多,篇幅很长,我都已经分了上下三篇了,依然这么长,但是其实内容都差不多一样,但是我还是毫无保留地给你了。 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也...

    sarva 评论0 收藏0

发表评论

0条评论

light

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<