Vue中组件和组件之间的通信

目录

一,什么是组件

二,全局组件与局部组件

三,template模板引用

四,动态组件

五,动态组件结合keep-alive

六,父子组件的关系

七,组件通信 - 父组件向子组件传值

props选项高级选项配置

八,组件通信 -子组件向父组件传值

九,单向数据流

单向数据流子组件数据同步到父组件

十,非父子关系组件通信

十一,使用slot分发内容


 

一,什么是组件

组件Component,可扩展HTML元素,封装可重用的代码。通俗的来说,组件将可重用的HTML元素封装成为标签方便复用;

组件的使用:

  1. 使用全局方法Vue.extend创建构造器;
  2. 再使用全局方法Vue.component注册组件;

注意,在Vue.component里需要指明组件的名称,组件名称不能使用内置标签名称,如body。推荐使用短横线命名规则。例:

  • my-component 正确 (推荐)
  • my-Component 错误
  • mycomponent 正确
  • Mycomponent 正确
  • myComponent 错误
  • MyComponent 错误
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>01_component</title>
	</head>
	<body>
		<div id="sikiedu">
			<h3>hello Vue1</h3>
			<my-component></my-component>
			<my-component-a></my-component-a>
		</div>
	</body>
	<script type="text/javascript" src="../js/vue.js" ></script>
	<script type="text/javascript">
		
		//创建构造器
		let myComponent = Vue.extend({
			template : "<h1>hello Vue2</h1>"
		});
		
		//注册组件
		Vue.component('my-component', myComponent);
		
		//注册组件的简写
		Vue.component('my-component-a', {
			name : 'siki-edu',
			template : "<h2>hello sikiedu</h2>"
		})
		
		new Vue({
			data : {
				msg : '123'
			}
		}).$mount("#sikiedu");
	</script>
</html>

 

二,全局组件与局部组件

组件可分为全局组件与局部组件;

全局组件:

  • 在全局API中的Vue.component注册;
  • 该项目中所有Vue实例内均可以使用;

局部组件:

  • Vue实例中的components选项中注册;
  • 只能在本实例中使用;

全局组件和局部组件都可以存储数据,但是存储的方式与Vue实例中的data稍有不同;

组件里存储数据,data后需加上函数,数据写在函数体中。例:以下是在局部组件的data中,定义了name属性;

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>02_component</title>
	</head>
	<body>
		<div id="sikiedu">
			<my-component-b></my-component-b>
		</div>
		
		<div id="joey">
			<my-component-a></my-component-a>
		</div>
	</body>
	<script type="text/javascript" src="../js/vue.js" ></script>
	<script type="text/javascript">
		
		//注册组件的简写
		Vue.component('my-component-a', {
			template : "<h2>{{name}}</h2>",
			data : function(){
				return {
					name : 'hello sikiedu11'
				}
			}
		})
		
		new Vue({
			data : {
				msg : '123'
			},
			components : {
				"my-component-b" : {
					template :  "<h2>{{name}}</h2>",
					data(){
						return {
							name : "my-component-b !!"
						}
					}
				}
			}
		}).$mount("#sikiedu");
		
		new Vue({
			data : {
				msg : 'abc'
			}
		}).$mount("#joey");
	</script>
</html>

三,template模板引用

componenttemplate中书写大量的HTML元素很麻烦。

Vue提供了<template>标签,可以在里边书写HTML,然后通过ID指定到组建内的template属性上;

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>03_component_Template</title>
	</head>
	<body>
		<div id="sikiedu">
			<my-component-b></my-component-b>
			<my-component-b></my-component-b>
		</div>
		
	</body>
	
	<template id="my-template">
		<div>
			<h2>{{name}}</h2>
			<button @click="count++">{{count}}</button>
			<ul>
				<li v-for="item in numArray">{{item}}</li>
			</ul>
		</div>
	</template>
	
	<script type="text/javascript" src="../js/vue.js" ></script>
	<script type="text/javascript">
	
		new Vue({
			data : {
				msg : '123'
			},
			components : {
				"my-component-b" : {
					template :  "#my-template",
					data(){
						return {
							name : "my-component-b !!",
							numArray : [1, 2, 3, 4, 5],
							count : 0
						}
					}
				}
			}
		}).$mount("#sikiedu");
	
	</script>
