Vue3 学习笔记 —— 函数式编程、createVNode、render、h 函数

news2024/10/7 10:19:13

目录

2. createVNode()、render()

2.1 初步使用 createVNode()、render()

2.2 h 函数源码分析

3. 使用 h 函数的几种方法

3.1 h 函数 接收的参数

3.2 h 函数 使用方法

4. 通过 h 函数实现 button 组件

4.1 使用 props 接收传入组件的参数

4.2 使用 emit 向组件外发送事件

4.3 使用 ctx.slots.default() 在组件内定义插槽

5. 参考视频


template 模板

JSX(类似 React)

函数式编程(h 函数)

2. createVNode()、render()

2.1 初步使用 createVNode()、render()

Vue3 插件当时也涉及到了 createVNode()、render()

h 函数本质上是用了 Vue 内置函数 —— createVNode()、render() 实现的

我在 ElementPlus 实验室里试了一下:

  • 从 vue 中,引入 createVNode, render 函数
  • 使用 createVNode() 创建虚拟 DOM 节点
  • 使用 render() 渲染虚拟 DOM 节点

createVNode —— 创建虚拟 DOM:

  • @param 参数1 创建元素类型,必选
  • @param 参数2 创建元素属性
  • @paran 参数3 创建元素内容

render —— 渲染虚拟 DOM:

  • @param 参数1 要被渲染的虚拟 DOM,必选
  • @param 参数2 要渲染的位置,必选

完整测试代码:

<template>
  <div>
  </div>
</template>

<script lang="ts" setup>
import { createVNode, render } from 'vue'

/**
 * createVNode —— 创建虚拟 DOM
 * @param 参数1 创建元素类型,必选
 * @param 参数2 创建元素属性
 * @paran 参数3 创建元素内容
 * @description 虚拟 DOM 创建完成后,需要使用 render 函数,才能在页面中渲染
 */
const testDiv = createVNode('div', { id: "myDivId" }, 'Lyrelion');
console.log('虚拟 DOM 状态 --- testDiv ---', testDiv);

/**
 * render —— 渲染虚拟 DOM
 * @param 参数1 要被渲染的虚拟 DOM,必选
 * @param 参数2 要渲染的位置,必选
 * @description 虚拟 DOM 创建完成后,需要使用 render 函数,才能在页面中渲染
 */
render(testDiv, document.body);
</script>

 

结果如下,可以看到,我给 div 添加的 id、innerHTML,在虚拟 DOM 中都体现了 

2.2 h 函数源码分析

位置:packages\runtime-core\src\h.ts

打开后,可以看到作者贴心的加了一段注释:

// “h” 是 “createVNode” 的用户友好的版本,适用于手动编写的渲染函数


// 编译器生成的代码使用 “createVNode”,因为
// 1.它是单态的,避免了额外的呼叫开销
// 2.它允许为优化指定 patchFlags

// 没有 props 的命名槽,需要显式 “null” 以避免歧义

 

可以看到最后的 h 函数方法中,一直在使用 createVNode()

import {
  VNode,
  VNodeProps,
  createVNode,
  VNodeArrayChildren,
  Fragment,
  Text,
  Comment,
  isVNode
} from './vnode'

...
...
...

// “h” 是 “createVNode” 的用户友好的版本,适用于手动编写的渲染函数
// 编译器生成的代码使用 “createVNode”,因为
// 1.它是单态的,避免了额外的呼叫开销
// 2.它允许为优化指定 patchFlags

/*
// type only
h('div')

// type + props
h('div', {})

// type + omit props + children
// Omit props does NOT support named slots
h('div', []) // array
h('div', 'foo') // text
h('div', h('br')) // vnode
h(Component, () => {}) // default slot

// type + props + children
h('div', {}, []) // array
h('div', {}, 'foo') // text
h('div', {}, h('br')) // vnode
h(Component, {}, () => {}) // default slot
h(Component, {}, {}) // named slots

// 没有 props 的命名槽,需要显式 “null” 以避免歧义
h(Component, null, {})
**/

