前端_Vue_9.模板引用、组件基础

news2024/12/30 3:06:07

文章目录

  • 一、模板引用
    • 1.1. 访问模板引用
    • 1.2. v-for 中的模板引用
    • 1.3. 函数模板引用
    • 1.4. 组件上的 ref
    • 1.5. 小结
  • 二、组件基础 ⭐
    • 2.1. 定义一个组件
    • 2.2. 使用组件
    • 2.3. 传递props
    • 2.4. 监听事件
    • 2.5. 通过插槽(slot)来分配内容
    • 2.6. 动态组件
    • 2.7. DOM模板解析注意事项 🔺
      • 2.7.1. 大小写区分
      • 2.7.2. 闭合标签


一、模板引用

虽然Vue的声明性渲染模型为你抽象了大部分对DOM的直接操作,但在某些情况下,我们仍然需要直接访问底层DOM元素。

声明性渲染
关于声明性,前期遇到时已经做过简单介绍。而这边官方文档的语句再次暴露了声明性渲染的一些特点,即抽象了大部分对DOM的直接操作,简单讲就是我们只要指定模板挂载到哪里,而不需要直接在操作模板中各个元素的细节(因为这部分在底层或者说后台已经做好了)。

要实现这一点,我们可以使用特殊的 ref attribute:

<input ref="input">

ref 是一个特殊的attribute,和 v-for 章节中提到的 key 类似。它允许我们在一个特定的DOM元素或子组件实例被挂载后,获得对它的直接引用。这可能很有用,比如说在组件挂载时将焦点设置到一个input元素上,或在一个元素上初始化一个第三方库。

1.1. 访问模板引用

挂载结束后引用都会暴露在 this.$refs 之上:

<script>
export default {
	mounted() {
		this.$refs.input.focus()
	}
}
</script>

<template>
	<input ref="input" />
</template>

注意,你只可以在组件挂载后才能访问模板引用。如果你想在模板中的表达式上访问 $refs.input ,在初次渲染时会是 null 。这是因为在初次渲染前这个元素还不存在!

1.2. v-for 中的模板引用

当在 v-for 中使用模板引用时,相应的引用中包含的值是一个数组:

<script>
export default {
	data() {
		return {
			list: [
				/* ... */
			]
		}
	},
	mounted() {
		console.log(this.$refs.items)
	}
}
</script>

<template>
	<ul>
		<li v-for="item in list" ref="items">
			{{ item }}
		</li>
	</ul>
</template>

应该注意的是,ref 数组并不保证与源数组相同的顺序。

1.3. 函数模板引用

除了使用字符串值作名字,ref attribute 还可以绑定为一个函数,会在每次组件更新时都被调用。该函数会收到元素引用作为其第一个参数:

<input :ref="(el) => { /* 将el赋值给一个数据属性或 ref 变量 */ }" >

注意我们这里需要使用动态的 :ref 绑定才能够传入一个函数。当绑定的元素被卸载时,函数也会被调用一次,此时的 el 参数会是 null 。你当然也可以绑定一个组件方法而不是内联函数。

1.4. 组件上的 ref

模板引用也可以被用在一个子组件上。这种情况下引用中获得的值是组件实例:

<script>
import Child from './Child.vue'

export default {
	components: {
		Child
	},
	mounted() {
		// this.$refs.child 是 <Child />组件的实例
	}
}
</script>

<template>
	<Child ref="child" />
</template>

如果一个子组件使用的是选项式API,被引用的组件实例和该子组件的 this 完全一致,这意味着父组件对子组件的每一个属性和方法都有完全的访问权。这使得在父组件和子组件之间创建紧密耦合的实现细节变得很容易,当然也因此,应该只在绝对需要时才使用组件引用。大多数情况下,你应该首先使用标准的 props 和 emit 接口来实现父子组件交互。

expose 选项可以用于限制对子组件实例的访问:

