zoukankan      html  css  js  c++  java
  • vue render函数进阶学习

    上一篇博客我和大家分享了vue render函数的基础使用

    这篇博客我们来简单讲一讲render函数他是怎么实现得

    先来一张官方得图

    在实例初始化得时候,html通过render函数编译生成了一个虚拟dom,视图层会根据虚拟dom生成一个真实dom

    然后如果响应数据发生变化得时候,render函数会重新调用,在更新得时候render函数会返回一个新的虚拟dom , 这个新的虚拟dom并不会直接把之前得替换掉,他会对比新旧dom,然后通过diff算法,把改动最小得结果,拿去更新真实dom,避免发生大量得dom回流和重绘

    render函数触发的时机

    刚才在上边已经说过了,render函数会在响应数据发生改变的时候去被触发,那么就不得不说一说vue的响应式原理

    之前就听说过vue实现的原理是数据劫持,那么他到底是怎么做到的数据劫持这件事呢?

    在vue的源码里边可以看到,vue实例在初始化的时候会把data里边所有的属性添加一个对象进去

    function observe (obj) {
    
     // 迭代对象的所有属性
     // 并使用Object.defineProperty()转换成getter/setters
     Object.keys(obj).forEach(key => {
      let internalValue = obj[key]
    
    // 每个属性分配一个Dep实例
    const dep = new Dep()
    
    Object.defineProperty(obj, key, {
    
      // getter负责注册订阅者
      get () {
        dep.depend()
        return internalValue
      },
    
      // setter负责通知改变
      set (newVal) {
        const changed = internalValue !== newVal
        internalValue = newVal
        
            // 触发后重新计算
            if (changed) {
              dep.notify()
            }
          }
        })
    })
    return obj
    }
    

    在没有更改属性的原有行为的基础上加了一个依赖对象进去,然后通过这个以来对象来发送通知告诉监听watcher 数据发生了变化 ,然后watcher去调用render函数 更新dom

    render函数中的jsx语法

    jsx事js内定义的一套类xml语法,可以解析出js代码,由js引擎解析,在上一篇博客里边我使用的是render函数本身的写法,但是感觉十分的冗余,jsx里边则非常简介,你可以直接返回一个标签的所有属性,感觉和html没什么两样 比如说

      render() {
    const { count, onChange } = this;
    return (
      <div>
        <componment
          style={{ marginTop: "10px" }}
          count={count}
          type="button"
          onChange={onChange}
        />
        <componment
          style={{ marginTop: "10px" }}
          count={count}
          type="button"
          domPropsInnerHTML={`hello ${this.count}.`}
          onChange={onChange}
        />
      </div>
    );
    }
    

    上边的代码可以轻松的渲染出来两个组件
    需要注意的是使用jsx语法的时候需要babel插件,官方插件连接

    createElement

    render函数里边用的createElement方法创建的vnode,createElement方法在vue的源码里边是对_createElement方法的封装,之前是由五个参数的,其中有一个参数是对子节点的犯规,
    我们使用的createElement在经过规范化之后,默认返回的一个vnode类型的数组

    vnode有四个属性

    • tag
    • data
    • context
    • children

    第一个是节点的名称 首先会对tag进行一个判断,如果是字符串的话,会去看是不是html规范的一些检点,如果是的话会创建一个普通的vnode节点

    如果是以恶搞注册过的组件名称,则会createComponent 创建一个组件类型的vnode

    如果都不是则会创建一个位置的标签

    什么是vnode

    所谓虚拟DOM,是一个用于表示真实 DOM 结构和属性的 JavaScript 对象,这个对象用于对比虚拟 DOM 和当前真实 DOM 的差异化,然后进行局部渲染从而实现性能上的优化。

    vnode的渲染

    在render函数生成完毕虚拟dom树之后 就开始了vnode的首次渲染,vue里边调用的是_update方法

     // src/core/instance/lifecycle.js
    Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
    const vm: Component = this
    if (vm._isMounted) {
      callHook(vm, 'beforeUpdate')
    }
    const prevEl = vm.$el
    const prevVnode = vm._vnode
    const prevActiveInstance = activeInstance
    activeInstance = vm
    vm._vnode = vnode
    
    if (!prevVnode) {
      // 初始化渲染
      vm.$el = vm.__patch__(
        vm.$el, vnode, hydrating, false /* removeOnly */,
        vm.$options._parentElm,
        vm.$options._refElm
      )
      // no need for the ref nodes after initial patch
      // this prevents keeping a detached DOM tree in memory (#5851)
      vm.$options._parentElm = vm.$options._refElm = null
    } else {
      // 更新渲染
      vm.$el = vm.__patch__(prevVnode, vnode)
    }
    activeInstance = prevActiveInstance
    // update __vue__ reference
    if (prevEl) {
      prevEl.__vue__ = null
    }
    if (vm.$el) {
      vm.$el.__vue__ = vm
    }
    // if parent is an HOC, update its $el as well
    if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
      vm.$parent.$el = vm.$el
    }
    // updated hook is called by the scheduler to ensure that children are
    // updated in a parent's updated hook.
    }
    

    可以看出不管如何最终都是调用的__patch__方法
    这个__patch__方法主要有两个作用 第一个是创建真实dom 另外一个是发生变化之后把新老的虚拟dom进行对比然后更新真实dom
    这个方法对应的方法是createPatchFunction() 有兴趣的可以去源码里边搜一下

    结束语

    以上是我对render函数的从响应到渲染还有他的作用的理解 有不对的地方欢迎批评指正

  • 相关阅读:
    201771010101 白玛次仁 《2018面向对象程序设计(Java)》第七周学习总结
    201771010101 白玛次仁 《2018面向对象程序设计(Java)课程学习进度条》
    实验六201771010101 白玛次仁
    第七周作业
    第七周上机练习
    第六周作业
    第六周上机练习
    第五周上机作业
    Java第四周作业
    Java第四次作业
  • 原文地址:https://www.cnblogs.com/netUserAdd/p/10923570.html
Copyright © 2011-2022 走看看