Vue学习笔记—组件之间通信

一、props && emit(父子组件通信)

1、props => 父组件向子组件传参

例子:

<template id="shop-item">
    <div>
        <!-- 3. 子组件接收到的props就可以直接作为data去使用 -->
        <p>
            <span>{{ id }}</span>
            <b>{{ shopTitle }}</b>
            <span>{{ status | formatStatus }}</span>
            <em>{{ price | toFixed }}</em>
        </p>
    </div>
</template>

<div id="app">
    <div class="container">
        <!-- 子组件也可以写成单标签 -->
        <!-- 参数如果是驼峰,那么传递的时候要转成小写加横杠(-) -->
        <!-- 在html里用-加小写,在js里面用驼峰 -->
        <!-- 1. 父组件里使用子组件的时候可以通过绑定属性传参 -->
        <shop-item v-for="shopItem in list" :key="shopItem.id" :price="shopItem.price" :id="shopItem.id"
                :shop-title="shopItem.shopTitle" :status="shopItem.status">

        </shop-item>
    </div>
</div>
<script>
    const shopItem = {
        template: '#shop-item',
        // 2. 在子组件里通过props来接收参数
        // props: ['id', 'price', 'title', 'status'],
        // props还可以使用对象的方式来接收参数
        props: {
            shopTitle: String,
            status: {
                type: String,
                required: false,
                default: "001"
            },
            id: Number,
            price: Number
        },
        filters: {
            formatStatus(value) {
                const statusMap = {
                    "001": "未付款",
                    "002": "待发货",
                    "003": "已发货",
                    "004": "已签收",
                    "005": "已评价"
                }
                return statusMap[value]
            },
            toFixed(value) {
                return value.toFixed(2)
            }
        }
    }
    const app = new Vue({
        el: '#app',
        data: {
            list: [
                { id: 1, status: "001", shopTitle: "拖把", price: 19.999 },
                { id: 2, status: "002", shopTitle: "扫把", price: 11 },
                { id: 2, status: "004", shopTitle: "簸箕", price: 30.9 },
                { id: 4, status: "003", shopTitle: "鸡毛掸子", price: 19.9 },
                { id: 5, shopTitle: "吸尘器", price: 199 },
            ]
        },
        components: {
            shopItem
        }
    })
</script>
  • 父组件向子组件传参的过程:
    • 父组件里使用子组件的时候可以通过绑定属性传参(传递)
    • 在子组件里通过 props 来接收参数 (接收)
    • 子组件接收到的 props 就可以直接作为 data 去使用(渲染)
  • 父组件向子组件传参需要注意:
    • 参数如果是驼峰,那么传递的时候要转成小写加横杠(-)
    • html 里用(-)加小写,在 js 里面用驼峰
    • props 不仅可以用数组来接收参数,还可以使用对象来接收参数
    • props 是单向的传递数据

2、$emit => 子组件向父组件传参

例子:

<template id="shop-item">
    <div>
        <!-- 3. 子组件接收到的props就可以直接作为data去使用 -->
        <p>
            <span>{{ id }}</span>
            <b>{{ shopTitle }}</b>
            <span>{{ status | formatStatus }}</span>
            <em>{{ price | toFixed }}</em>
            <!-- <button v-if="isCart" class="in">移出购物车</button>
<button v-else>加入购物车</button> -->

            <button :class="{ in:isCart }" @click="toggleIsCart">
                {{ isCart ? "移出" : "加入" }}购物车
            </button>
        </p>
    </div>
</template>
<div id="app">
    <div class="container">
        <!-- 子组件也可以写成单标签 -->
        <!-- 参数如果是驼峰,那么传递的时候要转成小写加横杠(-) -->
        <!-- 在html里用-加小写,在js里面用驼峰 -->
        <!-- 1. 父组件里使用子组件的时候可以通过绑定属性传参 -->
        <shop-item v-for="shopItem in list" :key="shopItem.id" :price="shopItem.price" :id="shopItem.id"
                :shop-title="shopItem.shopTitle" :status="shopItem.status" :is-cart="shopItem.isCart"
                @toggle-is-cart-form-item="toggleIsCartByParent">

        </shop-item>
    </div>