</html>

四,动态组件

在一个元素上挂载多个组件,根据不同状态进行切换的时候,可以使用动态组件;

动态组件的使用:需要使用内置组件<component></component>,根据 :is 的值决定显示哪个组件,:is的值是要显示的组件id

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>04_dynamic_Component</title>
	</head>
	<body>
		<div id="sikiedu">
			<button @click="selectedName = 'my-component-a'"> a </button>
			<button @click="selectedName = 'my-component-b'"> b </button>
			<button @click="selectedName = 'my-component-c'"> c </button>
			
			<component :is="selectedName"></component>
		</div>
	</body>

	<script type="text/javascript" src="../js/vue.js" ></script>
	<script type="text/javascript">
	
		new Vue({
			data : {
				selectedName : 'my-component-a'
			},
			components : {
				"my-component-a" : {
					template :  "<h1>hello Vue</h1>"
				},
				"my-component-b" : {
					template :  "<a href='http://www.sikiedu.com'>sikiedu官网</a>"
				},
				"my-component-c" : {
					template :  "<p>欢迎来到siki学院学习!</p>"
				}
			}
		}).$mount("#sikiedu");
	
	</script>
</html>

 

五,动态组件结合keep-alive

keep-alive:包裹动态组件时,会缓存不活动的组件示例,而不是销毁它们。

max:数字。最多可以缓存多少组件示例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>05_keep-alive</title>
	</head>
	<body>
		<div id="sikiedu">
			<button @click="selectedName = 'my-component-a'"> a </button>
			<button @click="selectedName = 'my-component-b'"> b </button>
			<button @click="selectedName = 'my-component-c'"> c </button>
			
			<keep-alive :max="2">
				<component :is="selectedName"></component>
			</keep-alive>
		</div>
	</body>

	<script type="text/javascript" src="../js/vue.js" ></script>
	<script type="text/javascript">
	
		new Vue({
			data : {
				selectedName : 'my-component-a'
			},
			components : {
				"my-component-a" : {
					name : 'my-com-a',
					template :  "<h1>A : {{num}}</h1>",
					data(){
						return {
							num : Math.ceil( Math.random() * 100)
						}
					}
				},
				"my-component-b" : {
					template :  "<a href='http://www.sikiedu.com'>B : {{num}}</a>",
					data(){
						return {
							num : Math.ceil( Math.random() * 100)
						}
					}
				},
				"my-component-c" : {
					template :  "<p>C : {{num}}</p>",
					data(){
						return {
							num : Math.ceil( Math.random() * 100)
						}
					}
				}
			}
		}).$mount("#sikiedu");
	
	</script>
</html>

这个示例的结果自己调试,录屏有点麻烦 。。

六,父子组件的关系

Vue的组件内也可以定义组件,这种关系成为父子组件的关系;

如果在一个Vue实例中定义了component-a,然后在component-a中定义了component-b,那他们的关系就是:

    Vue实例 -- 根组件 root

             component-a – 相对于root 这是子组件,相对于component-b这是 父组件

                      component-b -- 子组件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>06_fatherAndChild</title>
	</head>
	<body>
		<div id="sikiedu">
			<father-component></father-component>
		</div>
	</body>

	<template id="father-template">
		<div>
			<h1>father component</h1>
			myData : <span>{{name}}</span>
			<hr />
			
			<child-component></child-component>
		</div>
	</template>
	
	<template id="child-template">
		<div>
			<h2>child component</h2>
			fatherData : <span>{{name}}</span>
		</div>
	</template>

	<script type="text/javascript" src="../js/vue.js" ></script>
	<script type="text/javascript">
	
		new Vue({
			data : {
				
			},
			components : {
				"father-component" : {
					template :  "#father-template",
					data:()=>({
						name:"joey"
					}),
					
					components : {
						"child-component" : {
							template : "#child-template",
							data(){
								return{
									name:"lijiang"
								}
							}
						}
					}
					
				}
			}
		}).$mount("#sikiedu");
	
	</script>
</html>

七,组件通信 - 父组件向子组件传值

父组件向子组件传值:父组件通过属性向下传值的方式和子组件通信;

