当前位置: 首页 > news >正文

Vue渲染—深入VNode(h函数、JSX、render函数)

最近要面试,来复习总结一下vue渲染相关的知识。

h 函数

h 函数会返回一个 vnode(虚拟节点)

h 函数底层是基于 createVnode 创建虚拟节点的

  • 优势:跳过了模版的编译
  • 缺点:写起来不方便(可以用 jsx 去代替)

不过对于写一些弹窗之类的,需要挂载到 #app 根节点外面的,用 h 函数会比较方便。

template 编译过程:parser -> ast -> transform -> render

const vnode = h('div', '111')
console.log(vnode)
// {
//     type: "div",
//     props: null,
//     children: "111",
// }

渲染

  1. 普通组件
<template><vnode />
</template><script setup>import { h } from 'vue'const vnode = h('div', '111')
</script>
  1. 动态组件

<component> 可以接收一个 vnode,渲染到页面

<template><component :is="vnode" />
</template><script setup lang="ts">
import { h, createVNode } from 'vue'
const vnode = h('div', '111')

h 函数的写法(参数)

// 写法1
const vnode = h('div', '333')
// 写法2 第一个参数可以传递一个组件
import A from './A.vue'
const vnode = h(A)
// 写法3 第二个参数可以传递多个子节点
const vnode = h('div', [h('span', 'hello'), h('span', 'world')])
// 写法4 第二个参数可以传递props
const vnode = h('div', { style: { color: 'red' } }, '333')
// 写法5 插槽
import { h, createVNode, useSlots } from 'vue'
const slots = useSlots()
const vnode = h('div', slots.default()) // slots.default() 返回一个vnode数组

补充

import A from './A.vue'
console.log(A)

当我们去打印组件的时候,会有一个 render 属性,是一个函数,这个函数会返回一个 vnode,也就是 A.render() 调用后返回的就是 vnode。

关于渲染响应式数据

vnode 会正常渲染,但是响应式数据变了,不会触发 rerender,但是 watch 可以监听到数据变化

因为当前的环境是 setup 的环境,没有被 effect 包裹,所以响应式数据不会响应式

// ⚠️注意:响应式数据不会响应式,因为响应式数据需要effect包裹
let num = ref(0)
const vnode = h('div', num.value)
setTimeout(() => {num.value++
}, 1000)
watchEffect(() => {console.log(num.value)
})

而下面的这种写法,就会触发 rerender(采用函数 () => h('div', num.value)

因为当组件在渲染的时候,会帮我们调用 vnode 函数,调用函数的环境就是一个effect

变成函数可以理解为是一个组件(函数式组件),就不是一个 vnode 了

let num = ref(0)
const vnode = () => h('div', num.value)setTimeout(() => {num.value++
}, 1000)

函数式组件

上面的例子就是一个函数式组件,可以接收props,类型为 FunctionalComponent,返回一个 vnode

<template><Vnode :count="1"><div>hello</div></Vnode>
</template><script setup lang="ts">
import { h, type FunctionalComponent } from 'vue'
const Vnode: FunctionalComponent<{ count: number }> = (props, ctx) => {// ctx.attrs => props => { count: 1 }// ctx.slots => { default: () => [h('div', 'hello')] } // vctx.slots.default():node数组// ctx.emitreturn h('div', [props.count, ctx.slots.default()])
}
</script>

JSX

写过 react 的对 JSX 应该不陌生,这里也不过多赘述

在.vue 文件或.jsx/.tsx 文件中的基础 JSX 用法

import { defineComponent } from 'vue'export default defineComponent({setup() {const greeting = 'Hello, Vue with JSX!'return () => (<div><h1>{greeting}</h1><p>This is rendered using JSX.</p></div>)}
})

defineComponent 是 vue 提供的一个辅助函数,为 ts 提供更好的类型支持。

对于 <script setup> 语法,默认已经是类型推导的,因此通常不需要显式使用 defineComponent

函数式组件写法也可以:

// A.tsx
import type { FunctionalComponent } from "vue"export const Vnode: FunctionalComponent<{ count: number }> = (props, ctx) => {return <div><div>{props.count}</div></div>
}

h 函数的关系

JSX 是一种创建 VNode 的语法糖,最终转化为 h() 调用。

这意味着你可以选择是直接使用 h() 还是使用更直观的 JSX 语法。两者本质上是一样的——都是为了创建 VNode。

render 函数

模板编译后的 render 函数

在 vue 中我们平时使用最多的写法就是template模版,模版的本质就是 render函数的语法糖。

render 函数作为组件的渲染入口,返回的就是虚拟节点(vnode)

  • vue3:

在 vue3 中可以用setup 函数返回一个 render 函数

export default {setup() {return () => h('h1', 'hello world')// return () => <h1>hello world</h1>}
}
  • vue2:
// 示例:render函数返回vnode
export default {render(h) {return h('div', 'hello world')}
}

Vue 包里的 render 函数

import { render } from 'vue'

这个 render 和 模板编译后的 render 函数作用是不一样的。

  • 作用:将虚拟节点渲染到真实 DOM 容器中
  • 参数(vnode, container) - 虚拟节点和容器元素
  • 调用时机:手动控制何时渲染/更新/卸载
  • 用途:手动挂载组件、动态渲染等
import { h, render } from 'vue'const vnode = h('div', { class: 'container' }, 'Hello World')
const container = document.getElementById('app')
// 渲染到页面
render(vnode, container)// 更新渲染(传入新的 vnode)
const newVnode = h('div', { class: 'container updated' }, 'Updated Content')
render(newVnode, container)// 卸载组件(传入 null)
render(null, container)

实际应用场景

  1. 手动挂载应用(类似 createApp)
import { h, render } from 'vue'
import App from './App.vue'const appVNode = h(App)
const container = document.getElementById('app')
render(appVNode, container)

使用 createApp(推荐) createApp(App).mount('#app')

  1. 动态渲染组件
import { h, render } from 'vue'function showMessage(message: string) {const vnode = h('div',{class: 'message',onClick: () => {render(null, container) // 点击关闭}},message)const container = document.createElement('div')document.body.appendChild(container)render(vnode, container)
}

通常开发中使用 createApp().mount() 更方便,底层就是基于 render 实现的。

http://www.dtcms.com/a/441872.html

相关文章:

  • GPT_Data_Processing_Tutorial
  • 华为AC+AP无线网络组网与配置指南
  • 交互动效设计
  • 电子商务网站建设与管理相关文献邢台路桥建设总公司没有网站吗
  • Leetcode 3700. Number of ZigZag Arrays II
  • Turbopack介绍(由Vercel开发的基于Rust的高性能前端构建工具,用于挑战传统构建工具Webpack、vite地位)Next.js推荐构建工具
  • 网站自适应 如何做ui设计可以从事什么工作
  • 【学习记录】宝塔面板 + Docker 快速部署 RustDesk 自建远程控制服务器
  • 【3DGS复现】Autodl服务器复现3DGS《简单快速》《一次成功》《新手练习复现必备》
  • ollama的下载以及Spring AI Alibaba的ChatModel和ChatClient的流式输出和在idea的实现
  • 自己搭建服务器 发布网站 域名如何申请深圳专业做网站专业
  • 【pytest】fixture 内省(Introspection)测试上下文
  • 【开题答辩实录分享】以《基于python的奶茶店分布数据分析与可视化》为例进行答辩实录分享
  • 嵌入式硬件——基于IMX6ULL的I2C实现
  • 【ROS2学习笔记】分布式通信
  • 唐尧文化 网站建设工作总结邢台手机网站制作
  • 心脏病监测数据可视化分析
  • 【机器人】WMNav 将VLM融入世界模型 | 零样本目标导航 | IROS‘25
  • 第七课(零基础友好版)|机器学习像养宠物:数据—训练—测试(五年级·自学)
  • 无法解析插件 org.apache.maven.plugins:maven-site-plugin:3.12.1
  • 即墨网站建设哪里有安卓app怎么开发
  • 告别性能焦虑:Python 性能革命实践指南
  • Android dmabuf_dump 命令详解
  • Android 中的 mk 和 bp 文件编译说明
  • 配置即权限:从传统开源 RBAC 框架到 SPARK 的六层数据护盾,告别改权限就要改代码的魔咒
  • 青海网站制作腾讯视频wordpress
  • 免费建设钓鱼网站平台wordpress中文开发文档下载
  • JavaScript 测试 jQuery
  • 第2章:项目框架搭建
  • Java 网络请求 Jar 包选型指南:从基础到实战