十、组件(8)

news2025/4/19 10:27:35

本章概要

  • 递归组件
  • 异步更新队列
  • Teleport

10.11.2 递归组件

组件可以在自己的模板中递归调用自身,但这需要使用 name 选项为组件指定一个内部调用的名称。
当调用 Vue.createApp({}).component({})全局注册组件时,这个全局的 ID 会自动设置为该组件的name选项。
递归组件和程序语言中的递归函数调用一样,都需要有一个条件结束递归,否则就会导致无限循环。
例如,可以通过 v-if 指令(表达式计算为假时)结束递归。
以下是一个分类树状显示例子:

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8">
</head>

<body>
	<div id="app">
		<category-component :list="categories"></category-component>
	</div>

	<script src="https://unpkg.com/vue@next"></script>
	<script>
		const CategoryComponent = {
			name: 'catComp',
			props: {
				list: {
					type: Array
				}
			},

			template: `
          			<ul>
          				<!-- 如果list为空,表示没有子分类了,结束递归 -->
          				<template v-if="list">
        						<li v-for="cat in list">
        							{{cat.name}}
        							<catComp :list="cat.children"/>
        						</li>
        					</template>
          			</ul>
          			`
		}
		const app = Vue.createApp({
			data() {
				return {
					categories: [
						{
							name: '程序设计',
							children: [
								{
									name: 'Java',
									children: [
										{ name: 'Java SE' },
										{ name: 'Java EE' }
									]
								},
								{
									name: 'C++'
								}
							]
						},
						{
							name: '前端框架',
							children: [
								{ name: 'Vue.js' },
								{ name: 'React' }
							]
						}]
				}
			},
			components: {
				CategoryComponent
			}
		}).mount('#app');
	</script>
</body>

</html>

渲染结果如下:
在这里插入图片描述

10.11.3 异步更新队列

代码如下:

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8">
</head>

<body>
	<div id="app">
		<my-component></my-component>
	</div>

	<script src="https://unpkg.com/vue@next"></script>
	<script>
		const app = Vue.createApp({});
		app.component('my-component', {
			data() {
				return {
					message: '无限恐怖'
				}
			},
			methods: {
				change() {
					this.message = '无限曙光';
					console.log(this.$refs.msg.textContent);
				}
			},
			template: `
              	<div>
              		<p ref="msg">{{ message }}</p>
              		<button @click="change">修改内容</button>
              	</div>`
		})

		app.mount('#app');
	</script>
</body>

</html>

代码很简单,当点击“修改内容”按钮时,修改组件 message 数据属性的值,然后在 Console 窗口中输出组件模板中 p 元素的文本内容。

按理说,p 元素的内容就是 message 属性的值,修改了 message 属性的值,在 change() 方法中理应输出修改后的值,但实际上输出的是“无限恐怖”。

这是因为 Vue 在数据变化需要更新 DOM 时并不是同步执行,而是异步执行的。每当侦听到数据更改时,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。

如果同一个观察者被多次触发,只会将其放入队列中一次。Vue在缓冲时会去除重复数据,这样可以避免不必要的计算 和 DOM 操作。

然后,在下一个时间循环tick中,Vue 刷新队列并执行实际的工作。Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate ,如果执行环境不支持,则会采用 setTimeout(fn,0)代替。

对于本例,当在change() 方法中修改 message 属性值的时候,该组件不会立即重新渲染。当队列刷新时,组件会在下一个 tick 中更新。多数情况下,不需要关心这个过程,但是如果想在数据更改后立即访问更新后的 DOM ,这时就需要用到 Vue.nextTick(callback) 方法,传递给 Vue.nextTick() 方法的回调函数会在 DOM 更新后完成被调用。

修改上述代码,如下:

change() {
  this.message = '无限曙光';
  Vue.nextTick(() => console.log(this.$refs.msg.textContent))
}

使用浏览器在此访问页面,单击“修改内容”按钮,在 Console 窗口中的输出为 “无限曙光”。

