面试官对我说,你怎么把Vue的渲染函数理解成这个样子!!!

概述

我们知道,Vue中模板从渲染到展示过程大致是这样一个流程:

模板(template) ---》 AST ---》渲染函数 ---》VNode ---》 Render Tree(虚拟DOM) ---》Layout ---》 Painting ---》Show

也就是说:

  • Vue.js在将模板字符串转换为JavaScript渲染函数 时,会生成 的一个内部数据结构称为AST ,这个AST表示了模板的结构,包括元素、属性、子元素等信息
  • Vue.js的编译器会遍历AST,将其转换为渲染函数。这个过程包括静态提升(hoisting static content)、代码生成等优化步骤
  • 当Vue的渲染函数执行时,它会将元素转换一个个的VNode,然后这些VNode组合在一起就形成了虚拟DOM
  • 然后经过diff算法过后就能更新到真实的DOM上了。

认识渲染函数 h

Vue推荐在绝大数情况下使用模板来创建你的HTML,然后一些特殊的场景,你真的需要JavaScript的完全编程的能力,这个时候你可以使用渲染函数,它比模板更接近编译器。

上面说了,我们之前编写的template 中的HTML 最终也是使用渲染函数生成对应的VNode; 那么,如果你想充分的利用JavaScript的编程能力,我们可以自己来编写createVNode函数,生成对应的VNode

那么我们应该怎么来做呢? --- 使用h()函数:

  • h() 函数是一个用于创建vnode的一个函数
  • 其实更准确的命名应该是createVNode() 函数,但是为了简便,在Vue中将之简化为h() 函数

h函数的使用

h()函数如何使用呢?它接受三个参数,如下图所示:

注意事项:

  • 如果没有props ,那么通常可以将children作为第二个参数传入
  • 如果会产生歧义 ,可以将null作为第二个参数传入 ,将children作为第三个参数传入

h函数可以在两个地方使用:

  • render函数选项中
  • setup 函数选项中(setup本身需要是一个函数类型,函数再返回h函数创建的VNode

也就是说,我们现在要做什么工作呢?再啰嗦一遍,我们上面说了,我们编写的template最终会被渲染函数转换为VNode,而现在呢我们想充分利用JS的能力,所以我们不使用template了,自己来编写html内容,这样没有中间商赚差价,渲染函数一步到位我们编写的内容转换为VNode。

文字描述可能还是有些抽象,接下来我们一起来看几个例子,加深一下理解吧!

在render函数选项中使用

example1.vue

javascript 复制代码
<script>
  import { h } from 'vue'

  export default {
    render() {
      return h("div", { className: "app" }, [
        h("h2", { className: "title" }, "我是标题"),
        h("p", { className: "content" }, "我是内容, 哈哈哈"),
      ])
    }
  }
</script>

<style scoped>
</style>

上面代码的运行结果和下面代码的运行结果在Vue中是一样的 example2.vue

javascript 复制代码
<template>
  <div class="app">
    <h2 class="title">我是标题</h2>
    <p class="content">我是内容, 哈哈哈</p>
  </div>
</template>

<script>
</script>

<style scoped>
</style>

在setup函数选项中使用

再来一个稍微复杂点的例子: 实现计数器功能 + 复用别的组件 Home.vue

javascript 复制代码
<template>
  <div class="home">
    <h2>home Page</h2>
  </div>
</template>

<script setup> 
</script>

<style lang="less" scoped> 
</style>

App.vue

javascript 复制代码
<script>
  import { h } from 'vue'
  import Home from "./Home.vue"

  export default {
    data() {
      return {
        counter: 0
      }
    },

    render() {
      return h("div", { className: "app" }, [
        h("h2", null, `当前计数: ${this.counter}`),
        h("button", { onClick: this.increment }, "+1"),
        h("button", { onClick: this.decrement }, "-1"),
        h(Home)
      ])
    },
    methods: {
      increment() {
        this.counter++
      },
      decrement() {
        this.counter--
      }
    }
  }
</script>

<style scoped>
</style>

那么在Vue3的 <script setup> 语法糖中又该如何使用呢? 有 亿 点点奇怪,先看代码吧 App.vue

javascript 复制代码
<template>
  <render/>
  <h2 class="">内容</h2>
</template>

<script setup>
import { ref, h } from 'vue';
import Home from './Home.vue'

const counter = ref(0)

const increment = () => {
  counter.value++
}
const decrement = () => {
  counter.value--
}

const render = () => h("div", { className: "app" }, [
  h("h2", null, `当前计数: ${counter.value}`),
  h("button", { onClick: increment }, "+1"),
  h("button", { onClick: decrement }, "-1"),
  h(Home)
])

</script>

<style scoped>
</style>

也就是说,在 <script setup> 语法糖中我们不能直接返回渲染函数,否则会报错(大家自己尝试一下就知道了)。我们应该将渲染函数当成箭头函数的返回值返回,并且还要在template中使用才行。。。嗯??? 不知道大家到这里有没有一种感觉,这不是脱裤子放 P 吗!绕一圈又回去了

我们本来在template中的写法多么简单,这还整的越来越复杂了,如果我们想完全的利用JS的能力,为什么要这样写呢?为什么不使用JSX呢! 哈哈是的呢,我们平常确定是不会这样写的,但是,这不是没办法吗,面试官想让我们这样哈哈哈。但是 u1s1,理解h不是也使得我们提升了一些吗

至于JSX,相信写过React的同学一定不陌生,和JS不能说是十分相似,只能说是一模一样(还是不一样的哈,JSX比JS的范围要大的)。Vue中也可以使用 JSX,不过我们一般也不会使用。毕竟一个框架有一个框架的特点吗。不过看Vue官方的动向似乎有点向JSX倾斜,我们拭目以待吧~

总结

本篇文章我们讲述了Vue文件从编写到显示到页面上的整个过程,并且详细解说了渲染函数的执行流程,相信大家看过以后对整个流程一定会有更加深刻的了解。我们下次再见吧~

相关推荐
程序员黄同学9 分钟前
Python 中如何创建多行字符串?
前端·python
anyup_前端梦工厂33 分钟前
uni-app 认识条件编译,了解多端部署
前端·vue.js·uni-app
Fetters041 小时前
一篇快速上手 Axios,一个基于 Promise 的网络请求库(涉及原理实现)
前端·ajax·axios·promise
蒟蒻的贤1 小时前
vue11.22
开发语言·前端·javascript
爱上语文1 小时前
Axios案例练习
前端·javascript·css·html
河畔一角1 小时前
升级react@18.3.1后,把我坑惨了
前端·react.js·低代码
天天进步20151 小时前
Vue 3 + Vite:构建闪电般快速的开发环境
前端·javascript·vue.js
Dragon Wu1 小时前
前端框架 Redux tool RTK 总结
前端·javascript·前端框架
yqcoder2 小时前
reactflow 中 useStoreApi 模块作用
前端·javascript
williamdsy2 小时前
【vue】关于异步函数使用不当导致的template内容完全无法渲染的问题
前端·javascript·vue.js