vue3中h函数的使用

h函数是用于创建一个 vnodes ,它既可以用于创建原生元素,也可以创建组件,其渲染后的效果等同于使用模版语言来进行创建。

h函数的传参如下:

// 完整参数签名
function h(
  type: string | Component,
  props?: object | null,
  children?: Children | Slot | Slots
): VNode

// 省略 props
function h(type: string | Component, children?: Children | Slot): VNode

第一个参数既可以是一个字符串 (用于原生元素) 也可以是一个 Vue 组件定义。第二个参数是要传递的 prop,第三个参数是子节点。

1、创建原生元素:

<script setup>
import { ref, h } from 'vue'

const message = ref('在div里面渲染的值')
const comp = h(
  'div',
  {
    style: {
      color: 'red'
    },
    onclick: ()=> {
      console.log('点击了原生元素div');
    }
  },
  message.value
)
</script>

<template>
  <component :is="comp" />
</template>

这里给 div 传的 props 里有样式 style 和 事件 click ,在页面上的显示和点击了元素后效果和在模版语言中定义是一样的:

需要注意的是,我们这里的 comp 是一个 vnodes ,而 setup 函数并不是响应式的环境,所以当我们在 setup 函数中调用 h 函数来获取 vnodes 时,并没有绑定 message !只有在 render 函数 中执行才会绑定,所以我们可以定义一个h函数来返回给 comp,在渲染时,让component来帮我们调用。可以通过在 2s 后改变 message 的值来对比两种情况下页面渲染的变化:

const message = ref('在div里面渲染的值')
// 这样不会更新 message 的值
// const comp = h(
//   'div',
//   {
//     style: {
//       color: 'red'
//     },
//     onclick: ()=> {
//       console.log('点击了原生元素div');
//     }
//   },
//   message.value
// )

// 这样可以更新 message 的值
const comp = () => h(
  'div',
  {
    style: {
      color: 'red'
    },
    onclick: ()=> {
      console.log('点击了原生元素div');
    }
  },
  message.value
)

setTimeout(()=> {
  message.value = '2s后更新了在div里面渲染的值'
}, 2000)

2、创建组件

这里使用的是一个批量注册的方式导入 HelloWorld 组件,Comp 是一个全局组件

全局组件的定义如下:

// component.js

import { h } from 'vue'

const modules = import.meta.glob('../components/*.vue')

const components = {}
for(const path in modules) {
    const module = await modules[path]()
    const componentName = path.replace(/.*\/(.*)\.vue/, '$1')
    components[componentName] = module.default
}
const component = (props,{slots}) => {
    let name  =  props?.component
    return h(
        components[name], 
        { 
            msg: '通过props传的msg',
            onFoo: (value)=> {
                console.log(value);
            },
        },
        slots
    )
}

export default component

页面上导入是这样的:

容易混淆的地方是,Comp 是一个全局组件,通过传参 HelloWorld 渲染的才是 HelloWorld 组件,相当于外面套了一层,这里的 slots 其实是 Comp 组件的 slots , slots 传进了 HelloWorld 组件里,使用 HelloWolrd 组件里预留的插槽渲染的

<Comp component="HelloWorld">
    我是 Comp 组件的默认插槽
    <template #header>
      <div>
        我是 Comp 组件的 header 插槽
      </div>
    </template>
  </Comp>

HelloWorld 组件中定义的:

<template>
  <div>
    <div>{{msg}}</div>
    <div style="color: red">{{valueInProps}}</div>
    <slot></slot>
    <slot name="header" valueInSlot="我是 header 插槽里面的值">
      <div>
        我是 header 插槽里面的默认值,外部没有定义的话就是显示这个
      </div>
    </slot>
  </div>
</template>

那么 slots 里面到底是什么呢,我们直接打印一下看看:

我们可以看到 slots 其实是一个对象,键是插槽的名字,值其实就是一个 渲染函数 h(),

也可以这样写:

const component = (props,{slots}) => {
    let name  =  props?.component
    console.log(slots);
    return h(
        components[name], 
        { 
            msg: '通过props传的msg',
            onFoo: (value)=> {
                console.log(value);
            },
        },
        slots.default()
    )
}

使用作用域插槽的话:

const component = (props,{slots}) => {
    let name  =  props?.component
    return h(
        components[name], 
        { 
            msg: '通过props传的msg',
            onFoo: (value)=> {
                console.log(value);
            },
        },
        slots.default('我是作用域插槽传的值')
    )
}

<Comp component="HelloWorld">
    <template #default="scope">
      <div>
        {{scope}}
      </div>
    </template>
  </Comp>

如果我们不想帮 Comp 组件渲染的话,也可以自己来写:

