vue —— h函数的学习与使用

文章目录

  • 一、h函数是什么?
  • 二、h函数格式说明及使用
    • 示例1:简单创建一个VNode(vue3)
    • 示例2:vue2中h函数用法
    • 示例3:vue3中h函数的用法
    • vue2和vue3中h函数的区别?
  • 三、h函数实现原理
  • 四、h函数常用场景
  • 五、h函数及插槽slot使用
  • 六、h函数和v-model使用

一、h函数是什么?

先看一下 Vue3官方文档说明:
在这里插入图片描述

简单理解: Vue中的 h 函数是 Vue 用于创建虚拟DOM(Virtual DOM)节点的核心函数。在 Vue 3.0 版本中,这个函数作为渲染函数的基础工具,用于替代模板解析的过程,允许开发者以编程方式描述组件结构和动态生成虚拟节点。

二、h函数格式说明及使用

function h(type, props, children)
  • type: 必需,表示要创建的元素类型或组件类型。它可以是一个字符串(HTML标签名),一个组件选项对象、异步组件函数或者一个函数式组件。
  • props: 可选的对象,包含了传递给元素或组件的所有属性(attributes)和 props。例如:可以包含类名、样式、事件监听器等。
  • children: 可选,代表子节点,它可以是字符串(文本内容)、数组(包含多个子节点,每个子节点可以是字符串或其他由 h 创建的虚拟节点)或者其他合法的虚拟DOM节点。

示例1:简单创建一个VNode(vue3)

import { h } from 'vue'

const vnode = h(
  'div', // 类型为 div 标签
  { id: 'app', class: 'container' }, // props 对象
  [ // 子节点数组
    h('p', { class: 'text' }, 'Hello, World!'), // 子节点1:一个 p 标签
    h('button', { onClick: handleClick }, 'Click me') // 子节点2:一个绑定了点击事件handleClick的按钮
  ]
)

function handleClick() {
  console.log('Button was clicked!')
}

通过h函数的方式构建虚拟DOM树,Vue可以在内部高效地比较新旧虚拟DOM的不同,并最小化地更新实际DOM,从而提高页面渲染性能。

示例2:vue2中h函数用法

import Vue from 'vue' // 引入Vue和h函数

// 定义一个组件
var MyComponent = {
  props: ['message'],
  render: function (createElement) {
    return createElement( // createElement实际上就是h函数
      'div', // 元素类型
      { 		 // 属性对象
        class: ['my-class'], 
        style: { color: 'red' },
        on: {
          click: this.handleClick,
        },
      },
      [ // 子元素数组
        this.message, // 文本内容
        createElement('span', {}, '这是一个子元素'),
      ]
    )
  },
  methods: {
    handleClick: function (event) {
      console.log('Clicked!')
    }
  }
}

// 注册并使用该组件
new Vue({
  el: '#app',
  components: {
    MyComponent
  },
  template: `
    <div id="app">
      <my-component message="Hello from custom render function!" />
    </div>
  `
})

示例3:vue3中h函数的用法

import { h, ref, defineComponent } from 'vue';

// 定义一个使用h函数的组件
const MyComponent = defineComponent({
  props: {
    message: String,
  },
  setup(props) {
    const count = ref(0);

    function handleClick() {
      count.value++;
    }

    return () => h('div', { // 元素类型
      class: ['my-class'], 
      style: { color: 'red' },
      onClick: handleClick, // 事件监听器
    }, [
      props.message, // 文本内容
      h('span', {}, '这是一个子元素'),
      `Clicked ${count.value} times`, // 动态文本内容
    ]);
  },
});

// 使用该组件
new Vue({
  render: (h) => h(MyComponent, { props: { message: "Hello from custom render function!" } }),
}).$mount('#app');

vue2和vue3中h函数的区别?

1、导入方式不同: Vue 2需要从 Vue 实例中获取 h 函数,通常在 render 函数中通过参数传递。Vue 3直接从 @vue/runtime-domvue 模块中导入。

// vue2
import Vue from 'vue';
export default {
  render(h) {
   // 使用 h 函数
  }
}

// vue3
import { h } from 'vue';
export default {
  setup() {
  	return () => h('div', 'Hello World');
  }
}

2、与Composition API集成

  • Vue 2不直接支持 Composition API,需要结合 options API 来使用。
  • Vue 3在 Composition API 的 setup 函数中可以直接使用响应式数据,并返回一个渲染函数作为组件的输出。

3、模板语法的替代

  • Vue 2在自定义渲染函数中广泛使用 h 函数来代替模板语法。
  • Vue 3虽然仍然可以使用 h 函数,但随着单文件组件(SFC)中模板语法以及Composition API的改进,直接使用 h 函数的情况相对较少。

