谈谈vue的render函数?

更新日期: 2019-03-07阅读: 2.7k标签: 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

VueJS 实际开发中会遇到的问题

VueJS 实际开发中会遇到的问题,主要写一些 官方手册 上没有写,但是实际开发中会遇到的问题,需要一定知识基础。

vue与后台交互ajax数据

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

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

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

Vue响应式开发,深入理解Vue.js响应式原理

深入理解Vue.js响应式原理。Vue教程有关的视频都讲到,我习惯响应式开发,在更早的Angular1时代,我们叫它:数据绑定(Data Binding)。你只需要在Vue实例的 data() 块中定义一些数据,并绑定到HTML

vue中慎用style的scoped属性

在vue组件中,为了使样式私有化(模块化),不对全局造成污染,可以在style标签上添加scoped属性以表示它的只属于当下的模块,这是一个非常好的举措,但是为什么要慎用呢?因为scoped往往会造成我们在修改公共组件(三方库或者项目定制的组件)的样式困难,需要增加额外的工作量

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

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

使用webpack提升vue应用的4种方式

webpack是开发Vue单页应用必不可少的工具,它能管理复杂的构建步骤,并且优化你的应用大小和性能, 使你的开发工作流更加简单。在这篇文章中,我将解释使用webpack提升你的Vue应用的4种方式,包括:单文件组件、优化Vue构建过程、浏览器缓存管理、代码分离

Vue2.0用户权限控制解决方案

Vue-Access-Control是一套基于Vue/Vue-Router/axios 实现的前端用户权限控制解决方案,通过对路由、视图、请求三个层面的控制,使开发者可以实现任意颗粒度的用户权限控制。

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

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

Vue2实例详解与生命周期

Vue的实例是Vue框架的入口,其实也就是前端的ViewModel,它包含了页面中的业务逻辑处理、数据模型等,当然它也有自己的一系列的生命周期的事件钩子,辅助我们进行对整个Vue实例生成、编译、挂着、销毁等过程进行js控制。

点击更多...

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