export default {
	expose: ['publicData', 'publicMethod'],
	data() {
		return {
			publicData: 'foo',
			privateData: 'bar'
		}
	},
	methods: {
		publicMethod() {
			/* ... */
		},
		privateMethod() {
			/* ... */
		}
	}
}

在上面这个例子中,父组件通过模板引用访问到子组件实例后,仅能访问 publicData 和 publicMethod 。

1.5. 小结

看完模板引用章节后,对模板引用小结一下。

  • 从写法上来讲, ref attribute 就是模板引用,它可以获得挂载后的DOM元素或组件实例的引用。它是用于访问底层模板中的DOM元素的。

    你可能会问“我加个id=‘xxx’,不就可以通过id访问了?”
    这个问题先不回答行或不行。
    其实在Vue中获取DOM的方法并不止一种,但官方推荐的是这种。所以现阶段,使用这种即可。

二、组件基础 ⭐

组件允许我们将UI划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。在实际应用中,组件常常被组织成层层嵌套的树状结构:
在这里插入图片描述
这和我们嵌套 HTML 元素的方式类似, Vue 实现了自己的组件模型,使我们可以在每个组件内封装自定义内容与逻辑。 Vue 同样也能很好地配合原生 Web Component。

2.1. 定义一个组件

当使用构建步骤时,我们一般会将 Vue 组件定义在一个单独的 .vue 文件中,这被叫做单文件组件(简称SFC):

<script>
export default {
	data() {
		return {
			count: 0
		}
	}
}
</script>

<template>
	<button @click="count++">You clicked me {{ count }} times.</button>
</template>

当不使用构建步骤时,一个 Vue 组件以一个包含 Vue 特定选项的 JavaScript 对象来定义:

export default {
	data() {
		return {
			count: 0
		}
	},
	template:`
		<button @click="count++">
			You clicked me {{ count }} times.
		</button>`
}

这里的模板是一个内联的 JavaScript 字符串,Vue将会在运行时编译它。你也可以使用ID选择器来指向一个元素(通常是原生的 <template> 元素),Vue将会使用其内容作为模板来源。

上面的例子中定义了一个组件,并在一个 .js 文件里默认导出了它自己,但你也可以通过具名导出在一个文件中导出多个组件。

2.2. 使用组件

提示
接下来的指引中都使用SFC语法,无论你是否使用构建步骤,组件相关的概念都是相同的。

要使用一个子组件,我们需要在父组件中导入它。假设我们把计数器组件放在了一个叫做 ButtonCounter.vue 的文件中,这个组件将会以默认导出的形式被暴露给外部。

<script>
import ButtonCounter from './ButtonCounter.vue'

export default {
	components: {
		ButtonCounter
	}
}
</script>

<template>
	<h1>Here is a child component!</h1>
	<ButtonCounter />
</template>

若要将导出的组件暴露给模板,我们需要在 components 选项上注册它。这个组件将会以注册时的名字作为模板中的标签名。

当然,你也可以全局地注册一个组件,使得它在当前应用中的任何组件上都可以使用,而不需要额外再导入(import)。关于组件的全局注册和局部注册两种方式的利弊,后面组件注册章节中专门讨论。

组件可以被重用任意多次:

<h1>Here is a child component!</h1>
<ButtonCounter />
<ButtonCounter />
<ButtonCounter />

你会注意到,每当点击这些按钮时,每一个组件都维护着自己的状态,是不同的 count。这是因为每当你使用一个组件,就创建了一个新的实例。

在单文件组件中,推荐为子组件使用 PascalCase(就是大写开头,不同单词间大写区分的命名方法) 的标签名,以此来和原生的 HTML 元素作区分。虽然原生HTML标签名是不区分大小写的,但 Vue 单文件组件是可以在编译中区分大小写的。我们也可以用 />来关闭一个标签。

