本文主要說兩件事
1. 如何實作父子元件之間的雙向綁定
2. 父元件如何通路子元件的data,method, 子元件如何通路父元件的data,method等
一. 如何實作父子元件之間的雙向綁定
案例描述:
父子元件雙向綁定
父元件有一個message,
子元件有一個文本框
讓他們兩個同步變化
實作思路:
1. 子元件接收父元件傳遞過來的參數
2. 先實作子元件的雙向綁定
3. 子元件将資料傳給父元件
實作步驟:
第一步: 子元件接收父元件的data
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../../js/vue.js"></script>
</head>
<body>
<div id="app">
父元件的值: {{message}}
<br>
<input type="text" v-model="message"></input>
<comp1 :cmessage="message" ></comp1>
</div>
<template id="comp1">
<div style=" width: 600px; background-color: #085e7d; color: antiquewhite">
<h2>子元件cmessage的值:{{cmessage}}</h2>
<br>
</div>
</template>
<script>
Vue.component("comp1", {
template: "#comp1",
props: ["cmessage"],
})
const app = new Vue({
el: "#app",
data: {
message: "hello"
}
});
</script>
</body>
</html>
子元件通過屬性props: ["cmessage"], 來接收父元件的message屬性. 并且父元件修改message的值, 子元件跟随改變
效果如下:
第二步: 實作子元件屬性的雙向綁定
元件的資料綁定, 使用的也是data屬性.但在元件中, data定義為一個方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../../js/vue.js"></script>
</head>
<body>
<div id="app">
父元件的值: {{message}}
<br>
<input type="text" v-model="message"></input>
<comp1 :cmessage="message" ></comp1>
</div>
<template id="comp1">
<div style=" width: 600px; background-color: #085e7d; color: antiquewhite">
<h2>子元件cmessage的值:{{cmessage}}</h2>
<h2>子元件cmess的值: {{cmess}}</h2>
<br>
cmess:<input type="text" v-model="cmess" ></input>
<br>
</div>
</template>
<script>
Vue.component("comp1", {
template: "#comp1",
props: ["cmessage"],
data() {
return {
"cmess": this.cmessage
}
}
})
const app = new Vue({
el: "#app",
data: {
message: "hello"
}
});
</script>
</body>
</html>
data中定義了屬性cmess, 其值是屬性cmessage的值. 我們實作cmess屬性的雙向綁定.cmess:<input type="text" v-model="cmess" ></input>
效果如下:
這樣子元件cmess的雙向綁定實作了, 但是我們發現修改父元件的時候,子元件沒有變化. 修改子元件的時候, 父元件也沒有變化
第三步: 子元件屬性變化同步給父元件
子元件屬性的改變同步給父元件, 使用的是自定義事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../../js/vue.js"></script>
</head>
<body>
<div id="app">
父元件的值: {{message}}
<br>
<input type="text" v-model="message"></input>
<comp1 :cmessage="message" @csyncchange="syncchange"></comp1>
</div>
<template id="comp1">
<div style=" width: 600px; background-color: #085e7d; color: antiquewhite">
<h2>子元件cmessage的值:{{cmessage}}</h2>
<h2>子元件cmess的值: {{cmess}}</h2>
<br>
cmess:<input type="text" v-model="cmess" @input="changeMessage"></input>
<br>
</div>
</template>
<script>
Vue.component("comp1", {
template: "#comp1",
props: ["cmessage"],
data() {
return {
"cmess": this.cmessage
}
},
methods: {
changeMessage(event) {
console.log(event.target.value)
this.$emit("csyncchange", event.target.value)
}
},
watch: {
cmessage(val, oldval) {
console.log(val, oldval)
console.log()
this.cmess = val
}
}
})
const app = new Vue({
el: "#app",
data: {
message: "hello"
},
methods: {
syncchange(value) {
this.message = value
}
}
});
</script>
</body>
</html>
添加子元件的input事件: @input="changeMessage".
changeMessage(event) {
console.log(event.target.value)
this.$emit("csyncchange", event.target.value)
}
然後自定義一個csyncchange事件, 父元件監聽這個事件的變化
<comp1 :cmessage="message" @csyncchange="syncchange"></comp1>
父元件自定義一個method方法, 接收事件傳遞的資料
methods: {
syncchange(value) {
this.message = value
}
}
這樣就實作了子元件修改cmess的值, 同步給父元件. 效果如下:
但是, 我們發現,在組建同步給父元件沒問題, 元件隻同步資料給了props屬性, 而沒有同步給cmess
第四步: 使用watch方法監聽props屬性的變化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../../js/vue.js"></script>
</head>
<body>
<div id="app">
父元件的值: {{message}}
<br>
<input type="text" v-model="message"></input>
<comp1 :cmessage="message" @csyncchange="syncchange"></comp1>
</div>
<template id="comp1">
<div style=" width: 600px; background-color: #085e7d; color: antiquewhite">
<h2>子元件cmessage的值:{{cmessage}}</h2>
<h2>子元件cmess的值: {{cmess}}</h2>
<br>
cmess:<input type="text" v-model="cmess" @input="changeMessage"></input>
<br>
</div>
</template>
<script>
Vue.component("comp1", {
template: "#comp1",
props: ["cmessage"],
data() {
return {
"cmess": this.cmessage
}
},
methods: {
changeMessage(event) {
console.log(event.target.value)
this.$emit("csyncchange", event.target.value)
}
},
watch: {
cmessage(val, oldval) {
console.log(val, oldval)
console.log()
this.cmess = val
}
}
})
const app = new Vue({
el: "#app",
data: {
message: "hello"
},
methods: {
syncchange(value) {
this.message = value
}
}
});
</script>
</body>
</html>
這一步的重點是watch方法. 同步cmessage的值給cmess. 看看效果
以上,完美實作了,父子元件的雙向資料綁定.
二. 父子元件的互相通路
如果父元件想要通路子元件的屬性和方法, 或者子元件想要通路父元件的屬性和方法怎麼辦呢? 下面來看看:
1. 父元件通路子元件
父元件通路子元件有兩種方式
- 1. 使用$children
- 2. 使用@refs
案例: 現在有一個父元件, 想要拿到子元件的方法或者變量.
-
使用$children擷取
擷取所有的子元件: this.$children
擷取某個子元件的屬性: this.$children.屬性名
擷取某個子元件的方法: this.$children.方法名()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h1>第一種方法: 使用children通路子元件</h1>
<app1-comp></app1-comp>
<app1-comp></app1-comp>
<app1-comp></app1-comp>
<button @click="btnclick">按鈕</button>
</div>
<template id="comp1">
<div>
<p>隻有app1才能使用的元件</p>
<h2>{{name}}</h2>
</div>
</template>
<script src="../../js/vue.js"></script>
<script>
const app1Comp = Vue.extend({
template: comp1,
data() {
return {
name : "name名稱"
}
},
methods: {
getchange() {
console.log("getchange方法")
}
}
})
let app = new Vue({
el: "#app",
data: {
message: "hello"
},
components:{
app1Comp: app1Comp
},
methods: {
btnclick() {
console.log("點選事件", this.$children)
console.log("父元件通路子元件的data資料: ",this.$children[1].name)
console.log("父元件通路子元件的方法: ",this.$children[1].getchange())
}
}
});
</script>
</body>
</html>
在dom中使用了三個comp1元件. 我們可以使用this.$children來擷取所有的元件
這裡擷取到了3個元件, 并列印了第二個元件的名稱和方法
-
使用@refs擷取屬性
使用refs的好處是可以根據元件名稱擷取. 而不是周遊, 因為周遊的下标時可能修改的.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--
父元件通路子元件有兩種方式
1. 使用$children
2. 使用@refs
需求: 現在有一個父元件, 想要拿到子元件的方法或者變量.
是以, 我們先定義一個元件.
-->
<div id="app">
<h1>第二種方法: 使用refs通路子元件</h1>
<app2-comp ref="app21"></app2-comp>
<app2-comp ref="app22"></app2-comp>
<app2-comp ref="app23"></app2-comp>
<button @click="btnclick">按鈕</button>
</div>
<template id="comp1">
<div>
<p>隻有app1才能使用的元件</p>
<h2>{{name}}</h2>
</div>
</template>
<script src="../../js/vue.js"></script>
<script>
const app1Comp = Vue.extend({
template: comp1,
data() {
return {
name : "name名稱"
}
},
methods: {
getchange() {
console.log("getchange方法")
}
}
})
let app = new Vue({
el: "#app",
data: {
message: "hello"
},
components:{
app1Comp: app1Comp,
app2Comp: app1Comp
},
methods: {
btnclick() {
console.log(this.$refs.app21.name)
console.log(this.$refs.app21.getchange())
}
}
});
</script>
</body>
</html>
這一次我們給元件起了名字, 通過$refs可以指定元件名,擷取屬性和方法
2. 子元件通路父元件
- 子元件通路父元件使用的是$parent
- 子元件通路根元件使用$root
通常new Vue()也是一個元件, 他是根元件. 如果子元件想要擷取根元件的屬性和方法,使用@root
下面這個例子, 是子元件comp1裡面引用了另一個元件comp2. 在comp2中擷取comp1的屬性和方法, 使用@parent, 這就是子元件擷取父元件的屬性和方法
comp2要想擷取new Vue()對象的屬性和方法, 使用的是$root.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--
父元件通路子元件有兩種方式
1. 使用$children
2. 使用@refs
需求: 現在有一個父元件, 想要拿到子元件的方法或者變量.
是以, 我們先定義一個元件.
-->
<div id="app">
<h1>子元件通路父元件</h1>
<comp1></comp1>
</div>
<template id="comp1">
<div>
<comp2></comp2>
</div>
</template>
<template id="comp2">
<div>
<p>元件comp2</p>
<button type="text" @click="btnClick">按鈕</button>
</div>
</template>
<script src="../../js/vue.js"></script>
<script>
const app1Comp = Vue.extend({
template: comp1,
data() {
return {
name: "name名稱"
}
},
components: {
comp2: {
template: comp2,
methods: {
btnClick() {
console.log(this.$parent)
console.log(this.$parent.name)
// 擷取root元素, 也就是vue元素
console.log(this.$root)
console.log(this.$root.message)
}
}
}
}
})
let app = new Vue({
el: "#app",
data: {
message: "hello"
},
components:{
comp1: app1Comp
},
methods: {
btnclick() {
}
}
});
</script>
</body>
</html>
以上就是父子元件之間互相通路的情況