使用步骤:

  1. 定义组件:现有自定义组件com-acom-bcom-acom-b的父组件;
  2. 准备获取数据:com-b要获取父组件data中的NAME属性;
  3. <com-b :name=“NAME”></com-b> 使用v-bind 绑定NAME属性,红色部分为属性名称,可以随意写。
  4. 在子组件定义部分里添加选项,值是个字符串数组 props:[name],将上边红色的属性名称写在这里;
  5. 之后就可定义在子组件中使用name属性了;

例1:

 

结果:

例2:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>07_fatherToChild</title>
	</head>
	<body>
		<div id="sikiedu">
			<father-component :msg="msg"></father-component>
		</div>
	</body>

	<template id="father-template">
		<div>
			<h1>father component</h1>
			myData : <span>{{NAME}} , {{id}} , {{user.username}}</span><br />
			fatherDate : <span>{{msg}}</span><br />
			<input type="text" v-model="NAME"/>
			<hr />
			
			<child-component :username="NAME" :id="id" :user="user"></child-component>
		</div>
	</template>
	
	<template id="child-template">
		<div>
			<h2>child component</h2>
			fatherData : <span>{{username}} , {{id}} , {{user.username}}</span>
		</div>
	</template>

	<script type="text/javascript" src="../js/vue.js" ></script>
	<script type="text/javascript">
	
		new Vue({
			data : {
				msg : 'helloVue'
			},
			components : {
				"father-component" : {
					template :  "#father-template",
					data(){
						return {
							id : 1,
							NAME : 'joey',
							user : {
								username : 'sikiedu-joey',
								password : '123123'
							}
						}
					},
					props : ['msg'],
					
					components : {
						"child-component" : {
							template : "#child-template",
							props : ['username', 'id', 'user']
						}
					}
				}
			}
		}).$mount("#sikiedu");
	
	</script>
</html>

推荐文章:https://blog.csdn.net/qq_42492055/article/details/82558971 (父子间传值)

props选项高级选项配置

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>08_props</title>
	</head>
	<body>
		<div id="sikiedu">
			<father-component></father-component>
		</div>
	</body>

	<template id="father-template">
		<div>
			<h1>father component</h1>
			myData : 
			<span>
				{{name}} , 
				{{id}} , 
				{{user.username}} , 
				{{age}}
			</span><br /><hr />
			<child-component  :id="id" :age="age"></child-component>
		</div>
	</template>
	
	<template id="child-template">
		<div>
			<h2>child component</h2>
			fatherData : 
			<span>
				{{name}} , 
				{{id}} , 
				{{user.username}},
				{{age}}
			</span>
		</div>
	</template>

	<script type="text/javascript" src="../js/vue.js" ></script>
	<script type="text/javascript">
	
		new Vue({
			data : {
				
			},
			components : {
				"father-component" : {
					template :  "#father-template",
					data(){
						return {
							id : '01',
							name : 'joey',
							user : {
								username : 'lijiang',
								password : '123123'
							},
							age : 18
						}
					},
					props : ['msg'],
					
					components : {
						"child-component" : {
							template : "#child-template",
							props : {
								name : {
									type : String,
									default : "siki"
								},
								id : [Number, String],
								user : {
									type : Object,
									default : function(){
										return {username : 'lain', password : '123123'};
									}
								},
								age : {
									type : Number,
									validator : function(value){
										return value >= 0;
									}
								}
							}
						}
					}
				}
			}
		}).$mount("#sikiedu");
	
	</script>
</html>

八,组件通信 -子组件向父组件传值

子组件向父组件传值:子组件通过$.emit()方法以事件形式向父组件发送消息传值;

使用步骤:

  1. 定义组件:现有自定义组件com-acom-bcom-acom-b的父组件;
  2. 准备获取数据:父组件com-a要获取子组件data中的height属性;
  3. 在子组件com-b中,需要用$.emit()方法将数据以事件的形式发送,$.emit('sendData', data, data…),红色的部分事件名可自定义,数据可传递多个;
  4. 在父组件中使用子组件的地方 <com-b @自定义事件名='getData'></com-b> 监听子组件自定义的事件,并且在方法中获取数据;
  5. 在父组件data定义height属性;
  6. 在父组件中实现getData(height)方法,方法参数是子组件传递的数据,例如这里直有一个height,然后为this.height赋值;
  7. 赋值完毕后就可以使用了;

例1:

