首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【Vue.js】017-Vue组件:基本使用、组件注册、父子组件、父子组件通信

【Vue.js】017-Vue组件:基本使用、组件注册、父子组件、父子组件通信

作者头像
訾博ZiBo
发布2025-01-06 15:21:27
发布2025-01-06 15:21:27
5650
举报

一、组件化的实现和使用步骤

1、什么是组件化

人的大脑处理问题的能力是有限的,当人们面对复杂问题的时候,很难一次性解决,但人的大脑也天生具有将问题拆解的能力,化繁为简,逐个解决,这种复杂问题拆解成多个小问题在程序中的表现就是组件化。在程序开发中,如果我们将一个复杂页面的所有逻辑都放在一起,势必导致逻辑混乱,难以阅读,不利于后续的管理和扩展。但如果我们将页面拆解成一个个小的功能块,每个功能块完成自己独立的功能,且这些功能块能够被应用到其他页面(可复用),那么程序的开发就会非常易于管理和扩展。

类似此图:

2、Vue的组件化思想

3、组件的基本步骤

步骤:

创建组件构造器——注册组件——使用组件;

图示:

二、组件化的基本使用过程

1、代码演示

代码语言:javascript
复制
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<!-- 3、使用组件 -->
			<my-cpn></my-cpn>
		</div>
		
		<script src="../../js/vue.js"></script>
		<script>
			//1、创建组件构造器对象
			const cpnC = Vue.extend({
				template:`
					<div>
						<h2>我是二级标题</h2>
						<p>我是P标签</p>
					</div>
				`
			});
			//2、注册组件,传入组件名和组件构造器对象
			Vue.component('my-cpn',cpnC);
			
			
			const app = new Vue({
				el:'#app',
				data:{
					
				}
			})
		</script>
	</body>
</html>

2、运行结果

三、全局组件和局部组件

1、全局组件

在上面《组件化的基本使用过程》中我们所使用的就是全局组件,全局组件意味着可以在多个vue的实例下使用

代码演示:
代码语言:javascript
复制
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<!-- 3、使用组件 -->
			<my-cpn></my-cpn>
		</div>
		
		<div id="app2">
			<my-cpn></my-cpn>
		</div>
		
		<script src="../../js/vue.js"></script>
		<script>
			//1、创建组件构造器对象
			const cpnC = Vue.extend({
				template:`
					<div>
						<h2>我是二级标题</h2>
						<p>我是P标签</p>
					</div>
				`
			});
			//2、注册组件,传入组件名和组件构造器对象
			Vue.component('my-cpn',cpnC);
			
			
			const app = new Vue({
				el:'#app',
				data:{
					
				}
			})
			const app2 = new Vue({
				el:'#app2',
				data:{
					
				}
			})
		</script>
	</body>
</html>
运行结果:

2、局部组件

那么怎么样才能注册局部组件呢?

答案是:在特定的vue实例下注册

代码演示:
代码语言:javascript
复制
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<!-- 3、使用组件 -->
			<my-cpn></my-cpn>
		</div>
		
		<div id="app2">
			<my-cpn></my-cpn>
		</div>
		
		<script src="../../js/vue.js"></script>
		<script>
			//1、创建组件构造器对象
			const cpnC = Vue.extend({
				template:`
					<div>
						<h2>我是二级标题</h2>
						<p>我是P标签</p>
					</div>
				`
			});
			//2、注册组件,传入组件名和组件构造器对象
			// Vue.component('my-cpn',cpnC);
			
			
			const app = new Vue({
				el:'#app',
				data:{
					
				},
				components:{
					// 注意这里的my-cpn要用引号引起
					'my-cpn': cpnC
				}
			})
			const app2 = new Vue({
				el:'#app2',
				data:{
					
				}
			})
		</script>
	</body>
</html>
运行结果(只能用在特定实例之内了):

四、父组件和子组件

1、简单使用