const component = (props,{slots}) => {
    let name  =  props?.component
    console.log(slots);
    return h(
        components[name], 
        { 
            msg: '通过props传的msg',
            onFoo: (value)=> {
                console.log(value);
            },
        },
        {
            default: ()=> h('div', '我是 HelloWorld 组件的默认插槽里面的值'),
            header: ()=> h('div', '我是 HelloWorld 组件的 header 插槽里面的值'),
        }
    )
}

如果我们想渲染预留插槽里面的值(即作用域插槽),可以这样传:

<slot name="header" valueInSlot="我是 header 插槽里面的值">
      <div>
        我是 header 插槽里面的默认值,外部没有定义的话就是显示这个
      </div>
</slot>
const component = (props,{slots}) => {
    let name  =  props?.component
    console.log(slots);
    return h(
        components[name], 
        { 
            msg: '通过props传的msg',
            onFoo: (value)=> {
                console.log(value);
            },
        },
        {
            default: ()=> h('div', '我是 HelloWorld 组件的默认插槽里面的值'),
            header: ({valueInSlot})=> h('div', '我是 HelloWorld 组件的 header 插槽里面的值,后面是预留插槽的值传递:'+valueInSlot),
        }
    )
}

页面上的显示效果:

还有两个比较好理解的点,这里也补充一下:

在组件中传值,我们知道是用 props 来进行传递,所以在子组件中也是用 defineProps 来 接收值,而子组件想要传值给父组件的话,注意如果是传 foo 函数,则要用 onFoo 接受,例子如下:

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

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

相关文章

【GD32F303红枫派使用手册】第二十二节 IIC-IIC OLED显示实验

22.1 实验内容 通过本实验主要学习以下内容&#xff1a; OLED驱动原理 IIC驱动OLED显示操作 22.2 实验原理 OLED模块的驱动芯片为SSD1306&#xff0c;其显存大小总共为 128*64bit 大小&#xff0c;SSD1306 将这些显存分为了 8 页&#xff0c;其对应关系如下所示&#xff1…

如何将办公文档压缩成rar格式文件?

压缩包格式是我们生活工作中常用到的文件格式&#xff0c;那么如何得到一个rar格式的压缩文件&#xff1f;或者说如何将文件压缩成rar格式而不是zip格式呢&#xff1f;今天我们来了解一下如何压缩为rar格式文件。 首先&#xff0c;下载并安装WinRAR&#xff0c;然后用鼠标选择需…

FlinkCDC介绍及使用

CDC简介 什么是CDC&#xff1f; cdc是Change Data Capture(变更数据获取)的简称。核心思想是&#xff0c;监测并捕获数据库的 变动(包括数据或数据表的插入&#xff0c;更新以及删除等)&#xff0c;将这些变更按发生的顺序完整记录下来&#xff0c;写入到消息中间件以供其它服…

修复 Android 手机卡在启动屏幕上的 7 种方法

Android 手机卡在启动屏幕上的情况并不常见。通常&#xff0c;问题出现在应用新更新或安装未知来源的应用程序后。幸运的是&#xff0c;您可以让您的 Android 手机跳过启动屏幕&#xff0c;而无需前往最近的服务中心。 当您的 Android 手机在启动屏幕上陷入无限循环时&#xf…

计算机组成原理 —— 存储系统(概述)

计算机组成原理 —— 存储系统&#xff08;概述&#xff09; 存储系统按层次划分按照存储介质分类按照存储方式分类按照信息可更改性分类根据信息的可保存性分类存储器性能指标 我们今天来学习计算机组成原理中的存储系统&#xff1a; 存储系统 存储系统是计算机系统中用于存…

css文字镂空加描边