除了使用全局的 Vue.nextTick() 方法外,在组件内部还可以使用实例的 nextTick() 方法,这样在回调函数中的 this 会自动绑定到当前组件实例上,而不是像上面的代码需要使用箭头函数来绑定 this 到组件实例。

change() {
  this.message = '无限曙光';
  this.$nextTick(function () {
    console.log(this.$refs.msg.textContent);
  })
}

10.11.4 Teleport

Vue 可以通过将 UI 和相关行为封装到组件中构建 UI ,组件之间可以嵌套,从而构成一个 UI 数。

然而,有事组件模板的一部分在逻辑上属于该组件,但从技术角度来看,应该将模板的这一部分移到 DOM 中的其它地方,位于 Vue 应用程序实例之外。

一个常见的场景是创建一个包含全屏模态的组件。在大多数情况下,模态的逻辑都存在于组件中的,但是我们会发现,模态的定位很难通过 CSS 来解决,我们不得不考虑对组件进行拆分。

Vue 3.0 官网给出了一个例子,有如下的 HTML 结构:

<body>
    <div id="app" style="position: relative;">
        <h3>Tooltips with Vue 3 Teleport</h3>
        <div>
            <modal-button></modal-button>
        </div>
    </div>
</body>

modal-button 组件在嵌套很深的 div 元素中渲染。modal-button 组件代码如下:

const app = Vue.createApp({});
  app.component('modal-button', {
    template: `
        <button @click="modalOpen = true">
            Open full screen modal! (With teleport!)
        </button>

        <div v-if="modalOpen" class="modal">
            <div>
                I am a modal !
                <button @click="modalOpen = false">
                    Close
                </button>
            </div>
        </div>
    `,
    data() {
        return { 
            modalOpen: false
        }
    }
})

运行结果如下:
在这里插入图片描述

modal-button 组件有一个 button 元素触发模态的打开,以及一个具有 .modal 样式类的 div 元素,它包含模态的内容和一个用于自我关闭的按钮。

.modal 样式类使用了一个样式表属性“position:absolute”,当 modal-button 组件在上面的 HTML 结构中渲染时,会发现由于模态在嵌套很深的 div 中渲染,样式属性 position:absolute 将相对于父级 div 元素应用。为了解决这个问题,Vue 3.0 给出了一个内置组件 teleport ,该组件允许控制在 DOM 中的哪个节点下渲染 HTML 片段。

teleport 组件有两个 prop ,如下:

  • to:字符串类型,必须的 prop 。其值必须是有效的查询选择器或 HTML 的元素名(如果在浏览器的环境中使用)。teleport 组件的内容将被移动到指定的目标元素中。
  • disabled:布尔类型,可选的 prop 。disabled 可以用于禁用 teleport 组件的功能,这意味着它的插槽内容将不会被移动到任何位置,而是在周围父组件中指定 teleport 的地方渲染。

修改 modal-button 组件的代码,使用 teleport 来告诉 Vue “将这个 HTML 传送到 body 标签下”。代码所示如下:

const app = Vue.createApp({});
app.component('modal-button', {
    template: `
        <button @click="modalOpen = true">
            Open full screen modal! (With teleport!)
        </button>

        <teleport to="body">
            <div v-if="modalOpen" class="modal">
                <div>
                    I'm a teleported modal! 
                    (My parent is "body")
                    <button @click="modalOpen = false">
                        Close
                    </button>
                </div>
            </div>
        </teleport>
    `,
    data() {
        return { 
            modalOpen: false
        }
    }
})

现在,当单机“Open full screen modal! (With teleport!)”按钮,Vue 会正确地将模态的内容在body标签下渲染。运行结果如下:
在这里插入图片描述

如果 teleport 的内容中包含了 Vue 组件,那么该组件在逻辑上仍是 teleport 父组件的子组件。代码如下:

const app = Vue.createApp({
    template: `
    <h1>Root instance</h1>
    <parent-component></parent-component>
    `
});
app.component('parent-component', {
    template: `
    <h2>This is a parent component</h2>
    <teleport to='#endofbody'>
        <child-component name="John"/>
    </teleport>
    `
})
app.component('child-component', {
    props:['name'],
    template: `
    <div>hello,{{ name }}</div>
    `
})
app.mount('#app');