代码演示:
代码语言:javascript
复制
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<!-- 5、使用 -->
			<cpn2></cpn2>
		</div>
		
		<script src="../../js/vue.js"></script>
		<script>
			// 1、创建第一个组件的内容构造器
			const cpnC1 = Vue.extend({
				template:`
					<div>
						<h1>我是标题1</h1>
						<p>我是内容1</p>
					</div>
				`
			})
			
			// 2、创建第二个组件的内容构造器
			const cpnC2 = Vue.extend({
				template:`
					<div>
						<h1>我是标题2</h1>
						<p>我是内容2</p>
						<!-- 注意:这里的cpn1必须放在div之内 -->
						<cpn1></cpn1>
					</div>
				`,
				// 3、在组件的内容构造器中注册组件
				components:{
					'cpn1': cpnC1
				}
			})
			
			const app = new Vue({
				el:'#app',
				data:{
					
				},
				// 4、局部注册
				components:{
					'cpn2': cpnC2
				}
			})
		</script>
	</body>
</html>
运行结果:

五、注册组件语法糖

1、概述

上面我们演示的基本使用注册组件的方式,在新版本的vue中已经不常见了,现在都使用语法糖进行注册;

2、演示

代码语言:javascript
复制
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<!-- 3、使用组件 -->
			<my-cpn></my-cpn>
		</div>
		
		<script src="../../js/vue.js"></script>
		<script>
			// 之前的写法
			//1、创建组件构造器对象
			// const cpnC = Vue.extend({
			// 	template:`
			// 		<div>
			// 			<h2>我是二级标题</h2>
			// 			<p>我是P标签</p>
			// 		</div>
			// 	`
			// });
			//2、注册组件,传入组件名和组件构造器对象
			// Vue.component('my-cpn',cpnC);
			// 语法糖写法:等于是二者的合并
			// 这是全局注册的写法
			Vue.component('my-cpn',{
				template:`
					<div>
						<h2>我是二级标题</h2>
						<p>我是P标签</p>
					</div>
				`
			})
			
			const app = new Vue({
				el:'#app',
				data:{
					
				},
				components:{
					// 这是局部组件的语法糖写法
					'my-cpn': {
						template:`
							<div>
								<h2>我是二级标题</h2>
								<p>我是P标签</p>
							</div>
						`
					}
				}
			})
		</script>
	</body>
</html>

六、组件模板的分离写法

1、概述

我们之前在注册组件的时候,将组件的模板html代码写在vue实例中,如果html代码比较复杂的话会因为文件内容过多而导致混乱;

2、两种写法

代码演示:
代码语言:javascript
复制
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<my-cpn></my-cpn>
		</div>
		<!-- 分离写法方式一 -->
		<!-- <script type="text/x-temolate" id="myCpn">
			<div>
				<h2>我是二级标题</h2>
				<p>我是P标签</p>
			</div>
		</script> -->
		<!-- 分离写法方式二 -->
		<template id="myCpn">
			<div>
				<h2>我是二级标题</h2>
				<p>我是P标签</p>
			</div>
		</template>
		<script src="../../js/vue.js"></script>
		<script>
			Vue.component('my-cpn',{
				template: '#myCpn'
			});
			const app = new Vue({
				el:'#app',
				data:{
					
				}
			})
		</script>
	</body>
</html>
运行结果:

七、组件数据的存放

1、概述

组件对象也有一个data属性,只是这个data属性必须是一个函数,而且这个函数返回一个对象,对象内部保存着数据;

之所以data属性必须是一个函数,是因为当返回的是同一个对象的时,组件多次使用的话会相互影响;

2、代码演示

代码语言:javascript
复制
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			{{message}}
			<my-cpn></my-cpn>
		</div>
		<template id="myCpn">
			<div>
				<h1>{{title}}</h1>
				<p>{{content}}</p>
			</div>
		</template>
		<script src="../../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: '#app',
				data: {
					message: '你好!'
				},
				components:{
					'my-cpn': {
						template: '#myCpn',
						data(){
							return{
								title: "我是标题",
								content: "我是p标签"
							}
						}
					}
				}
			})
		</script>
	</body>