...
...
...

// Actual implementation
export function h(type: any, propsOrChildren?: any, children?: any): VNode {
  const l = arguments.length
  if (l === 2) {
    if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
      // single vnode without props
      if (isVNode(propsOrChildren)) {
        return createVNode(type, null, [propsOrChildren])
      }
      // props without children
      return createVNode(type, propsOrChildren)
    } else {
      // omit props
      return createVNode(type, null, propsOrChildren)
    }
  } else {
    if (l > 3) {
      children = Array.prototype.slice.call(arguments, 2)
    } else if (l === 3 && isVNode(children)) {
      children = [children]
    }
    return createVNode(type, propsOrChildren, children)
  }
}

 

3. 使用 h 函数的几种方法

3.1 h 函数 接收的参数

  • type —— 元素的类型,必选
  • propsOrChildren —— 数据对象(props、attrs、dom、class、style、...)
  • children —— 子节点,可以包含混合的 VNode 和 字符串

除类型 type 之外,所有参数都是可选的

3.2 h 函数 使用方法

// 除类型之外的所有参数都是可选的
h('div')
h('div', { id: 'foo' })
 
// 属性和内容,都可以在第二个参数中使用
// Vue 会自动选择正确的分配方式
h('div', { class: 'bar', innerHTML: 'hello' })
 
// 可以添加 .prop 和 .attr 等修饰符
// 分别带有 “.” 和 “^” 前缀
h('div', { '.name': 'some-name', '^width': '100' })
 
// class、style 可以是对象,也可以是数组
h('div', { class: [foo, { bar }], style: { color: 'red' } })
 
// 定义事件需要加 on,如 onXxx
h('div', { onClick: () => {} })
 
// 子集可以是字符串
h('div', { id: 'foo' }, 'hello')
 
// 如果没有props,可以省略 props
h('div', 'hello')
h('div', [h('span', 'hello')])
 
// 子数组可以包含混合的 VNode 和 字符串
h('div', ['hello', h('span', 'hello')])

4. 通过 h 函数实现 button 组件

4.1 使用 props 接收传入组件的参数

定义一个箭头函数,该函数返回一个 h 函数

箭头函数默认接收两个参数 props、ctx,就跟 setup 接收的两个参数作用一样

再来回忆下:

  • 第一个参数 div 就是元素类型
  • 第二个参数 { class: 'my-div' } 就是 数据对象(props、attrs、dom、class、style、...)
  • 第三个参数 props.text 子节点,此处就是一段文字
<template>
  <Btn text="Lyrelion"></Btn>
</template>
  
<script setup lang='ts'>
import { h } from 'vue';

type Props = {
  text: string
}

// 按钮组件 —— 定义一个箭头函数,返回 h 函数
const Btn = (props: Props, ctx: any) => {
  return h('div', {
    class: 'my-div',
  }, props.text)
}

</script>

<style scoped>
  .my-div {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 110px;
    height: 55px;
    background: red;
    border-radius: 10px;
    color: #fff
  }
</style>

 

 

4.2 使用 emit 向组件外发送事件

emit 添加事件的时候,一定要带上 on 前缀

<template>
  <Btn text="Lyrelion" @on-click="getNum"></Btn>
</template>
  
<script setup lang='ts'>
import { h } from 'vue';

type Props = {
  text: string
}

// 按钮组件 —— 定义一个箭头函数,返回 h 函数
const Btn = (props: Props, ctx: any) => {
  return h('div', {
    class: 'my-div',
    onClick: () => {
      ctx.emit('on-click', 123)
    }
  }, props.text)
}

const getNum = (num: number) => {
  console.log(num);
}

</script>

 

 

4.3 使用 ctx.slots.default() 在组件内定义插槽

<template>
  <Btn @on-click="getNum">
        <template #default>
            Lyrelion-slots
        </template>
  </Btn>
</template>
  
<script setup lang='ts'>
import { h } from 'vue';