父组件:

例2:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>09_childToFather</title>
	</head>
	<body>
		<div id="sikiedu">
			<father-component></father-component>
		</div>
	</body>

	<template id="father-template">
		<div>
			<h1>father component</h1>
			myData : 
			<span>
				{{name}} , 
				{{id}} , 
				{{user.username}} , 
				{{age}}
			</span><br />
			childData : 
			<span>
				{{width}},
				{{height}}
			</span><hr />
			<child-component  :id="id" :age="age" @send-event="getData"></child-component>
		</div>
	</template>
	
	<template id="child-template">
		<div>
			<h2>child component</h2>
			fatherData : 
			<span>
				{{name}} , 
				{{id}} , 
				{{user.username}},
				{{age}}
			</span><br />
			myData : 
			<span>
				{{width}},
				{{height}}
			</span><br />
			<button @click="sendData">向父组件发送数据</button>
		</div>
	</template>

	<script type="text/javascript" src="../js/vue.js" ></script>
	<script type="text/javascript">
	
		new Vue({
			data : {
				
			},
			components : {
				"father-component" : {
					template :  "#father-template",
					methods : {
						getData(width, height){
							this.width = width;
							this.height = height;
						}
					},
					data(){
						return {
							id : '01',
							name : 'joey',
							user : {
								username : 'lijiang',
								password : '123123'
							},
							age : 18,
							width : 0,
							height : 0
						}
					},
					
					components : {
						"child-component" : {
							template : "#child-template",
							methods : {
								sendData(){
									console.log(this);
									this.$emit('send-event', this.width, this.height);
								}
							},
							data(){
								return {
									width : 50,
									height : 100
								}
							},
							props : {
								name : {
									type : String,
									default : "siki"
								},
								id : [Number, String],
								user : {
									type : Object,
									default : function(){
										return {username : 'lain', password : '123123'};
									}
								},
								age : {
									type : Number,
									validator : function(value){
										return value >= 0;
									}
								}
							}
						}
					}
				}
			}
		}).$mount("#sikiedu");
	
	</script>
</html>

 

九,单向数据流

单向数据流:父组件值的更新,会影响到子组件,反之则不行;

修改子组件的值:

  • 局部数据:在子组件中定义新的数据,将父组件传过来的值赋值给新定义的数据,之后操作这个新数据;
  • 如果对数据进行简单的操作,可以使用计算属性;
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>10_one-Way Data Flow</title>
	</head>
	<body>
		<div id="sikiedu">
			<father-component ></father-component>
		</div>
	</body>

	<template id="father-template">
		<div>
			<h1>father component</h1>
			myData : <span>{{name}}</span><br />
			<input type="text" v-model="name"/><hr />
			<child-component :name="name"></child-component>
		</div>
	</template>
	
	<template id="child-template">
		<div>
			<h2>child component</h2>
			fatherData : <span>{{childUpperName}}</span><br />
			<input type="text" v-model="childUpperName"/><hr />
		</div>
	</template>

	<script type="text/javascript" src="../js/vue.js" ></script>
	<script type="text/javascript">
	
		new Vue({
			data : {
				msg : 'helloVue'
			},
			components : {
				"father-component" : {
					template :  "#father-template",	
					data(){
						return {
							name : 'joey'
						}
					},
					props : ['msg'],
					
					components : {
						"child-component" : {
							template : "#child-template",
							props : ['name'],
							data(){
								return {
									childName : this.name
								}
							},
							computed : {
								childUpperName(){
									return this.name.toString().toUpperCase();
								}
							}
						}
					}
				}
			}
		}).$mount("#sikiedu");
	
	</script>
</html>

 

单向数据流子组件数据同步到父组件