</html>

3、运行结果

八、父子组件的通信

1、概述

在开发中,往往一些数据确实需要从上层传递到下层:比如在一个页面中,我们从服务器请求到了很多的数据。其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。这个时候,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件);

如何进行父子组件间的通信呢?Vue官方提到通过props向子组件传递数据,通过事件向父组件发送消息;

真实的开发中,Vue实例和子组件的通信和父组件和子组件的通信过程是一样的;

2、props基本用法

概述:

在组件中,使用选项props来声明需要从父级接收到的数据;

props的值有两种方式:

方式一:字符串数组,数组中的字符串就是传递时的名称;

方式二:对象,对象可以设置传递时的类型,也可以设置默认值等;

图解:
代码演示:
代码语言:javascript
复制
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			{{message}}
			<my-cpn :title="title" :content="content"></my-cpn>
		</div>
		<template id="myCpn">
			<div>
				<h1>{{title}}</h1>
				<p>{{content}}</p>
			</div>
		</template>
		<script src="../../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: '#app',
				data: {
					message: '你好!',
					title: "我是标题啊",
					content: "我是内容啊"
				},
				components:{
					'my-cpn': {
						template: '#myCpn',
						props:['title','content']
					}
				}
			})
		</script>
	</body>
</html>
运行结果:

3、props数据验证

概述:

在前面,我们的props选项是使用一个数组;

我们说过,除了数组之外,我们也可以使用对象,当需要对props进行类型等验证时,就需要对象写法了。

验证都支持哪些数据类型呢?

String、Number、Boolean、Array、Object、Date、Function、Symbol;

当我们有自定义构造函数时,验证也支持自定义的类型;

自定义类型:
演示:

4、子级向父级传递

概述:

props用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中;

我们应该如何处理呢?这个时候,我们需要使用自定义事件来完成;

什么时候需要自定义事件呢?

当子组件需要向父组件传递数据时,就要用到自定义事件了;

我们之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件;

自定义事件的流程:

在子组件中,通过$emit()来触发事件;

在父组件中,通过v-on来监听子组件事件;

图解:
自定义事件代码演示:
代码语言:javascript
复制
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<!-- 注意:这里的方法不可带括号 -->
			<child-cpn @increment='changeTotal' @decrement='changeTotal'></child-cpn>
			当前值:{{total}}
		</div>
		<template id="myCpn">
			<div>
				<button @click="increment">+1</button>
				<button @click="decrement">-1</button>
			</div>
		</template>
		<script src="../../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: '#app',
				data:{
					total: 0
				},
				methods:{
					changeTotal(counter){
						this.total = counter;
					}
				},
				components:{
					'child-cpn':{
						template: '#myCpn',
						data(){
							return{
								counter: 0
							}
						},
						methods:{
							increment(){
								this.counter++;
								this.$emit('increment',this.counter);
							},
							decrement(){
								this.counter--;
								this.$emit('decrement',this.counter);
							}
						}
					}
				}
			})
		</script>
	</body>
</html>
运行结果:

九、父子组件的访问方式

1、概述

有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问跟组件;

父组件访问子组件:使用children或refs;

子组件访问父组件:使用$parent;

2、$children

概述:

我们先来看下$children的访问:

this.$children是一个数组类型,它包含所有子组件对象;

我们这里通过一个遍历,取出所有子组件的message状态,不常用!