如果你是直接在DOM中书写模板(例如原生 <template>元素的内容),模板的编译需要遵从浏览器中HTML的解析行为。在这种情况下,你应该需要使用 kebab-case 形式并显式地关闭这些组件的标签。

<!-- 如果是在 DOM 中书写该模板 -->
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>

2.3. 传递props

从命名上来看,prop大概是property的缩写,可以认为是属性的意思。

如果我们正在构建一个博客,我们可能需要一个表示博客文章的组件。我们希望所有的博客文章共享相同的视觉布局,但内容不同。要实现这样的效果自然必须向组件中传递数据,例如每篇文章标题和内容,这就会用到props。

Props是一种特别的 attributes,你可以在组件上声明注册。要传递给博客文章组件一个标题,我们必须在组件的props列表上声明它。这里要用到 props 选项:

<!-- BlogPost.vue -->
<script>
export default {
	props: ['title']
}
</script>

<template>
<h4>{{ title }}</h4>
</template>

当一个值被传递给 prop 时,它将成为该组件实例上的一个属性。该属性的值可以像其他组件属性一样,在模板和组件的 this 上下文中访问。

一个组件可以有任意多的 props ,默认情况下,所有 prop 都接受任意类型的值。

当一个 prop 被注册后,可以像这样以自定义 attribute 的形式传递数据给它:

<BlogPost title="My journey with Vue" />
<BlogPost title="Blogging with Vue" />
<BlogPost title="Why Vue is so fun" />

在实际应用中,我们可能在父组件中会有如下的一个博客文章数组:

export default {
	// ...
	data() {
		return {
			posts: [
				{ id: 1, title: 'My journey with Vue' },
				{ id: 2, title: 'Blogging with Vue' },
				{ id: 3, title: 'Why Vue is so fun' }
			]
		}
	}
}

这种情况下,我们可以使用 v-for 来渲染它们:

<!--template-->
<BlogPost
	v-for="post in posts"
	:key="post.id"
	:title="post.title"
	/>

留意我们是如何使用 v-bind 来传递动态prop值的。当事先不知道要渲染的确切内容时,这一点特别有用。

2.4. 监听事件

继续关注上面的 <BlogPost>组件。有时候我们需要它和父组件进行交互。例如,要在此处实现A11y(Accessibility )的需求,将博客文章的文字放大,而页面的其余部分仍使用默认字号。

在父组件中,我们可以添加一个 postFontSize 数据属性来实现这个效果:

data() {
	return {
		posts: [
			/* ... */
		],
		postFontSize: 1
	}
}

在模板中用它来控制所有博客文章的字体大小:

<!--template-->
<div :style="{ fontSize: postFontSize + 'em' }">
	<BlogPost
		v-for="post in posts"
		:key="post.id"
		:title="post.title"
	/>
</div>

然后,给 <BlogPost>组件添加一个按钮:

<!--BlogPost.vue,省略了<script>-->
<template>
	<div class="blog-post">
		<h4>{{ title }}</h4>
		<button>Enlarge text</button>
	</div>
</template>

这个按钮目前还没有做任何事情,我们想要点击这个按钮开告诉父组件它应该放大所有博客文章的文字。要解决这个问题,组件实例提供了一个自定义事件系统。父组件可以通过 v-on 或 @ 来选择性地监听子组件上抛的事件,就像监听原生 DOM 事件那样:

<BlogPost
	...
	@enlarge-text="postFontSize += 0.1"
	/>

子组件可以通过调用内置的 $emit 方法,通过传入事件名称来抛出一个事件:

<!-- BlogPost.vue,省略了<script> -->
<template>
	<div class="blog-post">
		<h4>{{ title }}</h4>
		<button @click="$emit('enlarge-text')">Enlarge text</button>
	</div>
</template>

因为有了 @enlarge-text=“postFontSize += 0.1”的监听,父组件会接收这一事件,从而更新 postFontSize 的值。

我们可以通过 emits 选项来声明需要抛出的事件:

<!-- BlogPost.vue -->
<script>
export default {
	props: ['title'],
	emits: ['enlarge-text']
}
</script>

这声明了一个组件可能触发的所有事件,还可以对事件的参数进行验证。同时,这还可以让Vue避免将它们作为原生事件监听器隐式地应用于子组件的根元素(?)。

总之,子组件上声明事件和触发事件;父组件上监听事件即可。

2.5. 通过插槽(slot)来分配内容

一些情况下,我们会希望能和HTML元素一样向组件中传递内容:

<AlertBox>
	Something bad happened.
</AlertBox>

我们期望能渲染成这样:
在这里插入图片描述
这可以通过 Vue 的自定义<slot>元素来实现:

<template>
	<div class="alert-box">
		<strong>This is an Error for Demo Purposes</strong>
		<slot />
	</div>
</template>

<style scoped>
.alert-box {
	/* ... */
}
</style>

如上所示,我们使用 <slot> 作为一个占位符,父组件传递进来的内容就会渲染在这里。

2.6. 动态组件

有些场景会需要在两个组件间来回切换,比如Tab界面:

<script>
import Home from './Home.vue'
import Posts from './Posts.vue'
import Archive from './Archive.vue'
export default {
  components: {
    Home,
    Posts,
    Archive
  },
  data() {
    return {
      currentTab: 'Home',
      tabs: ['Home', 'Posts', 'Archive']
    }
  }
}
</script>

<template>
  <div class="demo">
    <button
       v-for="tab in tabs"
       :key="tab"
       :class="['tab-button', { active: currentTab === tab }]"
       @click="currentTab = tab"
     >
      {{ tab }}
    </button>
	  <component :is="currentTab" class="tab"></component>
  </div>
</template>

在这里插入图片描述
上面例子是通过 Vue 的 <component>元素和特殊的 is attribute 实现的:

<!-- currentTab 改变时组件也改变 -->
<component :is="currentTab"></component>

在上面例子中,被传给 :is 的值可以是以下几种:

  • 被注册的组件名
  • 导入的组件对象

你也可以使用 is attribute 来创建一般的 HTML 元素。
当使用 <component :is=“…”> 来在多个组件间作切换时,被切换掉的组件会被卸载。我们可以通过 <keepAlive> 组件强制被切换掉的组件仍然保持 “存活” 的状态。

2.7. DOM模板解析注意事项 🔺

如果你想在 DOM 中直接书写 Vue 模板,Vue则必须从 DOM 中获取模板字符串。由于浏览器的原生 HTML 解析行为限制,有一些需要注意的事项。

提示
下面讨论只适用于直接在DOM中编写模板的情况。如果你使用来自以下来源的字符串模板,就不需要顾虑这些限制了:

  • 单文件组件
  • 内联模板字符串(例如 template: ‘…’)
  • <scirpt type=“text/x-template”>

由于前期学习使用的是单文件组件,所以本节内容暂时略过,后期有需要再回来学习。

2.7.1. 大小写区分

HTML 标签和属性名称是不分大小写的,所以浏览器会把任何大写的字符解释为小写。这意味着当你使用DOM内的模板时,无论是 PascalCase 形式的组件名称、camelCase形式的prop名称还是 v-on 的事件名称,都需要转换为相应等价的 kebab-case(短横线连字符)形式:

// JavaScript 中的 camelCase
const BlogPost = {
	props: ['postTitle'],
	emits: ['updatePost'],
	template:`
		<h3>{{ postTitle }}</h3>
	`
}
<!-- HTML 中的 kebab-case -->
<blog-post post-title="hello!" @update-post="onUpdatePost"></blog-post>

2.7.2. 闭合标签

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

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

相关文章

go 库 Cobra 现代化的命令行框架

