8.vue文档API(5),组件

本文详细介绍了Vue组件的注册、渲染以及组件间通信的方法,包括全局与局部注册、props、$refs、$parent、$children、$root、$slots和$scopedSlots的使用,还探讨了动态组件、transition和keep-alive的特性和应用场景。同时,讲解了组件的name属性、inheritAttrs选项以及functional组件的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

组件:

之前vue实例,必须挂载到一个指定的DOM节点上,这样的话,太过死板,不灵活。所以,就有了组件,可以任意的挂载到一个vue实例下。组件本身,就可以看作是一个vue实例,和vue实例一样,具有生命周期。

注册与渲染:

只用组件之前,需要先注册注册的方式分为两种,一种是全局Vue注册, 这样的话,可以在任意的vue实例下调用该组件;另一种就是局部注册,

具体的实现这里有:https://blog.csdn.net/weixin_47870554/article/details/106946942

组件之间的信息获取:

一般而言,组件是无法获取上级或者下级组件的数据信息的,会警告。如下:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>vueTest</title>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>

	<div id="app">
		<component-demo1></component-demo1>
	</div>
	<script type="text/javascript">
		Vue.config.productionTip = false;
		var demo1 = {
			data: function() {
				return {
					name: 'components'
				}
			},
			template:`<div>
							<p>我想要父组件的信息: {{message}}</p>
						</div>`
		};
		var app = new Vue({
			el: '#app',
			data(){
				return{
					message: 'app'
				}
			},
			components: {
				'component-demo1': demo1,
			},
			template: `<div>
							<p>hello, {{message}}</p>
							<component-demo1></component-demo1>
						</div>`
		});
	</script>
</body>
</html>

组件可以通过props直接接收从标签传递过来的数据。传入的对象,内组件内部可以像data内的数据一样被使用。不过,貌似好像只能传入简单类型的数据。props一般用于实现父子组件之间的简单通信。

$slots插槽,可以在父组件渲染组件的时候,加入html代码,通过这种方式,将相关的数据在组件内显示。

props和$slots案例在这里:https://blog.csdn.net/weixin_47870554/article/details/106946942#t6

除了props和$slots之外,还有provide / inject、$refs、$parent、$children、$scopedSlots等方式获取父子组件之间的信息。

provide / inject

可以接受父级或者更高级的组件传递的数据。代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>vueTest</title>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
	<div id="app">
		<component-demo2></component-demo2>
	</div>
	<script type="text/javascript">
		Vue.config.productionTip = false;
		var demo1 = {
			data: function() {
				return {
					name: 'components'
				}
			},
			inject: ['superior'],
			template:`<div>
							<p>demo1 组件 inject接收数据: </p>
							<p>{{superior}}</p>
						</div>`
		};
		var demo2 = {
			data: function() {
				return {
					message: '这里是中间组件 demo2'
				}
			},
			components: {
				'component-demo1': demo1
			},
			template: `<div>
							<p>hello, {{message}}</p>
							<hr>
							<component-demo1></component-demo1>
						</div>`
		};
		var app = new Vue({
			el: '#app',
			provide: {
				superior: '从高级组件传来的数据'
			},
			components: {
				'component-demo2': demo2,
			}
		});
	</script>
</body>
</html>

$refsref

配合ref特殊属性,可以让父组件获取子组件的元素信息。(需要在生命周期mounted挂载之后才行,且只能获取子组件,不能获取子组件内部的组件信息)

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>vueTest</title>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
	<div id="app">
	</div>
	<script type="text/javascript">
		Vue.config.productionTip = false;
		var demo1 = {
			data: function() {
				return {
					message: '这里是底层组件 demo1'
				}
			},
			template:`<div>
							<p ref="demo1">hi, {{message}}</p>
						</div>`
		};
		var demo2 = {
			data: function() {
				return {
					message: '这里是中间组件 demo2'
				}
			},
			components: {
				'component-demo1': demo1
			},
			template: `<div>
							<p ref='demo2'>hello, {{message}}</p>
							<hr>
							<component-demo1></component-demo1>
						</div>`
		};
		var app = new Vue({
			el: '#app',
			components: {
				'component-demo2': demo2,
			},
			data: function() {
				return {
					message: '这里最初的组件app'
				}
			},
			methods: {
				getRefs(){
					console.log("this.$refs:", this.$refs);
				}
			},
			template: `
				<div ref="template">
					<p ref="message">{{message}}</p>
					<button v-on:click='getRefs'>获取refs</button>
					<hr>
					<component-demo2 ref="component"></component-demo2>
				</div>
			`,

		});
	</script>
</body>
</html>

只获取了本身template内的元素或者组件信息,组件内部的信息不能直接通过$refs获取。

$parent、$children、$root:

$parent、$children获取父组件或者子组建的vue实例信息。$root获取最上层地组件,如果不存在,就是自己。