图解(截图大多来自老师的教学PPT):
代码演示:
代码语言:javascript
复制
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<parent-cpn></parent-cpn>
		</div>
		<template id="p1">
			<div>
				<child-cpn1></child-cpn1>
				<child-cpn2></child-cpn2>
				<button @click="showChildCpnMessage">显示所有子组件信息</button>
			</div>
		</template>
		<template id="c1">
			<h1>我是子组件1</h1>
		</template>
		<template id="c2">
			<h1>我是子组件2</h1>
		</template>
		<script src="../../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: "#app",
				components:{
					'parent-cpn':{
						template: '#p1',
						components:{
							'child-cpn1': {
								template: '#c1'
							},
							'child-cpn2': {
								template: '#c2'
							}
						},
						methods:{
							showChildCpnMessage(){
								for(let i=0;i<this.$children.length;i++){
									// 通过下标拿取
									console.log(this.$children[i]);
								}
							}
						}
					},
				}
			})
		</script>
	</body>
</html>
运行结果:

3、$refs

$children的缺陷:

通过$children访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值;

但是当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化;

有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用$refs;

$refs的使用:

$refs和ref指令通常是一起使用的:

首先,我们通过ref给某一个子组件绑定一个特定的ID;

其次,通过this.$refs.ID就可以访问到该组件了;

图解:

4、$parent

概述:

如果我们想在子组件中直接访问父组件,可以通过$parent;

注意事项:

尽管在Vue开发中,我们允许通过$parent来访问父组件,但是在真实开发中尽量不要这样做;

子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高了;

如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题;

另外,更不要做的是通过$parent直接修改父组件的状态,那么父组件中的状态将变得飘忽不定,很不利于我的调试和维护;

图解:

十、非父子组件通信

1、概述

刚才我们讨论的都是父子组件间的通信,那如果是非父子关系呢?

非父子组件关系包括多个层级的组件,也包括兄弟组件的关系;

在Vue1.x的时候,可以通过dispatch和broadcast完成:

$dispatch用于向上级派发事件;

$broadcast用于向下级广播事件;

但是在Vue2.x都被取消了:

在Vue2.x中,有一种方案是通过中央事件总线,也就是一个中介来完成;

但是这种方案和直接使用Vuex的状态管理方案还是逊色很多;

并且Vuex提供了更多好用的功能,所以这里我们暂且不讨论这种方案,后续我们专门学习Vuex的状态管理;

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-01-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、组件化的实现和使用步骤
    • 1、什么是组件化
    • 2、Vue的组件化思想
    • 3、组件的基本步骤
      • 步骤:
      • 图示:
  • 二、组件化的基本使用过程
    • 1、代码演示
    • 2、运行结果
  • 三、全局组件和局部组件
    • 1、全局组件
      • 代码演示:
      • 运行结果:
    • 2、局部组件
      • 代码演示:
      • 运行结果(只能用在特定实例之内了):
  • 四、父组件和子组件
    • 1、简单使用
      • 代码演示:
      • 运行结果:
  • 五、注册组件语法糖
    • 1、概述
    • 2、演示
  • 六、组件模板的分离写法
    • 1、概述
    • 2、两种写法
      • 代码演示:
      • 运行结果:
  • 七、组件数据的存放
    • 1、概述
    • 2、代码演示
    • 3、运行结果
  • 八、父子组件的通信
    • 1、概述
    • 2、props基本用法
      • 概述:
      • props的值有两种方式:
      • 图解:
      • 代码演示:
      • 运行结果:
    • 3、props数据验证
      • 概述:
      • 自定义类型:
      • 演示:
    • 4、子级向父级传递
      • 概述:
      • 什么时候需要自定义事件呢?
      • 自定义事件的流程:
      • 图解:
      • 自定义事件代码演示:
      • 运行结果:
  • 九、父子组件的访问方式
    • 1、概述
    • 2、$children
      • 概述:
      • 图解(截图大多来自老师的教学PPT):
      • 代码演示:
      • 运行结果:
    • 3、$refs
      • $children的缺陷:
      • $refs的使用:
      • 图解:
    • 4、$parent
      • 概述:
      • 图解:
  • 十、非父子组件通信
    • 1、概述
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档