修改子组件的prop,同步到父组件:

  • 使用.sync修饰符;
  • 将要操作的数据封装成一个对象再操作;
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>11_one-Way Data Flow_01</title>
	</head>
	<body>
		<div id="sikiedu">
			<father-component ></father-component>
		</div>
	</body>

	<template id="father-template">
		<div>
			<h1>father component</h1>
			name : <span>{{name}}</span><br />
			<input type="text" v-model="name"/><br />
			userID : <span>{{user.id}}</span><br />
			<input type="text" v-model="user.id"/><br />
			
			<hr />
			<child-component :name.sync="name" :user="user"></child-component>
		</div>
	</template>
	
	<template id="child-template">
		<div>
			<h2>child component</h2>
			fatherData : <span>{{childName}}</span><br />
			<input type="text" v-model="childName"/><br />
			
			userID : <span>{{user.id}}</span><br />
			<input type="text" v-model="user.id"/><br />
			<hr />
		</div>
	</template>

	<script type="text/javascript" src="../js/vue.js" ></script>
	<script type="text/javascript">
	
		new Vue({
			data : {
				msg : 'helloVue'
			},
			components : {
				"father-component" : {
					template :  "#father-template",
					data(){
						return {
							name : 'joey',
							user : {
								id : 1
							}
						}
					},
					props : ['msg'],
					
					components : {
						"child-component" : {
							template : "#child-template",
							props : ['name', 'user'],
							data(){
								return {
									childName : this.name
								}
							},
							computed : {
								childUpperName(){
									return this.name.toString().toUpperCase();
								}
							},
							updated(){
								this.$emit('update:name', this.childName);
							}
						}
					}
				}
			}
		}).$mount("#sikiedu");
	
	</script>
</html>

 

十,非父子关系组件通信

Vue中不同的组件,即使不存在父子关系也可以相互通信,我们称为非父子关系通信;

我们需要借助一个空Vue实例,在不同的组件中,使用相同的Vue实例来发送/监听事件,达到数据通信的目的;

例1:

运行结果:

例2:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>12_non-fatherAndSon</title>
	</head>
	<body>
		<div id="sikiedu">
			<my-component-a></my-component-a>
			<my-component-b></my-component-b>
		</div>
	</body>

	<template id="template-a">
		<div>
			<h1>my-component-a</h1>
			comA name : <span>{{name}}</span><br />
			<button @click="sendData">发送数据给comB</button>
			<hr />
		</div>
	</template>
	
	<template id="template-b">
		<div>
			<h2>my-component-b</h2>
			comB name : <span>{{nameB}}</span>
			<hr />
		</div>
	</template>

	<script type="text/javascript" src="../js/vue.js" ></script>
	<script type="text/javascript">
	
		let comA = {
			template :  "#template-a",
			data(){
				return {
					name : "joey"
				}
			},
			methods : {
				sendData(){
					vm.$emit('send-event-a', this.name);
				}
			}
		}
		
		let comB = {
			template :  "#template-b",
			data(){
				return {
					nameB : ''
				}
			},
			mounted(){
				vm.$on('send-event-a', name => {
					console.log(this);
					this.nameB = name;
				})
			}
		}
	
		let vm = new Vue({
			data : {
				msg : 'sikiedu'
			}
		});
		new Vue({
			data : {
				
			},
			components : {
				"my-component-a" : comA,
				"my-component-b" : comB
			}
		}).$mount("#sikiedu");
	
	</script>
</html>

 

十一,使用slot分发内容

有时候我们需要在自定义组件内书写一些内容,例如:

<com-a>

<h1>title</h1>

</com-a>

如果想获取上面代码片段中h1标签的内容该怎么办呢?Vue提供了一个极为方便的内置组件<slot>

slot使用起来非常简单,点击跳转到API

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>13_slot</title>
	</head>
	<body>
		<div id="sikiedu">
			<my-component-a>
				<h1 slot="title">我才是大标题</h1>
				
				<ul slot="ulli">
					<li>a</li>
					<li>b</li>
					<li>c</li>
				</ul>
				
				<!-- <a href="#" slot="a">点击我传送</a> -->
			</my-component-a>
		</div>
	</body>

	<template id="template-a">
		<div>
			<slot name="a">数据为空</slot>
			<slot name="title">数据为空</slot>
			<h1>my-component-a</h1>
			<slot name="ulli">数据为空</slot>
		</div>
	</template>
	
	<script type="text/javascript" src="../js/vue.js" ></script>
	<script type="text/javascript">
	
		let comA = {
			template :  "#template-a"
		}
		
		new Vue({
			data : {
				
			},
			components : {
				"my-component-a" : comA
			}
		}).$mount("#sikiedu");
	
	</script>
</html>

这里推荐一篇关于slot的资料,感觉还不错:https://blog.csdn.net/kingov/article/details/78293384 

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值