$parent、$children部分代码:

methods: {
	getParent(){
		console.log("this.$parent:", this.$parent);
	},
	getChildren(){
		console.log("this.$children:", this.$children);
	}
},
template: `<div>
				<p ref='demo2'>hello, {{message}}</p>
			<button v-on:click='getParent'>获取parent</button>
			<button v-on:click='getChildren'>获取children</button>
				<hr>
				<component-demo1 ref='componentDemo2'></component-demo1>
			</div>`

 $root部分代码:

methods: {
	getRoot(){
		console.log("this.$root:", this.$root);
	}
},
template:`<div>
				<p ref="demo1">hi, {{message}}</p>
				<button v-on:click='getRoot'>获取root</button>
			</div>`

$scopedSlots、$slots:

$scopedSlots、$slots可用于获取从父组件处获取地插槽信息。($scopedSlots返回的是函数集)

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>vueTest</title>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
	<div id="app">
	</div>
	<script type="text/javascript">
		Vue.config.productionTip = false;
		var demo = {
			data: function() {
				return {
					message: '这里是中间组件 demo2'
				}
			},
			methods: {
				getSlots(){
					console.log("this.$slots:", this.$slots);
				},
				getScopedSlots(){
					console.log("this.$scopedSlots:", this.$scopedSlots);
				},
				getScopedSlotsVNode(){
					console.log("default:", this.$scopedSlots.default());
					console.log("slot2:", this.$scopedSlots.slot2());
					console.log("slot3:", this.$scopedSlots.slot3());
				},
			},
			template: `<div>
							<slot></slot>
							<slot name="slot2"></slot>
							<slot name="slot3"></slot>
							<button v-on:click='getSlots'>获取slots</button>
							<button v-on:click='getScopedSlots'>获取scopedSlots</button>
							<button v-on:click='getScopedSlotsVNode'>获取scopedSlotsVNode</button>
						</div>`
		};
		var app = new Vue({
			el: '#app',
			components: {
				'component-demo': demo,
			},
			data: function() {
				return {
					message: '这里最初的组件app',
					slotMessage1: '我是作用域插槽 slot1',
					slotMessage2: '我是作用域具名插槽 slot3'
				}
			},
			methods: {
				getRefs(){
					console.log("this.$refs:", this.$refs);
				}
			},
			template: `
				<div ref="template">
					<component-demo ref="component">
						<p >hello, 我是插槽 slot</p><p >hello, {{slotMessage1}}</p>
						<template v-slot:slot2>
							<p >hello, 我是具名插槽 slot2</p>
						</template>
						<template v-slot:slot3>
							<p>hello, {{slotMessage2}}</p>
						</template>
					</component-demo>
				</div>
			`,

		});
	</script>
</body>
</html>

is

用于实现动态组件。代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>vueTest</title>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
	<div id="app">
	</div>
	<script type="text/javascript">
		Vue.config.productionTip = false;
		var demo = {
			template: `<p>我是组件1号</p>`
		};
		var app = new Vue({
			el: '#app',
			components: {
				'component1': {
					template: `<p>我是组件1号</p>`,
					activated (){
						console.log("1号 激活 activated");
					},
					deactivated (){
						console.log("1号 停用 deactivated");
					},
					beforeDestroy: function(){
						console.log('1号 销毁之前');
					},
					destroyed: function(){
						console.log('1号 销毁');
					},
				},
				'component2': {
					template: `<p>我是组件2号</p>`,
					activated (){
						console.log("2号 激活 activated");
					},
					deactivated (){
						console.log("2号 停用 deactivated");
					},
					beforeDestroy: function(){
						console.log('2号 销毁之前');
					},
					destroyed: function(){
						console.log('2号 销毁');
					},
				},
				'component3': {
					template: `<p>我是组件3号</p>`,
					activated (){
						console.log("3号 激活 activated");
					},
					deactivated (){
						console.log("3号 停用 deactivated");
					},
					beforeDestroy: function(){
						console.log('3号 销毁之前');
					},
					destroyed: function(){
						console.log('3号 销毁');
					},
				},
			},
			data: function() {
				return {
					currentComponent: 'component1',
					currentComponentId: 0,
				}
			},
			methods: {
				changeComponent(){
					this.currentComponentId = (this.currentComponentId + 1) % 3;
					this.currentComponent = 'component' + (this.currentComponentId+1)
				}
			},
			template: 
				`<div>
					<component v-bind:is="currentComponent"></component>
					<button v-on:click='changeComponent'>changeComponent</button>
				</div>`,

		});
	</script>
</body>
</html>

更换的时候,触发了组件地销毁。

特殊组件:

transition