4、优化与性能

  • Vue 3底层引擎优化,使得 h 创建的虚拟DOM更加高效,尤其是在大型应用中表现更好。

5、props的处理

  • Vue 3中的 props 是通过 defineComponentprops 属性显式声明的,而在使用 h 函数时,这些 prop 值可以通过 setup 函数中的 props 参数直接访问,无需像 Vue 2 中那样进行解构。

总结来说:Vue 3中的 h 函数保持了其核心作用,但在上下文、API集成度和性能等方面进行了改进和优化,使其更适应于现代Vue应用程序开发需求。

三、h函数实现原理

Vue中的 h 函数(在 Vue 2中也称为 createElement)是用于构建虚拟 DOM 节点的核心函数。

基本实现原理可概述如下:

1、虚拟DOM节点创建:当调用 h(type, props, children) 时,它会创建一个描述真实DOM元素或组件的虚拟对象。这个虚拟对象包含类型信息(如标签名、组件名称)、属性对象(包括类名、样式、事件绑定等)以及子节点列表。

2、响应式数据绑定:如果传递给 h 函数的属性值是响应式的(例如由 Vue 的 datacomputed 返回的值),Vue 将通过内部的响应式系统跟踪这些值的变化,并在需要时重新生成虚拟DOM树。

3、DOM更新优化:Vue 使用虚拟DOM来计算状态变化前后DOM结构的差异,并将最小化的更新应用到实际DOM上,这个过程称为“异步批处理更新”和“DOM diff算法”。当组件状态改变并触发重新渲染时,Vue 会比较新旧虚拟DOM树的差异,只对实际发生变化的部分进行DOM操作,避免了频繁地重绘整个页面,从而提高性能。

4、跨平台支持h 函数作为抽象层,不仅限于浏览器环境下的DOM渲染,还能够应用于服务器端渲染(SSR)以及其他非DOM环境,比如Weex等跨平台应用场景。

5、Vue框架中的应用:Vue 在编译模板阶段,会将模板转换为 render 函数,render 函数中就大量使用了 h 函数来构建虚拟DOM。在Vue 3中即使使用的是模板语法,Vue也会将其编译成基于 h 函数的渲染逻辑。

总结来说,Vue 中的 h 函数通过创建和维护虚拟DOM,结合响应式数据系统与高效的DOM更新策略,实现了高效、灵活的视图渲染机制。

四、h函数常用场景

1、自定义渲染逻辑:当模板语法不足以处理复杂的动态内容或需要根据运行时条件动态生成DOM结构时,可以使用 h 函数在组件的 render 函数中编写更灵活的渲染逻辑。

2、高级组件库开发:组件库开发者通常会依赖 h 函数来创建可复用、功能丰富的组件。通过编程方式构建虚拟节点,可以实现对DOM元素精细控制和优化,如高级表格组件、树形控件、拖拽排序等复杂交互场景。

3、性能优化:在某些性能关键路径上,通过手动编写 h 函数来精确控制DOM更新,避免不必要的子组件渲染,从而提升应用性能。

4、无模板组件:如果不希望或者无法使用 .vue 单文件组件中的 <template> 标签,可以完全基于 h 函数来编写组件的渲染内容。

5、与JSX结合:Vue 3支持 JSX 语法,而 JSX 在编译阶段会被转换为 h 函数调用,因此对于喜欢 React 风格 JSX 开发的开发者来说,h 函数是底层支持的基础。

6、服务端渲染 (SSR):在服务端渲染 Vue 应用时,也需要使用 h 函数来创建 SSR 环境下的虚拟 DOM 节点。

简单使用示例:

// 通过h函数根据传入的items数组动态生成多个<li>子元素,并确保每个子元素都有唯一的key属性,以便Vue进行高效的DOM更新
export default {
  name: 'CustomComponent',
  props: ['items'],
  render() {
    return h(
      'ul',
      this.items.map(item => 
        h('li', { key: item.id }, item.text)
      )
    );
  }
}

五、h函数及插槽slot使用

import { h, defineComponent } from 'vue';

// 定义一个使用插槽的子组件:通过this.$slots来访问并渲染插槽内容
const MyComponent = defineComponent({
  render() {
    return h('div', [
      this.$slots.default?.(), // 使用默认插槽
      this.$slots.header?.(),  // 使用具名插槽 - 名为"header"
      this.$slots.footer?.(),  // 使用具名插槽 - 名为"footer"
    ]);
  },
});

// 在父组件中使用MyComponent并插入插槽内容
export default defineComponent({
  render() {
    return h(MyComponent, {}, [
      h('p', '这是默认插槽的内容'), 					// 默认插槽的内容
      h('template', { slot: 'header' }, [ // 具名插槽"header"的内容
        h('h1', '这是头部插槽内容'),
      ]),
      h('template', { slot: 'footer' }, [ // 具名插槽"footer"的内容
        h('p', '这是底部插槽内容'),
      ]),
    ]);
  },
});

