vue组件通信(props、$emit、$refs和is)

父传子props

使用组件的props属性实现父组件给子组件传数据

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
		<title></title>
	</head>
	<body>
		<!-- 父组件 -->
		<div id="app">
			<cpn :cmovies="movies" :cmessage="message"></cpn>
		</div>

		<!-- 子组件 -->
		<template id="cpn">
			<div>
				<ul>
					<li v-for="(item,index) in cmovies" :key="item">{{item}}</li>
				</ul>
				<h2>{{cmessage}}</h2>
			</div>
		</template>
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
		<script type="text/javascript">
			var app = new Vue({
				el: "#app",
				data(){
					return{
						message:"你好",
						movies:["复仇者联盟", "钢铁侠", "星际穿越", "哪吒传奇"]
					}		
				},
				components:{
					cpn:{
						template:"#cpn",
						// props:['cmovies', 'cmessage'],//数组写法
						props:{
							cmessage:{
								type:String,//传的数据类型
								required:true//在使用组件必传值
							},
							cmovies:{
								type: Array,
							},
						}
					}
				}
			})
		</script>
	</body>
</html>

这里父组件给子组传了一个字符message、一个数组movies。

子传父$emit

子组件向父组件传值,使用自定义事件 $emit

		<!-- 父组件 -->
		<div id="app">
			<!-- <cpn @itemclick="cpnclick"></cpn> -->
			<!-- 子组件传的数据itemclick,父组件使用cpnclick方法进行使用,这里不用填参数 -->
			
			<cpn @itemclick="cpnclick(arguments)"></cpn>
			<!-- 这里使用arguments接受数据 -->
		</div>
		
		<!-- 子组件 -->
		<template id="cpn">
			<div>
				<button v-for="(item,index) in categoties" :key="item.id" @click="btnClick(item,index)">{{item.name}}</button>
			</div>
		</template>
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
		<script type="text/javascript">
			var app = new Vue({
				el: "#app",
				data() {
					return {}
				},
				watch: {

				},
				methods: {
					cpnclick(arguments){
						console.log(arguments)
						console.log(arguments[0])//item
						console.log(arguments[0].name)
						console.log(arguments[1])//index
						// console.log('cpnClick'+item.name+'---'+index)
					}
				},
				components: {
					cpn: {//创建局部子组件
						template: "#cpn",
						data() {
							return {
								categoties: [{
										id: 'aaa',
										name: '热门推荐'
									},
									{
										id: 'bbb',
										name: '手机数码'
									},
									{
										id: 'ccc',
										name: '家用家电'
									},
									{
										id: 'ddd',
										name: '电脑办公'
									},
								] 
							}
						},
						methods: {
							btnClick(item,index) {
								this.$emit('itemclick', item,index)//传值给父组件
							}
						}
					},
				}
			})
		</script>

在这里插入图片描述
1.在子组件中定义一个方法btnClick(item),使用$emit,'itemclick’是事件名,item是传过去的值。在子组件中监听点击事件并回调此方法;
2.在父组件中定义一个方法cpnClcik(item) ,并在父组件(vue实例)中调用<cpn @itemclick="cpnClcik"></cpn>不写参数默认传递btnClick的item ),父组件监听事件名为itemclick的子组件传过来的事件;

父子组件的值双向绑定

这里主要使用watch进行监听

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
		<title></title> 
	</head>  
	<body>
		<!-- 父组件 -->
		<div id="app">
			<cpn :number1="num1" :number2="num2" @num1change="num1Change" @num2change="num2Change"></cpn>
			<hr>
			<h2>父组件num1:{{num1}}</h2>
			<input type="text" v-model="num1">
			<h2>父组件num2:{{num2}}</h2>
			<input type="text" v-model="num2">
			<hr >
		</div>

		<!-- 子组件 -->
		<template id="cpn">
			<div>
				<h2>number1:{{number1}}</h2>
				<h2>datanum1:{{datanum1}}</h2>
				<input type="text" v-model="datanum1">
				<!-- 子组件不能直接使用props内的值 -->
				<h2>number2:{{number2}}</h2>
				<h2>datanum2:{{datanum2}}</h2>
				<input type="text" v-model="datanum2">
			</div>
		</template>
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
		<script type="text/javascript">
			var app = new Vue({
				el: "#app",
				data() {
					return {
						num1: 1,
						num2: 2
					}
				},
				methods: {
					//接收子组件传来的值后,赋给num
					num1Change(value) {
						this.num1 = value
					},
					num2Change(value) {
						this.num2 = value
					},
				},
				components: {
					cpn: {
						template: "#cpn",
						data() {
							return {
								datanum1: this.number1, //子组件同样要加this
								datanum2: this.number2
							}
						},
						props: {
							number1: {
								type: [String, Number]
							},
							number2: {
								type: [String, Number]
							},
						},
						watch: {
							//监听datanum的值,发生改变时,传给父组件
							datanum1(newValue) {
								this.$emit('num1change', newValue)
							},
							datanum2(newValue) {
								this.$emit('num2change', newValue)
							},
							
							//监听number即num的值,发生改变时,改变datanum
							number1(newValue) {
								this.datanum1 = newValue
							},
							number2(newValue) {
								this.datanum2 = newValue
							}
						}
					},
				}
			})
		</script>
	</body>
</html>

父子组件的值双向绑定:
1.父组件app下num1、num2用props传给子组件cpn,cpn用number1、number2接收;
2.cpn用data把number1、number2赋给datanum1、datanum2(因子组件不能直接操作props内的值),而后把datanum1、datanum2与input输入框用v-model双向绑定;
3.在cpn中在watch下监听datanum1、datanum2,一旦变化,则用$emit()传给父组件app,app使用num1change、num2change接收,赋给num1、num2;而后回到第1步,第1步执行完后,number1、number2发生变化会触发cpn下的watch监听number1、number2,再将其赋值给datanum1、datanum2,改变了datanum1、datanum2。
4.最终形成闭环,改变任一方的值,都会牵动其他值的改变

在这里插入图片描述

父访问子 ref

$refs方式:ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例

ref的基本使用 用在元素上
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>

	</head>
	<body>
		<div id="app">
          <p ref="p" @click="handelClick" id="ppp">hello</p>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
		<script>
			const app = new Vue({
				el: "#app",
				data: {
					
				},
				methods: {
                 handelClick(){
					 console.log(this.$refs.p);
					 //两种方法都可获取p标签
					 const ppp = document.querySelector('#ppp')
					 console.log(ppp);
				 }
				},
			})
		</script>
	</body>
</html>
ref在子组件上的使用

ref 可以调用组件中的数据

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>

	</head>
	<body>
		<div id="app">
           <counter ref="one" @change="handelChange"></counter>
		   <counter ref="two" @change="handelChange"></counter>
		   <div>total:{{total}}</div>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
		<script>
			Vue.component('counter',{
				template:'<div @click="handelclick">{{number}}</div>',
				data(){
					return {
						number:0
					}
				},
				methods:{
					handelclick(){
						this.number++;
						this.$emit('change');
					}
				}
			})
			const app = new Vue({
				el: "#app",
				data: {
					total:0
				},
				methods: {
                 handelChange(){
					 this.total = this.$refs.one.number + this.$refs.two.number
				 }
				},
			})
		</script>
	</body>
</html>

ref 可以调用组件中的方法

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>

	</head>
	<body>
		<div id="app">
          <hello-world ref="hello"></hello-world>
		   <button @click="getHello">获取helloworld组件中的值</button>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
		<script>
			Vue.component('helloWorld',{
				template:`<div>helloWorld</div>`,
				data(){
					return {
						number:0
					}
				},
				methods:{
					handelClick(){
						console.log('我是子组件的方法');
					}
				}
			})
			const app = new Vue({
				el: "#app",
				data: {
					
				},
				methods: {
                 getHello(){
					console.log(this.$refs.hello.handelClick)//子组件方法
					console.log(this.$refs.hello.$el.innerHTML);//helloWorld
				 }
				},
			})
		</script>
	</body>
</html>
is用于动态组件且基于 DOM 内模板的限制来工作。

基于 DOM 内模板的限制来工作

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>is基于 DOM 内模板的限制来工作</title>

	</head>
	<body>
		<div id="app">
          <table>
			  <tr is="row">
			  </tr> 
		 <!-- <row></row> 这样写tr会在table外面-->
		  </table>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
		<script>
			Vue.component('row',{
				template:'<tr><td>111</td></tr>'
			})
			const app = new Vue({
				el: "#app",
				data() {
					return {}
				},
			})
		</script>
	</body>
</html>

动态组件component

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<!-- <child-one></child-one>
			<child-two></child-two> -->
			<component :is="type"></component>
			<button @click="handerClick">点击切换</button>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
		 <script>
			 Vue.component('cpn1',{
				 template:'<div>child-one</div>'
			 })
			 Vue.component('cpn2',{
			 	template:'<div>child-two</div>'
			 })
			const app = new Vue({
				el:'#app',
				data(){
					return {
						type:'cpn1'
					}
				},
				methods:{
					handerClick(){
						this.type=this.type==='cpn1'?'cpn2':'cpn1';
					}
					
				}
			}) 
			 
		 </script>
	</body>
</html>

is后的type代表组件名,通过改变type(组件名),来切换显示组件

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值