</div>
<script>
    const shopItem = {
        template: '#shop-item',
        // 2. 在子组件里通过props来接收参数
        // props: ['id', 'price', 'title', 'status'],
        // props还可以使用对象的方式来接收参数
        props: {
            shopTitle: String,
            status: {
                type: String,
                required: false,// 是否必须
                default: "001"
            },
            id: Number,
            price: Number,
            isCart: {
                type: Boolean,
                required: true,
                default: false
            }
        },
        methods: {
            toggleIsCart() {
                // 告诉父组件我要修改当前商品的isCart值了
                // 使用emit向父组件触发一个自定义事件
                // 这里的事件名和父组件绑定的事件名必须完全一致
                // 第二个参数可以向父组件传参
                this.$emit("toggle-is-cart-form-item", {
                    id: this.id
                })
            }
        },
        filters: {
            formatStatus(value) {
                const statusMap = {
                    "001": "未付款",
                    "002": "待发货",
                    "003": "已发货",
                    "004": "已签收",
                    "005": "已评价"
                }
                return statusMap[value]
            },
            toFixed(value) {
                return value.toFixed(2)
            }
        }
    }
    const app = new Vue({
        el: '#app',
        data: {
            list: [
                { id: 1, status: "001", isCart: false, shopTitle: "拖把", price: 19.999 },
                { id: 2, status: "002", isCart: false, shopTitle: "扫把", price: 11 },
                { id: 3, status: "004", isCart: false, shopTitle: "簸箕", price: 30.9 },
                { id: 4, status: "003", isCart: true, shopTitle: "鸡毛掸子", price: 19.9 },
                { id: 5, status: "004", isCart: false, shopTitle: "吸尘器", price: 199 },
            ]
        },
        components: {
            shopItem
        },
        methods: {
            toggleIsCartByParent({ id }) {
                console.log(id);
                // 根据id修改list
                // props传递是单项的,而且是响应式的,也就是说父组件的data被修改了,传递到子组件得到props也就响应式的被修改了
                this.list = this.list.map(shop => {
                    if (shop.id === id) shop.isCart = !shop.isCart
                    return shop
                })
            }
        }
    })
</script>

子组件向父组件传参的过程:

  • 在子组件里使用 emit 向父组件触发一个自定义事件
methods: {
    toggleIsCart() {
        this.$emit("toggle-is-cart-form-item", {id: this.id})
    }
},
  • 在父组件上监听子组件的自定义事件
<shop-item v-for="shopItem in list" @toggle-is-cart-form-item="toggleIsCartByParent">
</shop-item>
  • 在父组件上写一个方法去修改
toggleIsCartByParent({ id }) {
    this.list = this.list.map(shop => {
        if (shop.id === id) shop.isCart = !shop.isCart
        return shop
    })
}
  • 子组件向父组件传参需要注意:
    • 子组件向父组件触发的事件名和父组件绑定的事件名必须完全一致
    • 子组件使用 emit 向父组件触发事件的时候,参数写在事件名的后面

二、eventBus(非父子组件之间的传参)

1、例子:

<template id="dage">
    <div>
        <p @click="playErdi()">打我弟</p>
    </div>
</template>

<template id="erdi">
    <div>
        <div>
            <p v-if="ku">哭 呜呜呜</p>
        </div>
    </div>
</template>
<div id="app">
    <dage></dage>
    <erdi></erdi>
</div>
<script>
    // 事件总线:event bus
    // bus其实就是一个空的Vue实例,作用是帮助非父子组件之间的同学
    const bus = new Vue()
    const dage = {
        template: '#dage',
        methods: {
            playErdi() {
                // 先把这个行为通知bus,bus再去通知其他关联组件
                // 向bue触发一个自定义事件
                bus.$emit('play', { ku: true })
            }
        }
    }
    const erdi = {
        template: '#erdi',
        data() {
            return {
                ku: false
            }
        },
        created() {
            // 通过bus去监听play事件
            bus.$on('play', ({ ku }) => {
                this.ku = ku
            })
        }
    }
    const app = new Vue({
        el: '#app',
        data: {
        },
        components: {
            dage,
            erdi
        }
    })
</script>

2、平级组件之间传参的过程:

先定义一个事件总线:event bus (作用是帮助非父子组件之间的通信)

const bus = new Vue()

然后在一个组件里使用 bus.$emitbus 触发一个自定义事件

playErdi() {
    // 先把这个行为通知bus,bus再去通知其他关联组件
    // 向bue触发一个自定义事件
    bus.$emit('play', { ku: true })
}

最后在另一个组件创建的过程当中通过 bus.$on 去监听事件

created() {
    // 通过bus去监听play事件
    bus.$on('play', ({ ku }) => {
        this.ku = ku
    })
}

注意:

在实战项目当中很少使用 event bus 去传递参数,一般都使用 VueX


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 848130454@qq.com

文章标题:Vue学习笔记—组件之间通信

文章字数:1.9k

本文作者:Spicy boy

发布时间:2018-07-06, 17:52:21

最后更新:2021-03-08, 17:20:59

原始链接:http://www.spicyboy.cn/2018/07/06/Vue%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E2%80%94%E7%BB%84%E4%BB%B6%E4%B9%8B%E9%97%B4%E9%80%9A%E4%BF%A1/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