css文字镂空加描边 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>文字镂空</title><style>/* 公用样式 */html,body{width: 100%;height: 100%;position: relative;}/* html{overflow-y: scroll;} */*{margi…

【机器学习 复习】 第1章 概述

一、概念 1.机器学习是一种通过先验信息来提升模型能力的方式。 即从数据中产生“模型”( model )的算法&#xff0c;然后对新的数据集进行预测。 2.数据集&#xff08;Dataset&#xff09;&#xff1a;所有数据的集合称为数据集。 训练集&#xff1a;用来训练出一个适合模…

Android (已解决)Execution failed for task ‘:app:lint‘

文章目录 一、错误原因二、解决方法 一、错误原因 这个错误信息表示在执行 Lint 检查时发现了错误&#xff0c;导致构建过程被中断。Lint 是一个用于检测 Android 项目中潜在问题的工具&#xff0c;比如性能、安全性、可用性等方面的问题。当Lint检查到严重错误时&#xff0c;…

库卡机器人减速机维修齿轮磨损故障

一、KUKA机器人减速器齿轮磨损故障的原因 1. 润滑不足&#xff1a;润滑油不足或质量不佳可能导致齿轮磨损。 2. 负载过重&#xff1a;超过库卡机械臂减速器额定负载可能导致齿轮磨损。 3. 操作不当&#xff1a;未按照说明书操作可能导致KUKA机器人减速器齿轮磨损。 4. 维护不足…

2024年全国青少信息素养大赛python编程复赛集训第四天编程题分享

整理资料不容易,感谢各位大佬给个点赞和分享吧,谢谢 大家如果不想阅读前边的比赛内容介绍,可以直接跳过:拉到底部看集训题目 (一)比赛内容: 【小学组】 1.了解输入与输出的概念,掌握使用基本输入输出和简单运算 为主的标准函数; 2.掌握注释的方法; 3.掌握基本数…

Ubuntu配置ssh+vnc(完整版)

Ubuntu配置sshvnc&#xff08;完整版&#xff09; 1 配置ssh 1. 安装openssh-server&#xff0c;配置开机自启 # 更新包 sudo apt-get update # 安装openssh-server sudo apt-get install -y openssh-server # 启动服务 sudo service ssh start # 配置开机自启 sudo systemc…

Github 2024-06-19 C开源项目日报 Top9

根据Github Trendings的统计,今日(2024-06-19统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目9C++项目1Netdata: 开源实时监控平台 创建周期:4020 天开发语言:C协议类型:GNU General Public License v3.0Star数量:68982 个Fork数量…

可平滑替代传统FTP的国产FTP方案,了解一下

企业在处理数据传输时&#xff0c;效率和安全性是关键。尽管传统FTP曾被广泛采用&#xff0c;然而&#xff0c;随着企业业务需求的增长&#xff0c;传统FTP在传输速度、安全性、稳定性以及可控性方面的不足逐渐显现。许多企业正在寻找更为高效、安全且用户体验更好的的国产FTP方…

在webstorm配置nodejs(从零开始)

在webstorm配置nodejs之前&#xff0c;需要先下载node.js和webStorm。 按下winr&#xff0c;输入cmd打开命令行 输入node -v和npm -v会出现相应的版本&#xff0c;如果报错则需要去下载node.js。 打开webStorm&#xff0c;File—settings 搜索node 选择node.exe安装位置 重启…

Elasticsearch基础(一):阿里云Elasticsearch简介

文章目录 阿里云Elasticsearch简介 一、什么是阿里云Elasticsearch 1、开源Elasticsearch 2、阿里云Elasticsearch 3、阿里云Elasticsearch介绍 4、总结 二、 阿里云Elasticsearch组件 1、X-Pack&#xff08;商业版扩展包&#xff09; 2、 Beats&#xff08;数据采集中…

华为OD机试 - 地图寻宝 - 深度优先搜索BFS(Java 2024 D卷 200分)

华为OD机试 2024D卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;D卷C卷A卷B卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测…

秋招突击——6/21——新作{两两交换链表中的节点,K个一组反转链表}

文章目录 引言新做删除有序数组中的重复项个人实现 K 个一组翻转链表个人实现参考代码 总结 引言 上午完全去听讲座了&#xff0c;听了三场&#xff0c;拿了三个讲座单&#xff0c;从九点一直到十二点。笔记本电脑插电才能用&#xff0c;就没带&#xff0c;所以没有进行复习。…

【图解IO与Netty系列】Netty源码解析——事件循环

Netty源码解析——事件循环 Netty事件循环源码解析select()processSelectedKeys()NioMessageUnsafe#read()NioByteUnsafe#read() runAllTasks() Netty事件循环 当Netty服务端启动起来以后&#xff0c;就可以接受客户端发送的请求&#xff0c;接收到客户端发来的请求后就会有事…

Android平台下VR头显如何低延迟播放4K以上超高分辨率RTSP|RTMP流

技术背景 VR头显需要更高的分辨率以提供更清晰的视觉体验、满足沉浸感的要求、适应透镜放大效应以及适应更广泛的可视角度&#xff0c;超高分辨率的优势如下&#xff1a; 提供更清晰的视觉体验&#xff1a;VR头显的分辨率直接决定了用户所看到的图像的清晰度。更高的分辨率意…

微服务改造启动多个 SpringBoot 的陷阱与解决方案

在系统运行了一段时间后&#xff0c;业务量上升后&#xff0c;生产上发现java应用内存占用过高&#xff0c;服务器总共64G&#xff0c;发现每个SpringBoot占用近12G的内存&#xff0c;我们项目采用微服务架构&#xff0c;有多个springboot应用。 一下子内存就不够用了&#xf…