谈谈vue的render函数?

更新日期: 2019-03-07 阅读: 3.2k 标签: vue

使用vue 这么长时间,对vue 对源码了解还是不多,作为一个不甘平庸的前端小白,决定奋起,那么今天我们就来谈谈vue 的render 函数
打开源码,我发现render 函数返回一个VNode; 可是我们并未在模版中写render 呀,这又是一个什么样的过程呢?
当我们创建一个Vue 实例的时候,我们会把template 编译生成render 函数;render 函数返回一个VNode; vue/src/core/instance/render.js

// 返回一个VNode;方法是实例的一个私有方法,它用来把实例渲染成一个虚拟 Node。
  Vue.prototype._render = function (): VNode {
    const vm: Component = this
    //拿到render 函数,可以是用户自己写,也可以通过编译生成;
    const { render, _parentVnode } = vm.$options

    if (_parentVnode) {
      vm.$scopedSlots = normalizeScopedSlots(
        _parentVnode.data.scopedSlots,
        vm.$slots,
        vm.$scopedSlots
      )
    }

    // set parent vnode. this allows render functions to have access
    // to the data on the placeholder node.
    vm.$vnode = _parentVnode
    // render self
    let vnode
    try {
      // There's no need to maintain a stack becaues all render fns are called
      // separately from one another. Nested component's render fns are called
      // when parent component is patched.
      //不需要维护堆栈,因为所有render 函数都是单独调用的。当修补父组件时,将调用嵌套组件的呈现FN
      currentRenderingInstance = vm
      // 第一个参数是当前上下文,_renderProxy 是在initProxy 中定义的,第二个是
      //vm.renderProxy 在生产环境下就是vm,在开发环境可能是一个proxy 对象;vm.$createElement 在initRender 函数中有定义;
      vnode = render.call(vm._renderProxy, vm.$createElement)
    } catch (e) {
      handleError(e, vm, `render`)
      // return error render result,
      // or previous vnode to prevent render error causing blank component
      /* istanbul ignore else */
      if (process.env.NODE_ENV !== 'production' && vm.$options.renderError) {
        try {
          vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)
        } catch (e) {
          handleError(e, vm, `renderError`)
          vnode = vm._vnode
        }
      } else {
        vnode = vm._vnode
      }
    } finally {
      currentRenderingInstance = null
    }
    // if the returned array contains only a single node, allow it
    if (Array.isArray(vnode) && vnode.length === 1) {
      vnode = vnode[0]
    }
    // return empty vnode in case the render function errored out
    // 如果渲染函数出错,则返回一个空的VNode;

    // 如果vnode 不是VNode 的一个实例;
    if (!(vnode instanceof VNode)) {
      // vnode 是一个array 说为vnode 是多个根节点;VNode 虚拟dom;
      if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) {
        // 从render 函数中返回多个根节点,应该返回单个的根节点;
        warn(
          'Multiple root nodes returned from render function. Render function ' +
          'should return a single root node.',
          vm
        )
      }
      vnode = createEmptyVNode()
    }
    // set parent
    vnode.parent = _parentVnode
    return vnode
  }

那么我们手写render,跟使用编译的有何区别?
编译生成render 函数
index.html'

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>vue-analysis</title>
  </head>
  <body>
    <div id="app">
      {{message}} 
    </div>
    <!-- built files will be auto injected -->
  </body>
</html>

main.js'

import Vue from 'vue'

/* eslint-disable no-new */
new Vue({
  el: '#app',
  data() {
    return {
      message: 'hello vue'
    }
    
  }
  
})

手写render 函数
index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>vue-analysis</title>
  </head>
  <body>
    <div id="app">
    </div>
    <!-- built files will be auto injected -->
  </body>
</html>

main.js

import Vue from 'vue'

/* eslint-disable no-new */
new Vue({
  el: '#app',
  render(createElememt) {
    return createElememt('div',{
      attrs: {
        id: "#app1"
      }
    }, this.message)
  },
  data() {
    return {
      message: 'hello vue'
    }
    
  }
  
})


总结:

// 与直接在html中写不一样,她没有从插值变换过来的过程,之前我们是在html 中定义了插值,她在不执行的时候,先把html 的空文件渲染出来,然后在new Vue 之后,执行mounted 方法再把插值从message 中替换成真实的数据

// 我们通过render 函数,直接手写render,我们不用在页面上显示那个插值,而是通过render函数,当它执行完毕以后,会把我们的message 替换上去,这样体验会更好一些;这里我们手写了render函数,我们就没有把template 转换成render函数这一步了;

//注意,我们挂载的元素会替换掉我们的根节点,这也是我们为什么不能用body 作为挂载点的原因,会把body 替换掉;


本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/2724

相关推荐

基于vue移动端UI框架有哪些?vue移动端UI框架总汇

vue现在使用的人越来越多了,这篇文章主要整理一些比较优秀的移动端ui框架,推荐给大家,例如:mint UI、vux、vonic、vant、cube-ui、Muse-ui、Vue-Carbon、YDUI等

vue watch监听对象的使用_实现首次不触发、深度监听

vue中的watch是一个对象,所以一定要当成对象来用,它有键-值组成,其中键就是你要监控的那个数据。这篇文章介绍:vue如何实现首次不触发watch,vue如何实现数据的深度监听?

组件化的概念/特性/优点,Vue组件的使用

Web 中的组件其实就是页面组成的一部分,具有高内聚性,低耦合度,互冲突等特点,有利于提高开发效率,方便重复使用,简化调试步骤等。vue 中的组件是一个自定义标签形式,扩展原生的html元素,封装可重用的代码。

vue扩展——使用vue插件添加全局方法属性

在使用vue构建一些大型项目的时候,会发现许多组件会共用到一些函数或常量,我们需要把它提取出来,每次需要的时候调用一次就可以了,避免每个组件都重新写再一篇的麻烦。

Vue的href动态拼接绑定

:href前面要加“:”或者v-bind: 字符串要用单引号包住 加上了冒号是为了动态绑定数据,等号后面可以写变量。 如果不使用冒号,等号后面就可以写字符串等原始类型数据。这是就无法进行动态绑定数据了

vue引用js文件的多种方式

vue引用js文件的多种方式,这里以为引入jquery为例。js引入文件方式包括: vue-cli webpack全局引入jquery、vue组件引用外部js的方法、单vue页面引用内部js方法

Vue的理解:Vue.js新手入门指南

从一个从未接触过除HTML+CSS+JavaScript+JQuery以外的前端技术的人到现在可以独立使用Vue.js以及各种附属的UI库来开发项目,我总结了一些知识和经验想与大家分享。

vue与后台交互ajax数据

Vue.js是一套构建用户界面的渐进式的前端框架。 vueJS与后台交互数据的方法我所了解的有以下几种

Vue.js最佳实践:五招让你成为Vue.js大师

本文面向对象是有一定Vue.js编程经验的开发者。如果有人需要Vue.js入门系列的文章可以在评论区告诉我,有空就给你们写。对大部分人来说,掌握Vue.js基本的几个API后就已经能够正常地开发前端网站

Vuejs讲解之:响应式、过渡效果、过渡状态

Vue是一套构建用户界面的JS渐进式框架。 Vue 只关注视图层, 采用自底向上增量开发的设计。讲解js高级之响应式、过渡效果、过渡状态。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!