<transition> 元素作为单个元素/组件的过渡效果。<transition> 只会把过渡效果应用到其包裹的内容上,而不会额外渲染 DOM 元素,也不会出现在可被检查的组件层级中。可用于前端动画,

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>vueTest</title>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
	<style type="text/css">
		.fade-enter-active, .fade-leave-active {
			transition: opacity .5s;
		}
		.fade-enter, .fade-leave-to/* .fade-leave-active below version 2.1.8 */{
			opacity: 0;
		}
	</style>
</head>
<body>
	<div id="app">
	</div>
	<script type="text/javascript">
		Vue.config.productionTip = false;
		var
			demo = {
				data (){
					return {
						show: true,
					}
				},
				template: 	`<div>
								<button v-on:click="show = !show"> show: {{show}} </button>
								<transition name="fade">
									<h1 v-if="show">I am demo2</h1>
								</transition>
							</div>`,
			},
			app = new Vue({
				el: '#app',
				components: {
					'demo': demo,
				},
				template: `<demo></demo>`,
			});
	</script>
</body>
</html>

keep-alive

<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。

具有独有地生命周期,activateddeactivated,代表被 keep-alive 缓存的组件激活和停用。

部分代码改成码如下:

template: 
	`<div>
		<keep-alive>
			<component v-bind:is="currentComponent"></component>
		</keep-alive>
		<button v-on:click='changeComponent'>changeComponent</button>
	</div>`,

都没有触发销毁。

可以为keep-alive设置参数,max、include、exclude,max表示最多可以缓存多少组件实例;include表示允许组件缓存地名单;exclude表示不允许组件缓存地名单。

  • max:

template: 
	`<div>
		<keep-alive max="2">
			<component v-bind:is="currentComponent"></component>
		</keep-alive>
		<button v-on:click='changeComponent'>changeComponent</button>
	</div>`,

(虽然2可以,符合预期的情况,但是max改成1的话,有点问题的样子......)

  • include:

template: 
	`<div>
		<keep-alive include="component1">
			<component v-bind:is="currentComponent"></component>
		</keep-alive>
		<button v-on:click='changeComponent'>changeComponent</button>
	</div>`,

只对component1进行了缓存。

  • exclude:

template: 
	`<div>
		<keep-alive exclude="component1">
			<component v-bind:is="currentComponent"></component>
		</keep-alive>
		<button v-on:click='changeComponent'>changeComponent</button>
	</div>`,

只有component1没有缓存。

组件属性:

name

允许组件模板递归地调用自身。指定 name 选项的另一个好处是便于调试。有名字的组件有更友好的警告信息。另外,当在有 vue-devtools,未命名组件将显示成 <AnonymousComponent>,这很没有语义。通过提供 name 选项,可以获得更有语义信息的组件树。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>vueTest</title>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
	<div id="app">
	</div>
	<script type="text/javascript">
		Vue.config.productionTip = false;
		var
			demo = {
				template: `<p>我是组件1号</p>`,
				created(){
					console.log(this);
				}
			},
			app = new Vue({
				el: '#app',
				components: {
					'component1': demo,
				},
				template: `<component1></component1>`
			});
	</script>
</body>
</html>

没有name的话,会显示components中对应地属性名。

demo = {
	name: 'demo',
	template: `<p>我是组件1号</p>`,
	created(){
		console.log(this);
	}
},

有name属性的话,会显示name的值。

inheritAttrs

组件绑定地属性,如果不被认作 props的话,根据inheritAttrs做处理,默认true。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>vueTest</title>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
	<div id="app">
		<custom-input :value="inheritAttrsText" :test="test"></custom-input>
	</div>
	<script type="text/javascript">
		Vue.config.productionTip = false;
		Vue.component('custom-input', {
			props: ['value'],
			template: "<input v-bind:value='value' >",
		})
		const app = new Vue({
			el:'#app',
			data:{
				inheritAttrsText: "inheritAttrsText",
				test:'1'
			}
		});
	</script>
</body>
</html>

改成true。

Vue.component('custom-input', {
	inheritAttrs: false,
	props: ['value'],
	template: "<input v-bind:value='value' >",
})

functional

表示组建的渲染方式,使组件无状态 (没有 data) 和无实例 (没有 this 上下文)。只能用一个简单的 render 函数返回虚拟节点使它们渲染的代价更小。默认false。

正常的template渲染。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>vueTest</title>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
	<div id="app">
		<my-component></my-component>
	</div>
	<script type="text/javascript">		
		Vue.config.productionTip = false;
		Vue.component('component-demo', {
			template: '<h1>template</h1>',
		});
		var app = new Vue({
			el: '#app',
			template: `<component-demo></component-demo>`
		})
	</script>
</body>
</html>

functional改为true

Vue.component('component-demo', {
	functional: true,
	template: '<h1>template</h1>',
});

报错无法渲染。

使用render

Vue.component('component-demo', {
	functional: true,
	render: function (createElement, context) {
		return createElement('div', 'render');
	}
});

正常渲染。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值