04. vue组件通信、事件总线

一、组件通信之父传子通信

1、父子通信


# 在全局组件上自定义属性
	<navbar myname="cc" age="18"></navbar>
# 在组件中获取, 关键字:props
	props: ['myname', 'age']
# 区分这两种赋值方式
	<navbar myname="cc" age="18"></navbar>
    <navbar :myname="'name'" age="18"></navbar>
    <navbar :myname="name" age="18"></navbar>

代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/vue.js"></script>
    <title>Title</title>
</head>
<body>

<div id="box">
    <navbar myname="jason" age="18"></navbar>
    <navbar :myname="name" :age="age"></navbar>
    <navbar :myname="'name'" :age="'age'"></navbar>
    <!--'name'和'age'被直接当做字符串显示-->
</div>

</body>
<script>
    // 全局组件
    Vue.component('navbar', {
        template: `
            <div>
                <button style="background: red">主页</button>
                父组件传递的内容是:{{myname}}---{{age}}
            </div>
        `,
        props: ['myname', 'age']
    })
    var vm = new Vue({
        el: '#box',
        data: {
            name: 'cc',
            age: 19,
        }
    })
</script>
</html>
image-20201217164315966

2、属性验证

 # 1、限制父传子的变量类型
	示例:
    props: {
        myname:String,
        isShow: Boolean
    }
# 2、父传子时注意一下的区别
	<navbar myname="cc" :isShow="isShow"></navbar>
	<navbar myname="cc" :isShow="false"></navbar>

代码演示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/vue.js"></script>
    <title>Title</title>
</head>
<body>

<div id="box">
    <navbar myname="jason" :isShow="isShow"></navbar>
    <navbar myname="jason" :isShow="false"></navbar>
</div>
</body>
<script>
    // 全局组件
    Vue.component('navbar', {
        template: `
            <div>
                <button style="background: red">主页</button>
                父组件传递的内容是:{{myname}}
            </div>
        `,
        props: {
            myname: String,
            isShow: Boolean
        }
    })
    var vm = new Vue({
        el: '#box',
        data: {
            name: 'cc',
            isShow: true
        }
    })
</script>
</html>
image-20201217190627235

二、组件通信之子与父通信

1、子与父通信

# 通过事件实现:
	点击一下子组件,就会触发父组件某个函数的执行

代码演示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/vue.js"></script>
    <title>Title</title>
</head>
<body>
<div id="box">
    <navbar @myevent="handleClick2"></navbar>
</div>
</body>
<script>
    // 全局组件
    Vue.component('navbar', {
        template: `
            <div>
                <button @click="handleClick1">点击触发父组件的函数执行</button>
            </div>
        `,
        methods: {
            handleClick1() {
                console.log('navbar组件的函数handleClick1执行')
                this.$emit('myevent', 100, this.name, 99)
            }
        },
        data() {
            return {name: 'cc'}
        }
    })
    var vm = new Vue({
        el: '#box',
        data: {
            name: 'cc',
            age: 19,
        },
        methods: {
            handleClick2(ev, a, b) {
                console.log('父组件的函数handleClick2执行')
                console.log(ev)
                console.log(a)
                console.log(b)
            }
        }
    })
</script>
</html>
image-20201217192057421

2、小案例

子组件有一个按钮,有一个输入框,当输入完内容,点击按钮,数据在父组件中展示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/vue.js"></script>
    <title>子与父通信小案例</title>
</head>
<body>
<div id="box">
    <child @myevent="handle"></child>
    <hr>
    {{name}}
</div>
</body>
<script>
    // 全局组件
    Vue.component('child', {
        template: `
            <div>
                <input type="text" v-model="myText">
                <button @click="handleClick">点我</button>
            </div>
        `,
        methods: {
            handleClick() {
                this.$emit('myevent', this.myText)
            }
        },
        data() {
            return {myText: ''}
        }
    })
    var vm = new Vue({
        el: '#box',
        data: {
            name: '',
        },
        methods: {
            handle(text) {
                this.name = text
            }
        }
    })
</script>
</html>
image-20201217192919916

执行流程图:

image-20201217220008652

三、ref属性

# ref属性也可以实现组件间的通信,子对父,父对子 都可以
- ref放在标签上,拿到的是原生节点
- ref放在组件上,拿到的是组件对象,
  	- 子传父的方式:(this.$refs.mychild.text)
    - 父传子的方式:(调用子组件的方式传参数)

1、使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/vue.js"></script>
    <title>Title</title>
</head>
<body>

<div id="box">
    <input type="text" ref="myref">
    <hr>
    <child ref="mychild"></child>
    <hr>
    <button @click="handleButton">点我</button>
</div>

