面试官对我说,你怎么把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

<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

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

<script>
</script>

<style scoped>
</style>

在setup函数选项中使用

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

<template>
  <div class="home">
    <h2>home Page</h2>
  </div>
</template>

<script setup> 
</script>

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

App.vue

<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

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

  • 16
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值