不管 child-component 组件在什么位置渲染,它仍是 parent-component 组件的子组件,并且从父组件接收 name prop 。这意味着来自父组件的注入将按预期工作,并且子组件将嵌套在 Vue Devtools 中父组件之下,而不是放在实际内容移动到的位置。

一个常见的用例场景是一个可重用的 Modal 组件,其中可能同时有多个活动实例。对于这种情况,多个 teleport 组件可以将他们的内容挂载到同一个目标元素下。挂载顺序将是一个简单的追加,代码如下:

<teleport to="#modals">
    <div>A</div>
</teleport>
<teleport to="modals">
    <div>B</div>
</teleport>
<!-- 结果 -->
<div id="modals">
    <div>A</div>
    <div>B</div>
</div>

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

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

相关文章

【云原生】Docker的基本使用方法与优势

&#x1f36c;Docker的基本使用方法和优势&#x1f959;一、简介&#x1f96a;二、优势&#x1f32e;三、基本使用&#x1f959;一、简介 Docker是基于Go语言实现的开源应用容器引擎&#xff0c;通过对应用组件的封装、分发、部署、运行等生命周期的管理&#xff0c;使用户的应…

配置Mysql与注册登录模块

后端职责可以粗浅的理解为处理各种数据&#xff0c;那么处理数据就可以从下面几个方面考虑&#xff1a; 数据的来源 根据不同的数据来源&#xff0c;我们探究两个方面的内容&#xff1a; 数据的形式 数据的操作 当然&#xff0c;一通操作以后&#xff0c;各个…

操作系统:进程与线程大解析

一文就懂进程与线程一、进程/线程相关概念进程中断并发与并行并发并行线程线程分类多进程和多线程上下文进程上下文进程上下文切换的场景线程上下文扩展&#xff1a;协程线程与协程的区别&#xff1a;协程的优势&#xff1a;二、进程/线程区别与关系进程和线程的区别进程和线程…

【C/C++】你知道位段吗?段位?不,是位段!

本章重点 什么是位段&#xff1f; 位段的内存分配 位段的跨平台问题 位段的应用 上一篇文章我详细介绍了第一种自定义类型--结构体。本章节我们认识一下另外一种自定义类型-- 位段。因为讲解位段时需要用到一点结构体的知识&#xff0c;所以我直接把链接放到这里可按需直接…

Swagger

一、Swagger简介 1.1、前言 前后端分离 Vue SpringBoot 当前主流的前后端分离技术栈 后端时代 前端只用管理静态页面&#xff0c;如html&#xff0c;其余的交给后端&#xff0c;而后端通过模板引擎&#xff0c;如jsp进行管理 前后端分离时代 后端&#xff1a;后端控制层&…

jsp健身房会员管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 健身房会员管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql&#xff0c;…

S7-200SMART PLC模拟量应用及创建库文件的具体方法

S7-200SMART PLC模拟量应用及创建库文件的具体方法 具体使用方法可参考以下内容: 模拟量计算公式: OUT = (In_chx - In_RawMin) * (In_EuMax - InEuMin) / (In_RawMax -In_RawMin) + In_EuMin 其中: OUT:转换后的实际值; In_chx:模拟量采集值; In_RawMax:原始数据的最大…

小侃设计模式(九)-组合模式

1.概述 组合模式&#xff08;Composite Pattern&#xff09;又叫部分整体模式&#xff0c;它创建了对象组的树形结构&#xff0c;将对象组合成树状结构以表示“整体-部分”的层析关系&#xff0c;使用户对单个对象和组合对象具有一致的访问性&#xff0c;是结构型设计模式的一…

Windows下一键搭建MBP系统,支持多种版本任意选择,免费永久使用,多系统使用新方案

Windows下一键搭建MBP系统,支持多种版本任意选择,免费永久使用,多系统使用新方案。 安装起来相当的简单,简单到只需要执行一行命令即可完成。使得游戏和开发可以兼顾,并且不用花费数万米的可以使用MBP。不仅如此,经过各项专业的测试,还有接近于原生的MBP系统性能。 效…

WinHex(二)

目录 1.我们打开WinHex&#xff0c;点击打开磁盘按钮 2.不同的文件在WinHex中有不同的文件显示 3.WinHex简单使用 4.删除之前所创建的虚拟磁盘 1.我们打开WinHex&#xff0c;点击打开磁盘按钮 2.不同的文件在WinHex中有不同的文件显示 3.WinHex简单使用 4.删除之前所创建的虚拟…

Java—Double类型进行加减乘除出错(精度)问题

前言&#xff1a; 我们知道&#xff0c;计算机在计算数据过程中都要先把源代码翻译成二进制的机器码&#xff0c;然后再进行相关的运算。然而在转换的过程中&#xff0c;有些十进制数无法用一个有限的二进制数来表示&#xff0c;就是说转换的时候出现了精度的丢失问题&#xff…

模型部署遇到的问题

1.不是有效的Win32应用程序 更改项目中的配置类型&#xff1a; 从网上下载的工程&#xff0c;之前人家是用来封装成库&#xff08;dll&#xff09;的&#xff0c;改成exe就好了。 vs学习问题 关于打开程序时不是有效的Win32应用程序_Lay_Nobody的博客-CSDN博客_vs不是有效的wi…

Spring Boot开发之SpringSercurity(续)

Spring Boot开发之SpringSercurity 一、授权1、打开上次项目以及数据库2、有的页面不登录也能访问&#xff0c;比如首页、登录以及注册等&#xff0c;因此对于某些请求不需要登录则放行这些接口(1)修改MySercurityConfig(2)修改TestController类(3)点击运行&#xff0c;在没登录…

数据抓取工具有哪些-数据抓取工具免费推荐的有哪些

随着社会的进步&#xff0c;科技的发展。不管是企业还是个人都清楚地明白了数据的重要性。不仅可以让我们掌握一手资源&#xff0c;同时还能通过数据更清楚竞争对手。同时也告别了手动复制粘贴的痛苦。 企业人员 通过爬取动态网页数据分析客户行为拓展新业务&#xff0c;分析…

java毕业设计健民中医药方网设计(附源码、数据库)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis Maven Vue 等等组成&#xff0c;B/…

NC5 二叉树根节点到叶子节点的所有路径和

描述 给定一个二叉树的根节点root&#xff0c;该树的节点值都在数字0−9 之间&#xff0c;每一条从根节点到叶子节点的路径都可以用一个数字表示。 1.该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点 2.叶子节点是指没有子节点的节点 3.路径只能从父节点到子节点…

java命令中的options

1. Java命令概述 安装JDK时&#xff0c;会使用java -version查看JDK版本&#xff0c;并验证安装是否成功直接输入java&#xff0c;会给出java命令的使用说明 -options&#xff1a;可选&#xff0c;java命令的命令行选项&#xff0c;多个选项使用空格分隔class&#xff1a;要启…

新人一看就懂:Dubbo3 + Nacos的RPC远程调用框架demo

文章目录一、前言Feign和Dubbo到底有啥区别&#xff0c;为啥大厂都爱用RPC框架&#xff1f;二、简介三、dubbo-api&#xff08;对外暴漏的接口&#xff09;1、pom依赖2、TestService接口四、dubbo-provider&#xff08;服务提供者&#xff09;1、pom依赖2、TestServiceImpl实现…

HCIP-Datacom OSPF进阶(一) 最常用的动态路由协议

目录 OSPF&#xff1a;开放式最短路径优先 OSPF配置方法&#xff1a; OSPF报文头部&#xff1a; OSPF报文类型&#xff1a; OSPF状态机&#xff1a; DR与BDR的作用&#xff1a; 设置选举DR时的优先级&#xff1a; OSPF的网络类型&#xff1a; 修改OSPF接口网络类型命令…

java毕业设计教学平台(附源码、数据库)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis Maven Vue 等等组成&#xff0c;B/…