Vue父子組件數據雙向綁定(父傳子、子傳父)及ref、$refs、is、:is的使用與區別

既然有父傳子那麼肯定有子傳父,有子傳父肯定也有兩者之間相互綁定

這裡我們先看一下子傳父的寫法:

一、子傳父:$emit()

看代碼:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>子傳父</title>
		<script src="https://cdn.jsdelivr.net/npm/vue"></script>
	</head>
	<style type="text/css">
		button {
			margin-left: 5px;
		}
	</style>
	<body>
		<div id="app">
			<cpn1 @itemclick="cpnclick"></cpn1>
		</div>
		<template id="cpn1">
			<div>
				<button type="button" v-for="item in menu" :key="item.id"
					@click="btnclick(item)">{{item.name}}</button>
			</div>
		</template>
		<script type="text/javascript">
			const cpn = {
				template: "#cpn1",
				data() {
					return {
						menu: [{
								id: 'one',
								name: '首頁'
							},
							{
								id: 'two',
								name: '分類'
							},
							{
								id: 'three',
								name: '購物'
							},
							{
								id: 'four',
								name: '我的'
							},
						],
					}
				},
				methods: {
					btnclick(item) {
						this.$emit('itemclick', item)
// 子傳父 在子組件中做一個點擊事件通過$emit派發出 給父組件 同時可以攜帶參數
					}
				}
			};
			const vm = new Vue({
				el: '#app',
				methods: {
					cpnclick(item) {
						console.log('cpnclick' + item.name);
					}
				},
				components: {
					"cpn1": cpn
				}
			})
			
		</script>
	</body>
</html>

打印效果:

兩者之間的關系: 

 1、父組件可以使用 props 把數據傳給子組件。
2、子組件可以使用 $emit 觸發父組件的自定義事件。

二、監聽原生點擊事件:.native 

不加.native時,不會觸發原生的點擊事件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>不加native修飾符</title>
	</head>
	<style>
		div{
			cursor: pointer;
		}
	</style>
	<body>
		<div id="app">
          <cpn @click="handelClick"></cpn>    //    這裡沒有加native修飾符
		</div>
		<!-- 子組件 -->
		  <template id="cpn">
		    <div>
		      我是子組件
		    </div>
		  </template>
		<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
		<script>
			const cpn = {
				template:'#cpn',
			}
			const app = new Vue({
				el: "#app",
				methods: {
                  handelClick(){
					  console.log('click');
				  }
				},
				components:{
					cpn
				}
			})
		</script>
	</body>
</html>

效果如下: 

不加修飾符是不會監聽到原生點擊事件的。

如果是加瞭.native修飾符時:

 添加方法:

<cpn @click.native="handelClick"></cpn>

效果如下圖所示:

三、組件通信的案例:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
 
	</head>
	<body>
		<div id="app">
          <cpn :number1="num1" :number2="num2"></cpn>
		</div>
		<template id="cpn">
			<div>
				<h2>{{datanum1}}</h2>
				<input type="text" v-model="datanum1"/>
				<h2>{{datanum2}}</h2>
				<input type="text" v-model="datanum2"/>
			</div>
		</template>  
		<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
		<script>
			const cpn = {
				template:'#cpn',
				data(){
					return {
						datanum1:this.number1,
						datanum2:this.number2,
					}
				},
				props:{
					number1:{
						type:[String,Number]
					},
					number2:{
						type:[String,Number]
					},
				}
			}
			const app = new Vue({
				el: "#app",
				data() {
					return {
						num1:1,
						num2:2
					}
				},
				components:{
					cpn
				}
			})
		</script>
	</body>
</html>

效果如下:

 四、實現父子之間的值的雙向綁定

在子組件中添加監聽器,利用props和$emit來進行父子之間的雙向綁定

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<cpn :number1="num1" :number2="num2" @dataclick1="changeClick1" @dataclick2="changeClick2"></cpn>
		</div>
		<template id="cpn">
			<div>
				<h2>{{datanum1}}</h2>
				<h3>number1:{{number1}}</h3>
				<input type="text" v-model="datanum1" />
				<h2>{{datanum2}}</h2>
				<h3>number2:{{number2}}</h3>
				<input type="text" v-model="datanum2" />
			</div>
		</template>
		<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
		<script>
			const cpn = {
				template: '#cpn',
				data() {
					return {
						datanum1: this.number1,
						datanum2: this.number2
					}
				},
				props: {
					number1: {
						type: [String, Number]
					},
					number2: {
						type: [String, Number]
					}
				},
				watch: {
					datanum1(n) {
						console.log('datanum1被監聽瞭');
						this.$emit('dataclick1', n / 100)
					},
					datanum2(n) {
						console.log('datanum2被監聽瞭');
						this.$emit('dataclick2', n * 100)
					}
				}
			}
			const app = new Vue({
				el: "#app",
				data() {
					return {
						num1: 1,
						num2: 2
					}
				},
				methods: {
					changeClick1(value) {
						this.num1 = value
					},
					changeClick2(value) {
						this.num2 = value
					}
				},
				computed: {
 
				},
				components:{
					cpn
				}
			})
		</script>
	</body>
</html>

效果 

 一個是除10一個是

五、父訪問子 $refs

