7.vue元件(二)--雙向繫結,父子元件訪問

盛開的太陽發表於2021-03-01

本文主要說兩件事

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來獲取所有的元件

7.vue元件(二)--雙向繫結,父子元件訪問

 

 這裡獲取到了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可以指定元件名,獲取屬性和方法

7.vue元件(二)--雙向繫結,父子元件訪問

 

 

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>

7.vue元件(二)--雙向繫結,父子元件訪問

 

 以上就是父子元件之間相互訪問的情況

 

相關文章