go 库 Cobra 现代化的命令行框架 文章目录go 库 Cobra 现代化的命令行框架1. 简介2. 主要功能3. 应用举例4. Cobra 安装5. 使用 Cobra 库创建命令5.1 创建 rootCmd5.2 创建 main.go5.3 添加命令5.4 编译并运行6. 特性6.1 使用标志6.2 非选项参数验证6.3 PreRun and PostRun Hoo…

手绘图说电子元器件-电声转换器件

电声转换器件包括能够将电信号转换为声音的扬声器、耳机、讯响器和蜂鸣器,能够将声音转换为电信号的传声器,能够进行电磁转换的磁头和具有压电效应的晶体等。 扬声器 扬声器俗称喇叭,是一种常用的电声转换器件,其基本作用是将电信号转换为声音,在收音机、录音机、电视机…

Linux | 套接字(socket)编程 | TCP协议讲解 | 通信模型搭建

文章目录TCP模型的特性TCP接口介绍TCP服务器套接字设置TCP客户端套接字设置TCP模型的特性 TCP是属于传输层协议的一种&#xff0c;上篇博客介绍了另一种传输层协议——UDP&#xff0c;关于它们之间的区别&#xff0c;这里再提一下 TCPUDP传输层协议传输层协议有连接无连接可靠…

Word控件Spire.Doc 【评论】教程(3):在C#、VB.NET中从Word文档中提取注释并保存在TXT文件中

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

[Leetcode] 合并两个有序数组、链表

1.合并两个有序数组 原地合并数组&#xff0c;即不使用额外的空间 --> 使用三个指针&#xff0c;从尾部往前处理 题目链接&#xff1a;https://leetcode.cn/problems/merge-sorted-array/ nums1 总长度 mn&#xff0c;自身长度m&#xff1b;nums2 自身长度n&#xff0c; 使…

SSRF渗透与攻防(一)

目录 前言 SSRF是什么 危害&#xff08;利用方式): SSRF漏洞原理&#xff1a; CURL协议&#xff1a; SSRF常见场景 社会化分享功能&#xff1a; 如何发现SSRF漏洞 工具利用&#xff1a; 如何防御SSRF漏洞 前言 SSRF(Server-Side Request Forgery:服务器端请求伪造) 是…

rocketmq 实战问题汇总

rocketmq 实战过程会遇到这样或者那样的问题&#xff0c;今天我们专门抽出一篇文章来分析一下汇总一下&#xff0c;避免以后踩同样的坑&#xff1a; 1、找不到JDK的问题&#xff1a; 综合分析&#xff0c;是因为JDK安装的目录有空格导致的&#xff1a;Program Files 两个单词之…

电子招标采购系统源码—企业战略布局下的采购寻源

​ 智慧寻源 多策略、多场景寻源&#xff0c;多种看板让寻源过程全程可监控&#xff0c;根据不同采购场景&#xff0c;采取不同寻源策略&#xff0c; 实现采购寻源线上化管控&#xff1b;同时支持公域和私域寻源。 询价比价 全程线上询比价&#xff0c;信息公开透明&#xff0…

CANoe—基于DoIP通过CAPL实现与ECU通信测试

如下连接是在CANoe中基于DoIP通过加载诊断数据库实现CANoe与待测ECU诊断通信: CANoe链接 本文继续此话题,通过一个简单的CAPL Demo,实现CANoe与ECU进行DoIP通信。 首先在CANoe新建Ethernet工程: 在CANoe “Simulation Setup”中新建CAPL Test Module: 在此例中采用CANo…

DHCP原理和实验

目录 DHCP基本认识和原理 场景一、同网段DHCP 场景二、不同段DHCP&#xff08;中继DHCP&#xff09; DHCP基本认识和原理 DHCP&#xff08;Dynamic Host Configuration Protocol动态主机协议&#xff09;。 作用&#xff1a;为局域网络中主机动态分发地址&#xff0c;以及…

C#里使用ExcelDataReader读取EXCEL文件的简单方法

C#里使用ExcelDataReader读取EXCEL文件的简单方法 读取EXCEL文件是比较常见的需求,所以在C#里也会经常遇到。 比如客户需要保存的条码数据,他们可以使用EXCEL来扫码进去,并且进行修改和核验, 然后软件就需要读取这些EXCEL文件,并且从这里得到所需要的条码。 要从EXCEL里…

Android 查看隐私权限方法调用者集合

背景 辛辛苦苦迭代完当前版本&#xff0c;准备推送 App 到应用市场上架&#xff0c;却收到拒审通知&#xff1a;App隐私合规上架护航版检测报告&#xff0c; 报告内容&#xff1a; 场景2:APP以隐私政策弹窗的形式向用户明示收集使用规则&#xff0c;未经用户同意&#xff0c;…

页面崩溃了!记录一次测试中出现的前端内存溢出现象

前情回顾 前几天在一次web应用测试过程中&#xff0c;前端发起了向后端接口的查询请求&#xff0c;由于后端响应较慢&#xff0c;前端一直处于等待响应返回状态。在几分钟后&#xff0c;突然页面出现让人惊悚的“噢噢&#xff0c;页面崩溃了”几个大字。 看到这几个字的一瞬间…

基于GitLab构建企业级CICD-Gitlab-Runner

背景 在过往企业开发中&#xff0c;大部分企业从开发到测试&#xff0c;到部署目前还是手工进行在一些某些中大型企业中&#xff0c;目前构建及部署还是直接使用二进制包部署&#xff0c;或直接单机运行在某些场合下&#xff0c;仓库中代码的编译需要硬件支持&#xff0c;致使…

SSM框架学习记录-Maven_day01

1.分模块开发 将原始模块按照功能拆分成若干个子模块&#xff0c;方便模块间的相互调用&#xff0c;接口共享&#xff1a;比如有订单和商品两个模块&#xff0c;它们都需要使用到商品的模型类&#xff0c;如果在这两个模块中都写模型类&#xff0c;就会出现重复代码&#xff0c…

Doris部分列更新在广告行业应用

背景&#xff1a;业务需要在不同的时间点对同一个session_id上的广告行为&#xff08;展示、点击、转换等&#xff09;数据的更新。 基于HBase归因 更新原理&#xff1a;以session_id为Key在HBase中写入数据&#xff0c;数据更新是先点查到历史数据&#xff0c;补齐当前数据后…

风已起,待云涌---多维度理解云安全

Fix the Unknown,Before You Know it. 新时代大门开启的时候&#xff0c;蜂拥而上的大都是勇士&#xff0c;风已起&#xff0c;待云涌&#xff01; 1.云安全&#xff1a; 未来安全的能力将成为计算、存储、网络之外的第四大基础设施&#xff0c;并全部融入到云基础设施中&…

Python爬虫入门 ~ selenium访问元素信息与交互基本使用

访问元素信息 前面我们成功定位到了页面的标签元素&#xff0c;那接下来就该轮到获取元素的信息了&#xff0c;常用的函数有以下几种: get_attributetexttag_name 前置准备 from selenium import webdriver from selenium.webdriver.chrome.service import Service from sel…

【Django项目开发】用户认证功能开发(四)

一、JWT Token配置 1、下载djangorestframework-jwt pip install djangorestframework-jwt2、settings.py指定使用的认证类JSONWebTokenAuthentication REST_FRAMEWORK {# 指定使用的认证类# a、在全局指定默认的认证类&#xff08;认证方式&#xff09;DEFAULT_AUTHENTICA…

企业金融App评测系列——微众银行以App构筑企业金融服务新生态,成为企业的随身数字银行

易观分析&#xff1a;近年来&#xff0c;疫情驱动小微企业线上化需求不断提升&#xff0c;经营面临的财力、人力、信息获取的紧迫性进一步提升。为更好发展普惠小微金融的商业银行对公服务&#xff0c;正聚焦更好满足小微企业的数字化需求&#xff0c;加快打造企业手机银行等移…