</body>
<script>
    Vue.component('child', {
        template: `
        <div>
        <input type="text" v-model="mytext">
        <hr>
        我是子组件的input
        </div>
    `,
        data() {
            return {
                mytext: ''
            }
        },
        methods:{
            add(a){
                console.log('我是子组件的add方法')
                console.log(a)
                return '返回了'
            }
        }
    })

    var vm = new Vue({
        el: '#box',
        data: {
            name: 'cc'
        },
        methods: {
            handleButton(){
                console.log('----',this.$refs)
                console.log('----',this.$refs.myref.value)
                console.log('----',this.$refs.mychild.mytext)
                // 调用child的方法add
                console.log('----',this.$refs.mychild.add(this.name))
            }
        }
    })
</script>
</html>
image-20201217224430302

四、事件总线

作用:不同层级的不同组件之间通信

代码演示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/vue.js"></script>
    <title>Title</title>
</head>
<body>
<div id="box">
    <child1></child1>
    <hr>
    <child2></child2>
</div>
</body>
<script>
    // 定义一个事件总线
    var bus = new Vue()

    // 组件1
    Vue.component('child1', {
        template: `
            <div>
                <input type="text" v-model="mytext">
                <button @click="handleClick">点击传数据到另一个组件</button>
            </div>
        `,
        methods: {
            handleClick() {
                console.log('组件1要发送的消息:',this.mytext)
                bus.$emit('send', this.mytext)  // 通过事件总线发送
            }
        },
        data() {
            return {
                mytext: '',
            }
        },
    })
    // 组件2
    Vue.component('child2', {
        template: `
            <div>
                收到的消息是:{{recv_text}}
            </div>
        `,
        data() {
            return {
                recv_text: '',
            }
        },
        mounted() {  // 组件挂载(生命周期钩子函数中的一个,开始监听事件总线上的send)
            bus.$on('send', (item) => {
                console.log('组件2收到了:', item)
                this.recv_text = item
            })
        },
    })
    var vm = new Vue({
        el: '#box',
        data: {}
    })
</script>
</html>
image-20201217203852447

五、动态组件

同一页面,点击切换组件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/vue.js"></script>
    <title>动态组件</title>
</head>
<body>
<div id="box">
    <ul>
        <li @click="who='child1'">首页</li>
        <li @click="who='child2'">商品</li>
        <li @click="who='child3'">订单</li>
    </ul>
    <keep-alive>
        <component :is="who"></component>
    </keep-alive>
</div>
</body>
<script>
    var vm = new Vue({
        el: '#box',
        data: {
            who: 'child1'
        },
        components: {
            child1: {
                template: `
                    <div>
                        我是首页组件
                        <input type="text">
                    </div>
                `
            },
            child2:{
                template:`
                    <div>我是商品组件</div>
                `
            },
            child3:{
                template:`
                    <div>我是订单组件</div>
                `
            }
        }
    })
</script>
</html>

六、slot插槽

1、基本使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>slot插槽</title>
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <child1>
        <ul>
            <li v-for="i in 4">{{i}}</li>
        </ul>
    </child1>
    <hr>
    <child2></child2>
    <hr>
    <child3></child3>
</div>
</body>
<script>
    var vm = new Vue({
        el: '#box',
        data: {
            who: 'child1'
        },
        components: {
            child1: {
                template: `
                    <div>
                        <slot></slot>
                        <hr>
                        我是首页组件
                    </div>
                `
            },
            child2: {
                template: `
                    <div>我是商品组件</div>
                `
            },
            child3: {
                template: `
                    <div>我是订单组件</div>
                `
            }
        }
    })
</script>
</html>
image-20201217210048852

2、小案例:一个组件通过插槽控制另一个组件的显示/隐藏

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>slot插槽控制另一个组件的显示</title>
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <child1>
        <button @click="isShow=!isShow">点击显示/隐藏child2</button>
    </child1>
    <child2 v-show="isShow"></child2>
</div>
</body>
<script>
    var vm = new Vue({
        el: '#box',
        data: {
            isShow: true
        },
        components: {
            child1: {
                template: `
                    <div>
                        <slot></slot>
                        <hr>
                    </div>
                `
            },
            child2: {
                template: `
                    <ul>
                        <li v-for="i in 4">{{i}}</li>
                    </ul>
                `
            }
        }
    })
</script>
</html>
image-20201217213240795

3、具名插槽

通过slot名称,指定标签放到组件的某个插槽中

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>指定标签放到组件的某个插槽中</title>
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <child1>
        <div slot="div1">我是div</div>
        <button @click="isShow=!isShow" slot="button1">点击显示/隐藏child2</button>
    </child1>
    <hr>
    <child2 v-show="isShow"></child2>

</div>
</body>
<script>
    var vm = new Vue({
        el: '#box',
        data: {
            isShow: true
        },
        components: {
            child1: {
                template: `
                    <div>
                        <slot name="button1"></slot>
                        <hr>
                        <h5>手动分割</h5>
                        <hr>
                        <slot name="div1"></slot>
                    </div>
                `
            },
            child2: {
                template: `
                    <ul>
                        <li v-for="i in 4">{{i}}</li>
                    </ul>
                `
            }
        }
    })
</script>
</html>

button1和div1的位置是组件中写的slot位置决定的:

image-20201217214640943
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值