鍍金池/ 問答/HTML/ vue父子組件傳值的問題,父子組件如何通訊?

vue父子組件傳值的問題,父子組件如何通訊?

要實(shí)現(xiàn)的功能:

  1. 點(diǎn)擊【顯示子組件】按扭,子組件顯示----已實(shí)現(xiàn)

  2. 點(diǎn)擊【關(guān)閉】,子組件關(guān)閉----未實(shí)現(xiàn);第一次點(diǎn)擊報(bào)underfind錯(cuò)誤?,并且子組件沒有隱藏

  3. 點(diǎn)擊【確認(rèn)】按鈕把input中的值傳到父組件的 {{text}} ------未實(shí)現(xiàn)

clipboard.png

clipboard.png

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>   
    <script type="text/javascript" src="https://cdn.bootcss.com/vue/2.3.0/vue.js"></script>

</head>
<body>
<template id="aa">
    <div>
        <hr>
       我是子組件2
        <input type="text" v-model="text2">
        <button @click="close()">關(guān)閉</button>
        <button @click="affirm()">確認(rèn)</button>
    </div>
</template>


<div id="box">
    <p>
        我是父組件:{{text}}
        <button @click="showChild()">顯示子組件</button>
    </p>

    <child-page  v-show="pageSwitch" :pageSwitch2="pageSwitch" :text2="text"></child-page>
</div>
<script>
    new Vue({
        el:"#box",
        data:{
            text:"hello",
            pageSwitch:false
        },
        methods:{
            showChild:function(){
                this.pageSwitch=true;
            }
        },
        components:{
            "child-page":{
                template:"#aa",
                data:function(){
                    return{
                        childmsg:"子組件信息"
                    }
                },
                props:['pageSwitch2',"text2"],
                methods:{
                    close:function(){
                        console.log(this.pageSwitch2);
                        console.log(this.text2);
                        this.pageSwitch2=false;
                    },
                    affirm:function(){
                        console.log(this.pageSwitch2);
                        console.log(this.text2);
                    }
                }
            }
        }
    })
</script>
</body>
</html>
回答
編輯回答
莫小染

其實(shí)樓上的方法都是舍近求遠(yuǎn)了,用$emit可以解決問題,
但是$emit的局限也很大,比如通過slot傳進(jìn)來的子組件就沒辦法使用$emit
高效而且能夠?qū)崿F(xiàn)解耦的做法:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>   
    <script type="text/javascript" src="https://cdn.bootcss.com/vue/2.3.0/vue.js"></script>

</head>
<body>
<template id="aa">
    <div>
        <hr>
       我是子組件2
        <input type="text" v-model="text2">
        <button @click="close()">關(guān)閉</button>
        <button @click="affirm()">確認(rèn)</button>
    </div>
</template>


<div id="box">
    <p>
        我是父組件:{{text}}
        <button @click="showChild()">顯示子組件</button>
    </p>

    <child-page  v-show="pageSwitch" :pageSwitch2="pageSwitch" :text2="text" :close="close" :affirm="affirm"></child-page>
</div>
<script>
    new Vue({
        el:"#box",
        data:{
            text:"hello",
            pageSwitch:false
        },
        methods:{
            showChild:function(){
                this.pageSwitch=true;
            },
            close:function(){
                console.log(this.pageSwitch2);
                console.log(this.text2);
                this.pageSwitch2=false;
            },
            affirm:function(){
                console.log(this.pageSwitch2);
                console.log(this.text2);
            }
        },
        components:{
            "child-page":{
                template:"#aa",
                data:function(){
                    return{
                        childmsg:"子組件信息"
                    }
                },
                props:['pageSwitch2',"text2","close","affirm"],
            }
        }
    })
</script>
</body>
</html>

整體思路的就是把close和affirm(拼寫錯(cuò)誤,其實(shí)是confirm)兩個(gè)方法移動(dòng)到父組件,
然后在父組件的模板里把這兩個(gè)方法傳給子組件。
解釋:根據(jù)面向?qū)ο蟮摹伴_閉原則”,要想實(shí)現(xiàn)通過繼承子組件來修改內(nèi)部的邏輯,必然要對(duì)外暴露使用關(guān)心的接口

2017年4月15日 14:24
編輯回答
薔薇花

子組件向父組件通信,可使用$emit、vuex、或eventBus等,根據(jù)題主描述的問題,建議使用$emit方法。

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>   
    <script type="text/javascript" src="https://cdn.bootcss.com/vue/2.3.0/vue.js"></script>