六、h函数和v-model使用

h函数本身并不直接支持v-model指令,但通过正确设置props和自定义事件,可以模拟出类似的双向数据绑定效果。

示例:使用h函数创建子组件,并实现了类似v-model的功能

// 子组件:实现了v-model的行为
import { h, defineComponent, ref, toRef } from 'vue';


const CustomInput = defineComponent({
  props: {
    modelValue: { type: String, required: true },
  },
  
  emits: ['update:modelValue'], // 声明将要触发的事件

  setup(props, { emit }) {
    const internalValue = ref(props.modelValue); // 创建一个响应式变量保存内部状态

    function handleChange(event) {
      internalValue.value = event.target.value; 			// 更新内部状态
      emit('update:modelValue', internalValue.value); // 触发更新事件
    }

    return () => h('input', {
      type: 'text',
      value: internalValue.value, // 将内部状态绑定到input元素的value属性
      onInput: handleChange, 			// 监听输入事件并更新状态
    });
  },
});

export default CustomInput;
// 父组件
import { h, ref } from 'vue';
import CustomInput from './CustomInput.vue';

export default {
  setup() {
    const inputValue = ref('初始值');

    return () => h(CustomInput, {
      modelValue: inputValue.value,
      'onUpdate:modelValue': (value) => {
        inputValue.value = value;
      },
    });
  },
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java每日一记 —— MySQL窗口函数的使用

MySQL窗口函数 1.什么时窗口函数2.窗口函数的基本应用2.1.排序函数2.2.分布函数2.3.前后函数2.4.头尾函数2.5.聚合函数2.6.其他函数 窗口函数时MySQL8.0中的 注意&#xff1a;窗口函数也有人称为“开窗函数” 1.什么时窗口函数 引入问题&#xff1a;让我们从一个实际的问题开始…

redis排序

文章目录 简介SORT命令的实现ALPHA选项的实现ASC和DESCBYLIMITGET命令 类似映射STORE选项的实现多个命令的执行顺序 简介 Redis的SORT命令可以对列表键、集合键或者有序集合键的值进行排序。 SORT命令的实现 服务器执行SORT numbers 命令的详细步骤如下&#xff1a; 1&#…

在windows安装python版本的tensorrt

文章目录 一、进入官网&#xff0c;下载tensorrt包二、下载后解压并把相应文件拷入对应cuda的文件夹2.1 拷贝头文件2.2 拷贝静态库2.3 拷贝动态库 三、安装whl文件四、验证 一、进入官网&#xff0c;下载tensorrt包 https://developer.nvidia.com/tensorrt-download 这里需要…

接口文档swagger2的使用

Spring-接口文档swagger2 1、swagger/knife4j 接口文档配置 ​ knife4j是swagger的增强版本&#xff0c;更加的小巧、轻量&#xff0c;功能也是更加的完善&#xff0c;UI也更加的清晰&#xff1b;可以从swagger到knife4j无缝切换。 1.1 引入相关依赖 <!--接口文档的开发:…

【Tailwind】各种样式的进度条

基本样式进度条&#xff1a; <div class"mb-5 h-2 rounded-full bg-gray-200"><div class"h-2 rounded-full bg-orange-500" style"width: 50%"></div> </div>带文字的进度条&#xff1a; <div class"relativ…

销售退货单单据录入的序列号当前单据类型不在允许范围内

文章目录 销售退货单单据录入的序列号当前单据类型不在允许范围内报错截图原因分析 销售退货单单据录入的序列号当前单据类型不在允许范围内 报错截图 销售退货单保存 原因分析 销售退货单序列号录入设置&#xff1a; 报错不满足条件的序列号&#xff0c;最后出库是 其他…

golang整合rabbitmq,创建交换机并绑定队列

1,如果要开发消息队列,需要创建交换机和队列,通常有2中方式创建,1种是在面板直接创建 2,第二种就是在代码中创建,这里 展示的是go语言代码中创建rabbitmq package mainimport ("fmt""log""github.com/streadway/amqp" )func main() {// 连接R…

Java 枚举和注解

一、枚举类 把具体的对象一个一个例举出来的类就称为枚举类 枚举对应英文(enumeration, 简写 enum)枚举是一组常量的集合。可以这里理解&#xff1a;枚举属于一种特殊的类&#xff0c;里面只包含一组有限的特定的对象。 1.实现方式1——自定义类实现枚举 public class Enume…

前端面试题:topK算法

当面试官问你&#xff0c;在不考虑数字越界的情况下&#xff0c;有1亿条搜索数据&#xff0c;让你从中找到前100条频率高的数据你会怎么实现&#xff1f; 当时&#xff0c;我的第一印象是把数据分组&#xff0c;分别求前多少条&#xff1f;但是没法保证每组的前100条或者多少条…

关于Linux系统的目录结构介绍常用命令介绍

目录 一. Linux系统目录结构介绍 二. 一些常用命令的介绍 1、# 与 $的区别 2、ifconfig 3、su 4、cd 5、目录查看 6、查看文件内容 7、创建目录及文件 8、复制和移动 9、其他 10、tar 11、which 12、whereis 13、find 14、chmod 三. vim的基本使用 四. SSH密…

【推荐100个unity插件之16】3D物品描边效果——Quick Outline免费插件

文章目录 前言地址介绍使用例子完结 前言 关于3D描边&#xff0c;其实之前有用shader弄过一个&#xff1a;【实现100个unity特效】shader实现3D物品闪光和描边效果 但是很遗憾的是他不支持URP项目&#xff0c;所以现在推荐这款插件&#xff0c;他能很好的支持URP&#xff0c;…

MyBatis中一级缓存是什么?SqlSession一级缓存失效的原因?如何理解一级缓存?

一级缓存是SqlSession级别的&#xff0c;通过同一个SqlSession查询的数据会被缓存&#xff0c;下次查询相同的数据&#xff0c;就 会从缓存中直接获取&#xff0c;不会从数据库重新访问 使一级缓存失效的四种情况&#xff1a; 1) 不同的SqlSession对应不同的一级缓存 2) 同一…

蓝桥杯备赛 week 3 —— 高精度(C/C++,零基础,配图)

目录 &#x1f308;前言&#xff1a; &#x1f4c1; 高精度的概念 &#x1f4c1; 高精度加法和其模板 &#x1f4c1; 高精度减法和其模板 &#x1f4c1; 高精度乘法和其模板 &#x1f4c1; 高精度除法和其模板 &#x1f4c1; 总结 &#x1f308;前言&#xff1a; 这篇文…

电饼铛行业研究:中国市场规模整体上涨趋势明显

电饼铛是一个烹饪食物的工具&#xff0c;单面或者上下两面同时加热使中间的食物经过高温加热&#xff0c;达到烹煮食物的目的。电饼铛也叫烤饼机&#xff0c;可以灵活进行烤、烙、煎等烹饪方法&#xff0c;有家用小款型和店面使用大款两种。 大型的电饼铛具有自动上下火控温…

Python基础语法:代码规范、判断语句与循环语句

目录 一、代码规范 二、判断语句 三、循环语句 总结&#xff1a; Python是一种高级、动态类型的编程语言&#xff0c;其语法清晰、简洁&#xff0c;易于学习。本文将介绍Python基础语法中的代码规范、判断语句和循环语句。 一、代码规范 良好的代码规范可以提高代码的可读…

谈谈ArrayList和LinkedList的区别

目录 一、什么是数组 二、ArrayList 三、LinkedList 四、ArrayList和LinkedList的区别 一、什么是数组 在编程中&#xff0c;数组&#xff08;Array&#xff09;是一种用于存储多个相同类型数据元素的数据结构。它是一个有序的集合&#xff0c;其中每个元素都有一个唯一的…

Windows11操作系统百科

简介 Windows 11是由微软公司&#xff08;Microsoft&#xff09;开发的操作系统&#xff0c;应用于计算机和平板电脑等设备 [1]。于2021年6月24日发布 [3]&#xff0c;2021年10月5日发行 [29]。 Windows 11提供了许多创新功能&#xff0c;增加了新版开始菜单和输入逻辑等 [6]…

Java 字符串 04 练习-用户登录

自己写的代码&#xff1a; import java.util.Scanner; public class practice {static String rightUsername "zhangsan";static String rightPassword "123456";public static void main(String[] args) {//读题拆解法//1、定义两个变量&#xff0c;记…

机器学习--jupyter使用

机器学习–jupyter notebook的使用 Jupyter项目是一个非盈利的开源项目&#xff0c;源于2014年的ipython项目&#xff0c;因为它逐渐发展为支持跨所有编程语言的交互式数据科学和科学计算 Jupyter Notebook&#xff0c;原名IPython Notbook&#xff0c;是IPython的加强网页版…

NAS with RL(使用强化学习进行神经网络架构搜索,基于pytorch框架)

目录 一、 原代码 二、 代码学习(修改后并加上详细注释&#xff09; 1. 控制器 2. NASModel 3. 初始化及训练过程 3.1 主要参数的初始化 3.2 数据集的准备与加载 3.3 搜索空间 3.4 训练、参数更新 4. 对搜索空间、搜索策略、性能评估策略的认识 4.1 搜索空间&#xf…