Vue.js使用-组件(下篇)

上一节,我们定义了组件的基本使用,下面我们看看组件其他的一些特性。
1.组件作用域
同时在Vue对象和组件中定义一个属性,显示结果是怎样的呢?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        {{ msg }}
        <my-component></my-component>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            msg: 'hello world'
        },
        components: {
            'my-component':{
                template: '<div>{{ msg }}</div>',
                data: function () {
                    return {
                        msg: 'hello shijingjing'
                    }
                }
            }
        }
    })
</script>
</html>

运行结果:

可见,都在各自的作用域内有效,且组件不影响Vue定义的属性。
如何让组件使用Vue定义的属性呢,上节已经提到过,使用props属性。如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        <my-component v-bind:my-msg="msg"></my-component>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            msg: 'hello world'
        },
        components: {
            'my-component':{
                template: '<div>{{ myMsg }}</div>',
                props: ['myMsg']
            }
        }
    })
</script>
</html>

运行结果:

2.slot占位符
slot的意思是卡槽,也就是一个占位符,内容由组件包含的内容而定。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        <my-component>
            <div>这是组件里面真正包含的内容</div>
        </my-component>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        components: {
            'my-component':{
                template: '<div>hello world</div><slot>这只是一个占位符,具体内容由component包含的内容来定</slot>'
            }
        }
    })
</script>
</html>

运行结果:

如果组件里面没有包含内容呢?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        <my-component>
        </my-component>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        components: {
            'my-component':{
                template: '<div>hello world</div><slot>这只是一个占位符,具体内容由component包含的内容来定</slot>'
            }
        }
    })
</script>
</html>

运行结果:

可以再组件中包含占位符,来定义更为通用的组件。如一个对话框组件,不同时候弹出的标题不同,那么标题可以使用slot定义,真正内容放到组件内部。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        <my-component>
            <header slot="header">
                你好吗
            </header>
            <div slot="body">
                是的
            </div>
            <footer slot="footer">
                再见
            </footer>
        </my-component>
        ------------------------------------------------------
        <my-component>
            <header slot="header">
                早上好
            </header>
            <div slot="body">
                中午好
            </div>
            <footer slot="footer">
                晚上好
            </footer>
        </my-component>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        components: {
            'my-component':{
                template: '<div>hello world</div><slot name="header"></slot><slot name="body"></slot><slot name="footer"></slot>'
            }
        }
    })
</script>
</html>

运行结果:

3.组件之间数据访问
1)父组件访问子组件属性 $children

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        <my-component></my-component>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        components: {
            'my-component':{
                template: '<div>hello world</div><child-component1></child-component1><button v-on:click="showChildData">显示组件</button>',
                components:{
                    'child-component1':{
                        template: '<div>hello child 1</div>',
                        data: function () {
                            return {
                                msg: 'child 1'
                            }
                        }
                    }
                },
                methods:{
                    showChildData: function () {
                        console.log(this.$children[0].msg);
                    }
                }
            }
        }
    })
</script>
</html>

运行结果:

除了$children,还可以使用v-ref:c1来给组件指定一个索引名称c1,查询子组件时,使用$refs.c1找到这个子组件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        <my-component></my-component>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        components: {
            'my-component':{
                template: '<div>hello world</div><child-component1 v-ref:c1></child-component1><button v-on:click="showChildData">显示子组件</button>',
                components:{
                    'child-component1':{
                        template: '<div>hello child 1</div>',
                        data: function () {
                            return {
                                msg: 'child 1'
                            }
                        }
                    }
                },
                methods:{
                    showChildData: function () {
                        console.log(this.$refs.c1.msg);
                    }
                }
            }
        }
    })
</script>
</html>

运行结果:

2)子组件访问父组件属性 $parent

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        <my-component></my-component>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        components: {
            'my-component':{
                template: '<div>hello world</div><child-component1></child-component1>',
                components:{
                    'child-component1':{
                        template: '<div>hello child 1</div><button v-on:click="showParentData">显示父组件</button>',

                        methods:{
                            showParentData: function () {
                                console.log(this.$parent.msg);
                            }
                        }
                    }
                },
                data: function () {
                    return {
                        msg: 'parent'
                    }
                }
            }
        }
    })
</script>
</html>

运行结果:

3)子组件访问根组件属性 $root

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        <my-component></my-component>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            msg: 'root'
        },
        components: {
            'my-component':{
                template: '<div>hello world</div><child-component1></child-component1>',
                components:{
                    'child-component1':{
                        template: '<div>hello child 1</div><button v-on:click="showRootData">显示根组件</button>',

                        methods:{
                            showRootData: function () {
                                console.log(this.$root.msg);
                            }
                        }
                    }
                }
            }
        }
    })
</script>
</html>

运行结果:

可见,根元素指的是Vue对象

由$children,$parent,$root可以实现父子组件,以及Vue对象间的数据交互,但是还是尽量使用props属性来传递数据,
可以避免父子组件的过度耦合,以及子组件修改了父组件中的数据。

4.组件之间事件传递
1)派发事件$dispatch,事件沿着父链冒泡

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        {{ message }}
        <my-component></my-component>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            message: ''
        },
        components: {
            'my-component':{
                template: ' <input v-model="msg" /><button v-on:click="notify">dispatch</button>',
                data: function () {
                    return {
                        msg: ''
                    }
                },
                methods:{
                    notify: function () {
                        this.$dispatch('child-msg', this.msg);
                    }
                }
            }
        },
        events:{
            'child-msg': function (msg) {
                this.message = msg;
            }
        }
    })
</script>
</html>

运行结果:

$.dispatch会将事件派发到父组件的events事件,父组件接收到子组件的派发后,调用child-msg事件。

2)broadcast广播事件,事件向下传导给所有的子组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        <input type="text" v-model="message"/>
        <button v-on:click="notify">broadcast</button>
        <my-component></my-component>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            message: ''
        },
        components: {
            'my-component':{
                template: '{{msg}}',
                data: function () {
                    return {
                        msg: ''
                    }
                },
                events:{
                    'parent-msg': function (msg) {
                        this.msg = msg;
                    }
                }
            }
        },
        methods:{
            notify: function () {
                this.$broadcast('parent-msg', this.message);
            }
        }
    })
</script>
</html>

运行结果:

$.broadcast会将事件广播到子组件的events事件,子组件接收到父组件的广播后,调用parent-msg事件。

原文地址:https://www.cnblogs.com/shijingjing07/p/8378899.html