</head>
<body>
<template id="aa">
    <div>
        <hr>
       我是子組件2
        <input type="text" v-model="text2">
        <button @click="close()">關(guān)閉</button>
        <button @click="affirm()">確認(rèn)</button>
    </div>
</template>


<div id="box">
    <p>
        我是父組件:{{text}}
        <button @click="showChild()">顯示子組件</button>
    </p>

    <child-page  v-show="pageSwitch" :pageSwitch2="pageSwitch" :text2="text"></child-page>
</div>
<script>
    new Vue({
        el:"#box",
        data:{
            text:"hello",
            pageSwitch:false
        },
        methods:{
            showChild:function(){
                this.pageSwitch=true;
            }
        },
        components:{
            "child-page":{
                template:"#aa",
                data:function(){
                    return{
                        childmsg:"子組件信息"
                    }
                },
                props:['pageSwitch2',"text2"],
                methods:{
                    close:function(){
                        console.log(this.pageSwitch2);
                        console.log(this.text2);
                        this.$emit("pageSwitch2",false);
                    },
                    affirm:function(){
                        console.log(this.pageSwitch2);
                        console.log(this.text2);
                    }
                }
            }
        }
    })
</script>
</body>
</html>

ps:如題主方法,點(diǎn)擊父組件方法隱藏子組件,雖然可以實(shí)現(xiàn)隱藏子組件的功能,但實(shí)際上還是控制父組件中的數(shù)據(jù),并沒有實(shí)現(xiàn)父子組件的通信,建議題主可以多了解props和emit等常用方法。

2017年5月29日 00:24
編輯回答
糖果果

子組件往父組件傳遞消息需要使用事件

2017年5月22日 04:36
編輯回答
骨殘心

感謝各位,效果已經(jīng)實(shí)現(xiàn)了

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script type="text/javascript" src="https://cdn.bootcss.com/vue/2.3.0/vue.js"></script>

</head>
<body>
<template id="aa">
    <div>
        <hr>
       我是子組件2
        <input type="text" v-model="text2b">
        <button @click="close()">關(guān)閉</button>
        <button @click="affirm()">確認(rèn)</button>
    </div>
</template>

<div id="box">
    <p>
        我是父組件:{{text}}
        <button @click="showChild()">顯示子組件</button>
    </p>
    <child-page  v-show="pageswitch" :pageswitch2="pageswitch" :text2="text" v-on:close2="close()" v-on:affirm2="affirm()" ref="childpage"></child-page>
</div>
<script>
    new Vue({
        el:"#box",
        data:{
            text:"hello",
            pageswitch:false
        },
        methods:{
            showChild:function(){
                this.pageswitch=true;
            },
            close:function(){
                this.pageswitch=false;
            },
            affirm:function(){
                this.text=this.$refs.childpage.text2b;  //父組件獲取子組件的值,使用this.$refs
            }
        },
        components:{
            "child-page":{
                template:"#aa",
                data:function(){
                    return{
                        childmsg:"子組件信息",
                        text2b:""
                    }
                },
                props:['pageswitch2',"text2"],  //子組件獲取父組件的值,使用props
                methods:{
                    close:function(){
                        this.$emit("close2");   //子組件事件觸發(fā)父組件的事件,使用 this.$emit
                    },
                    affirm:function(){
                        this.$emit("affirm2");
                    }
                },
                created:function(){
                    this.text2b=this.text2;
                }
            }
        }
    })
</script>
</body>
</html>

升級(jí)版代碼功能更多:
支持多個(gè)事件

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script type="text/javascript" src="https://cdn.bootcss.com/vue/2.3.0/vue.js"></script>
</head>
<style>
    .reply{
        font-size: 12px;
        background: #d0d0d0;
        width: 300px;
        padding: 5px;
    }
</style>

<body>
<template id="aa">
    <div>
        <hr>
        <input type="text" v-model="reply2b" placeholder="請(qǐng)輸入評(píng)論內(nèi)容">
        <button @click="close()">關(guān)閉</button>
        <button @click="affirm()">確認(rèn)</button>
    </div>
</template>

<div id="box">
    <ul>
        <li  v-for="item in items" @click="showChild(item)">
            {{item.title}}
            <p class="reply" v-show="item.reply">{{item.reply}}</p>
        </li>
    </ul>

    <child-page  v-show="pageswitch" :pageswitch2="pageswitch"  v-on:close2="close()" v-on:affirm2="affirm()" ref="childpage"></child-page>
</div>
<script>
    new Vue({
        el:"#box",
        data:{
            pageswitch:false,
            items:[
                {
                    "title":"標(biāo)題一",
                    "reply":"我是評(píng)論一"
                },
                {
                    "title":"標(biāo)題二",
                    "reply":""
                }
            ],
            item:""
        },
        methods:{
            showChild:function(item){
                this.pageswitch=true;
                this.$refs.childpage.init(item);   //父組件觸發(fā)子組件的事件this.$refs;
                this.item=item;
            },
            close:function(){
                this.pageswitch=false;
            },
            affirm:function(){
                this.item.reply=this.$refs.childpage.reply2b;  //父組件獲取子組件的值,使用this.$refs
            }
        },
        components:{
            "child-page":{
                template:"#aa",
                data:function(){
                    return{
                        childmsg:"子組件信息",
                        reply2b:""
                    }
                },
                props:['pageswitch2'],  //子組件獲取父組件的值,使用props
                methods:{
                    close:function(){
                        this.$emit("close2");   //子組件事件觸發(fā)父組件的方法,使用 this.$emit
                    },
                    affirm:function(){
                        this.$emit("affirm2");
                    },
                    init:function(item){
                        this.reply2b=item.reply;
                    }
                }
            }
        }
    })
</script>
</body>
</html>
2017年8月15日 11:35
編輯回答
朽鹿

父子組件的通信有自帶的方法 諸如emit props等
但是我推薦你使用狀態(tài)管理vuex 把vuex加入項(xiàng)目會(huì)使得整個(gè)項(xiàng)目管理和數(shù)據(jù)傳遞變得方便
當(dāng)然了 如果你只是簡(jiǎn)單應(yīng)用可以不這樣做

2018年7月6日 03:45
編輯回答
舊言

用vuex吧,也就是單一事件中心管理組件通信

你報(bào)錯(cuò)的原因應(yīng)該是你通過子組件修改了父組件的數(shù)據(jù),這在vue2.0是不允許的(1.0可以),你要是想只是不報(bào)錯(cuò),可以使用 mounted中轉(zhuǎn),但解決不了實(shí)際問題。所以可以父組件每次傳一個(gè)對(duì)象給子組件, 對(duì)象之間引用

data:{
        parentData:{
            text:"hello",
            pageSwitch:false
        }  
    }

像上面這樣,父組件傳遞數(shù)據(jù)對(duì)象給子組件,子組件修改數(shù)據(jù)對(duì)象里的內(nèi)容。

2018年4月13日 16:08
編輯回答
初念

那個(gè)報(bào)錯(cuò)的意思是,你不要直接修改父組建傳過來的變量的值,這樣容易前后不統(tǒng)一,
建議你在子組建建一個(gè)變量 或者用計(jì)算屬性

2017年3月3日 22:30
編輯回答
蟲児飛
<script>
    //父組件
    Vue.component('father', {
        template: `
            <div class="fatherBox">
                <div class="message" v-html="fatherData"></div>
                <button @click="changeChild">父組件按鈕</button>
                <child 
                    :show="forChild" 
                    @childHandle="doChildCommand"
                ></child>
            </div>
        `,
        data: function () {
            return {
                fatherData: '父組件數(shù)據(jù)',
                forChild: '父組件傳給子組件的數(shù)據(jù)'
            }
        },
        methods: {
            changeChild: function () {
                this.fatherData = '命令來源:<span>父組件</span>';
                this.forChild = '父組件改變了傳給子組件的數(shù)據(jù)';
            },
            doChildCommand: function (a,b) {
                this.fatherData = '命令來源:<span>子組件</span>';
                this.forChild = '子組件請(qǐng)求父組件改變了這個(gè)值。附帶參數(shù) <span>a->'+ a +', b->' + b +'</span>';
            }
        }
    })
 
    //子組件
    Vue.component('child', {
        props: {
            show: {
                type: String,
                default: '我是子組件'
            }
        },
        template: `
            <div class="childBox">
                <div class="message" v-html="show"></div>
                <button @click="changeFather">子組件按鈕</button>
            </div>
        `,
        methods: {
            changeFather: function () {
                //通知父組件的一個(gè)函數(shù)
                //第一個(gè)參數(shù)為與父組件約定好的函數(shù)
                //后面的參數(shù)是遞數(shù)據(jù),可以為多個(gè)
                this.$emit('childHandle','我是數(shù)據(jù)一','我也是數(shù)據(jù)')
            }
        }
    })
     
    new Vue({
        template: '<father></father>',
        el: '#app'
    })
</script>
2018年4月20日 04:04