type Props = {
  text?: string
}

// 按钮组件 —— 定义一个箭头函数,返回 h 函数
const Btn = (props: Props, ctx: any) => {
  return h('div', {
    class: 'my-div',
    onClick: () => {
      ctx.emit('on-click', 123)
    }
  }, ctx.slots.default())
}

const getNum = (num: number) => {
  console.log(num);
}

</script>

 

5. 参考视频

小满Vue3(第三十八章 函数式编程,h函数)_哔哩哔哩_bilibili小满Vue3(第三十八章 函数式编程,h函数)是Vue3 + vite + Ts + pinia + 实战 + 源码 +electron的第50集视频,该合集共计110集,视频收藏或关注UP主,及时了解更多相关视频内容。https://www.bilibili.com/video/BV1dS4y1y7vd?p=50&vd_source=8bc01635b95dbe8ecd349b2c23b03a10

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/77246.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自动化运维工具—Ansible概述及命令行模块

一.自动化运维工具—Ansible概述及命令行模块 1.1 Ansible是什么 Ansible是一个基于Python开发的配置管理和应用部署工具&#xff0c;现在也在自动化管理领域大放异彩。它融合了众多老牌运维工具的优点&#xff0c;Pubbet和Saltstack能实现的功能&#xff0c;Ansible基本上都可…

机器人手臂四旋翼的笛卡尔阻抗控制(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 当机器人手指与障碍物接触时,呈现出2阶机械阻抗特性。在阻抗控制算法中,不需直接计算加速度,从而避免了因大加速度误差给控制带…

leetcode 473. 火柴拼正方形-思路整理与细节分析

题目&#xff1a; 你将得到一个整数数组matchsticks&#xff0c;其中 matchsticks[i]是第i个火柴棒的长度。你要用所有的火柴棍拼成一个正方形。你不能折断任何一根火柴棒&#xff0c;但你可以把它们连在一起&#xff0c;而且每根火柴棒必须使用一次。如果你能使这个正方形&am…

FPGA新起点V1开发板(五)——Modelsim软件的使用(联合仿真)

文章目录一、简介1.1 前仿真1.2 后仿真二、联合仿真2.1 选择modesim的安装路径2.2 设置选择eda的工具2.3 test bench文件2.4 打开test bench文件2.5 给系统时钟和复位信号赋初值2.6 配置仿真功能三、RTL仿真3.1 打开波形窗口3.2添加内部信号四、时序仿真一、简介 1.1 前仿真 主…

web大学生网页作业成品 响应式网站水果超市7页(html+css+javascript+jquery+bootstarp)

&#x1f380; 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

web期末大作业 用HTML+CSS做一个漂亮简单的节日网页【传日文化节日中秋节】

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

web前端期末大作业—— HTML+CSS豪华车 (9页)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

蚂蚁金服开源的这份SpringBoot笔记,曾在24小时内GitHub星标48k

前言 Spring的影响力想必就不用小编多说了&#xff0c;今天要跟大家说的是SpringBoot。Spring Boot作为目前Spring技术体系中炙手可热的框架之一&#xff0c;已经是开发者们的必备神器了。在实际的项目中&#xff0c;需要集成各种的插件支持&#xff0c;还有很多或许我们平时不…

【计算机考研408-计算机网络-教书匠视频笔记】主机访问浏览器的全部过程

主机H1利用浏览器通过该域名请求访问web服务器 由于题目给定主机H1的ARP表是空的 &#xff08;1&#xff09;主机H1首先会发送ARP请求报文&#xff0c;ARP请求报文会被封装在以太网的MAC帧中发送 ARP请求报文&#xff1a;FF-FF-FF-FF-FF-FF 源MAC地址&#xff1a;00-11-22-3…

Docker 容器使用

文章目录Docker 容器使用Docker 客户端运行一个web应用查看 WEB 应用容器网络端口的快捷方式查看WEB应用程序日志查看WEB应用程序容器的进程检查WEB应用程序停止WEB应用容器重启WEB应用容器移除WEB应用容器Docker 容器使用 Docker 客户端 docker 客户端非常简单 ,我们可以直接…

全网显示 IP 归属地,用上这个开源库,实现也太简单了

细心的小伙伴可能会发现&#xff0c;最近蘑菇新上线了 IP 属地的功能&#xff0c;小伙伴在发表动态、发表评论以及聊天的时候&#xff0c;都会显示自己的 IP 属地信息 动态显示IP属地 在蘑菇群聊中&#xff0c;也 可 以 展 示 IP 属 地&#xff0c;下面是小伙伴们在交流群中显…

【强化学习论文合集】十八.2019国际表征学习大会论文(ICLR2019)

强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题。 本专栏整理了近几年国际顶级会议中,涉及强化学习(Rein…

面试官:你觉得你最大的缺点是什么?

面试官:你觉得你最大的缺点是什么? 前言 相信百分之80的同学们都会被问到这个问题&#xff1a;你觉得你最大的缺点是什么? 这也是求职者一个充满恐惧的问题&#xff0c;特别是我们程序员&#xff0c;大家在与人沟通并没有我们与代码沟通这么得心应手&#xff0c;如果你没回…

网络请求工具wget和curl

一. wget命令 wget命令来自于英文词组”web get“的缩写&#xff0c;其功能是用于从指定网址下载网络文件。 wget命令支持如HTTP、HTTPS、FTP等常见协议&#xff0c;可以在命令行中直接下载网络文件。 注意&#xff1a;不同busybox版本集成的wget命令&#xff0c;可能不…

统计检验分析

1. 正态分布检验 2. 统计检验 正态分布且方差齐非正态分布或方差不齐para test non-para testnon-pairedpaired2组 t-testWilcoxon rank-sum testWilcoxon signed-rank test3组及以上One way ANOVA Kruskal-Wallis testt-test: Paired t-test: 确定某个总体的成对测量值之间…

说说WM_DESTROY和WM_NCDESTROY的区别

在一个 Windows 窗口被销毁的时候&#xff0c;你会发现有两个比较类似的消息&#xff1a;WM_DESTROY和WM_NCDESTROY&#xff0c;那么&#xff0c;这俩兄弟之间有什么区别呢&#xff1f;今天就来讲讲。 不同之处在于&#xff0c;WM_DESTROY消息在窗口销毁序列的开头发送&#x…

MySQL执行计划误选索引及修改方案

MySQL的优化器 MySQL在执行查询语句时使用那个索引是由server层的优化器决定的。优化器的作用是找到一个最优的执行方案&#xff0c;用最小的代价去执行语句。由于MySQL使用预估的方式去选择索引&#xff0c;所以MySQL可能会出现选择索引出错的情况&#xff0c;无法命中最优索…

刘韧工作手册(2023年版)

刘韧于2022年9月22日为云算科技做内部演讲。由谭缘整理成文&#xff0c;李欣欣编辑&#xff0c;朱芳文审定。一、认知篇01 干中学&#xff0c;重复做。“学”是为了“习”&#xff0c;学到的东西是为了下一次习的时候&#xff0c;做得更好。“习”&#xff0c;是最终实践的成果…

WSL安装教程

wsl安装教程引言前期准备工作安装wsl第一步第二步 检测系统版本第三步 确定虚拟机特性第四步 下载Linux内核的更新包第五步 设置WSL 2作为默认版本第六步 选择Linux发行版本并设置Linux账号小TIPS引言 Windows Subsystem for Linux&#xff08;简称WSL&#xff09;是一个在Win…

大家都在画圣诞树,我们用代码敲一颗吧~圣诞树

前段时间发布的文章很多人问怎么操作的&#xff0c;今天具体说明一下&#xff1a;PS&#xff1a;如果需要下载可以点击左下角阅读全文下载代码使用更方便具体步骤如下&#xff1a;复制下面代码在电脑里面新建一个记事本&#xff0c;将代码复制到新建的记事本里保存记事本&#…