JavaScript中獲取元素可以使用document.querySelector,那可以在Vue中使用嗎?

我們可以測試一下

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="https://cdn.jsdelivr.net/npm/vue"></script>
	</head>
	<body>
		<div id="app">
			<p id="bb" @click="handelClick" ref="aa">Nanchen</p>
		</div>
		<script type="text/javascript">
			const vm = new Vue({
				el: '#app',
				data() {
					return {
					}
				},
				methods: {
					handelClick(){
						var bb = document.querySelector('bb');
						console.log(bb);
					}		
				}
			})
		</script>
	</body>
</html>

打印結果:

 答案是可以的,但是如果使用原生JS獲取元素的話,那麼用Vue就沒有意義瞭,Vue中有特定的語法

官網解釋:

$refs方式:ref 被用來給元素或子組件註冊引用信息。引用信息將會註冊在父組件的 $refs 對象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子組件上,引用就指向組件實例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="https://cdn.jsdelivr.net/npm/vue"></script>
	</head>
	<body>
		<div id="app">
			<p id="bb" @click="handelClick" ref="aa">Nanchen</p>
		</div>
		<script type="text/javascript">
			const vm = new Vue({
				el: '#app',
				data() {
					return {
					}
				},
				methods: {
					/* handelClick(){
						var bb = document.querySelector('bb');
						console.log(bb);
					} */
					handelClick() {
						console.log(this.$refs.aa);
					}
				}
			})
		</script>
	</body>
</html>

效果與上圖一致: 

六、使用$refs獲取組件中的值

 既然可以獲取普通元素那麼也可以獲得組件中的元素或者值

看這個例子:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
 
	</head>
	<body>
		<div id="app">
          <cpn ref="aaa"></cpn>
		  <button @click="handelClick">點擊</button>
		</div>
		<!-- 子組件 -->
		  <template id="cpn">
		    <div>
		      我是子組件
		    </div>
		  </template>
		<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
		<script>
			const cpn = {
				template:'#cpn',
				data(){
					return {
						name:'我是子組件的name'    //獲取子組件的屬性
					}
				},
				
			}
			const app = new Vue({
				el: "#app",
				methods: {
                  handelClick(){
					  console.log(this.$refs.aaa.name);
				  }
				},
				components:{
					cpn
				}
			})
		</script>
	</body>
</html>

效果如下: 

下面看一個擴展:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="https://cdn.jsdelivr.net/npm/vue"></script>
	</head>
	<body>
		<div id="app">
			<count ref="one" @change="handclick"></count>
			<count ref="two" @change="handclick"></count>
			<h2>{{total}}</h2>
		</div>
		
		<script type="text/javascript">
		Vue.component('count',{
			template:
			`<div @click="handclick">
				{{number}}
			</div>`,
			data(){
				return{
					number:0
				}
			},
			methods:{
				handclick(){
					this.number++;
					this.$emit('change')
				}
			}
		})
			const vm = new Vue({
				el:'#app',
				data(){
					return{
						total:0
					}
				},
				methods:{
					handclick(){
						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/[email protected]/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(){
					/* this.$refs.hello.handelClick(); */
					console.log(this.$refs.hello.$el.innerHTML);
				 }
				},
			})
		</script>
	</body>
</html>

效果如下:

 六、is與:is

is

作用:解決瞭html模板的限制。

看下面這段代碼:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="https://cdn.jsdelivr.net/npm/vue"></script>
	</head>
	<body>
		<div id="app">
			<table>
				<row></row>
			</table>
		</div>
		
		<script type="text/javascript">
		Vue.component('row',{
			template: '<tr><td>111</td></tr>'
		})
			const vm = new Vue({
				el:'#app',
				data(){
					return{
						
					}
				},
			})
		</script>
	</body>
</html>

會正常輸出

 但是:

會發現tr並不在table中,

解決辦法:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
 
	</head>
	<body>
		<div id="app">
          <table>
				<tr is="row"></tr>
			</table> 
		</div>
		<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
		<script>
			Vue.component('row', {
				template: '<tr><td>111</td></tr>'
			})
			const app = new Vue({
				el: "#app",
			})
		</script>
	</body>
</html>

 打印結果:

用:is還可以用來綁定動態組件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="https://cdn.jsdelivr.net/npm/vue"></script>
	</head>
	<body>
		<div id="app">
			<component :is="type"></component>
			<button type="button" @click="changeClick">切換</button>
		</div>
		<script type="text/javascript">
		// 這裡要定義兩個全局組件
			Vue.component('child-one',{
				template:'<div>child-one</div>'
			}),
			Vue.component('child-two',{
				template:'<div>child-two</div>'
			})
			const vm = new Vue({
				el:'#app',
				data(){
					return{
						type:'child-one'
					}
				},
				methods:{
					changeClick(){
						  this.type = this.type === 'child-one' ? 'child-two' :'child-one'
					}
				}
			})
		</script>
	</body>
</html>

效果如下:

以上就是Vue父子組件數據雙向綁定(父傳子、子傳父)及ref、$refs、is、:is的使用與區別的詳細內容,更多關於Vue父子組件數據雙向綁定的資料請關註WalkonNet其它相關文章!

推薦閱讀: