vue组件之间的数据通信

组件之间的数据传递(通信)

1.父子组件

1).在组件内部定义另一个组件称为父子组件
2).子组件只能在父组件中使用
3).默认情况下,子组件是无法访问父组件的数据的
html部分:
<div class="box" id="app">
    <my-hello></my-hello>
    
</div>

<template id="hello">
    <div>
        <p>我是hello组件</p>
        <p>我是hello组件的数据:{{name}},{{age}},{{user.id}}</p>
        <hr>
        <my-world></my-world>
    </div>
</template>

<template id="world">
    <div>
        <p>我是world子组件</p>
    </div>
</template>

js部分:
var vm = new Vue({
    el: "#app",
    data:{
        
    },
    components:{
        "my-hello":{
            template:"#hello",
            data:function(){
                return {
                    msg:"学习vue",
                    name:"yang",
                    age:27,
                    user:{id:666, userName:"杨义"}
                }
            },
            components:{         // 子组件 在hello父组件内部
                "my-world":{
                    template:"#world"
                }
            }
        }
    }
})

2.组件中的数据传递(通信)

2.1 子组件访问父组件的数据
a). 在子组件调用的时候,绑定需要访问的数据msg,并申明一个名字message。
    示例:<my-hello :message="msg"></my-hello>
b). 在子组件js内部,使用props来接受绑定的数据名

c). 最后在使用的时候{{申明的数据名}} ===> {{message}}
html部分:
    <div class="box" id="app">
        <my-hello></my-hello>

    </div>

    <template id="hello">
        <div>
            <p>我是hello组件</p>
            <p>我是hello组件的数据:{{name}},{{age}},{{user.id}}</p>
            <hr>
            <my-world v-bind:message="msg"></my-world>
        </div>
    </template>

    <template id="world">
        <div>
            <p>我是world子组件</p>
            <p>访问父组件的数据:{{message}}</p>
        </div>
    </template>

    js部分:
    var vm = new Vue({
        el: "#app",
        data:{
            
        },
        components:{
            "my-hello":{
                template:"#hello",
                data:function(){
                    return {
                        msg:"学习vue",
                        name:"yang",
                        age:27,
                        user:{id:666, userName:"杨义"}
                    }
                },
                components:{         // 子组件 在hello父组件内部
                    "my-world":{
                        template:"#world",
                        props:['message']
                    }
                }
            }
        }
    })

2.2 父组件访问子组件的数据
a).子组件使用 $emit发送数据给父组件,写法:this.$emit('事件名','需要发送的数据')
例:this.$emit('e-world',this.name,this,age)
b).子组件在父组件内调用的时候执行一个方法(@事件名="方法"),同时父组件自定义一个方法来接受子组件传过来的数据(例子中的getData方法)
例:
	<template id="world">
		<div>
			<p>我是父组件</p>
			<hello @e-world="getData"></hello>
		</div>
	</template>
	...
	// 这里是父组件内部的代码,不是vm根组件的代码
	data:{
		name:"",
		age:""
	},
	methods:{
		getData:function(name, age){
			this.name = name;
			this.age = age
		}
	}

3.父子组件间的单项数据流

父组件的数据一旦发生改变,子组件的数据会同步发生改变,反过来子组件数据改变时,父组件是不会改变的
而且子组件是不允许直接修改父组件的数据,会报错
解决方法:
    1).如果子组件想把父组件的数据拿到当成局部数据来使用,可以用一个变量存起来
    components:{
        "hello":{
            template:"#hello",
            props:["hellomsg"],     // 接受到父组件的hellomsg ==> <hello v-bind:hellomsg="msg"></hello>
            data:function(){
                return {
                    usermsg:this.hellomsg   //  拿usermsg存起来当局部数据来使用
                }
            }
        }
    }

    2).如果子组件想修改拿到父组件的数据,并同步给父组件有两个方法:
        a).可以使用修饰符:sync  1.0支持 2.0-2.2不支持
            html部分使用:
            <hello v-bind:hellomsg.sync="msg"></hello>

            js部分需要在子组件内methods使用:this.$emit("update:需要修改的数据","修改后的数据")
            components:{
                "hello":{
                    template:"#hello",
                    props:["hellomsg"],  
                    methods:function(){
                        this.$emit("update:hellomsg","hello world")
                    }
                }
            }
        b).因为js数据和对象都是引用类型指向同一内存空间,所以我们可以直接将父组件的数据包装成一个对象,修改对象的属性
            html部分使用:
            <hello v-bind:users="msg"></hello>

            js部分:
            users:{         // 父组件的属性,包装成一个对象
                age:18
            }
            -------------------------------------
            components:{
                "hello":{
                    template:"#hello",
                    props:["users"],  
                    methods:function(){
                        this.users.age = 100;
                    }
                }
            }

4.非父子组件之间的通信

非父子组件之间的通信,可以通过一个空的vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件
1).var Event = new Vue();

2).发送数据:Event.$emit("事件名","数据");
"my-b":{
    template:"#b",
    data:function(){
        return {
            age:18
        }
    },
    methods:{
        sendb:function(){
            Event.$emit("data-b",this.age)      // 发送age
        }
    }
}

3).接受数据:Event.$on("事件名",data=>{})  es6箭头函数,可以防止改变this指向
"my-c":{
    template:"#c",
    data:function(){
        return {    
            age:""          // 初始化age的值
        }
    },
    mounted:function(){         // 钩子函数 当模版编译完成之后执行
        Event.$on("data-a",data => {
            this.name = data;
        })
        Event.$on("data-b",data => {        // 接受age == data是回调函数的参数
            this.age = data;            // 这里的this如果不是箭头函数那指向的会是全局的vue实例 - Event
        })
    }
}

slot内容分发

用于获取组件内的原内容
组件:
<template id="hello">
    <div>
        <slot name="list1"></slot>      // 掉哟个slot时name = 组件调用时申明的slot名字      
        <p>{{name}}</p>
        <slot name="list2"></slot>
    </div>
</template>

组件调用(中间带内容)指定一个slot的名字:
<hello>
    <ul slot="list1">
        <li>aaa</li>
        <li>bbb</li>
        <li>ccc</li>
    </ul>
    <ol slot="list2">
        <li>111</li>
        <li>222</li>
        <li>333</li>
    </ol>
</hello>

js:
var vm = new Vue({
    el: "#app",
    data:{
        
    },
    components:{
        "hello":{
            template:"#hello",
            data:function(){
                return {
                    name:"yang"
                }
            }
        }
    }
})
<think>嗯,用户想了解Vue.js组件通信的方法和最佳实践。根据之前的引用资料,我记得Vue提供了多种通信方式,比如props、事件、Vuex等。不过用户可能对这些方法的具体使用场景和最佳实践不太清楚,需要详细解释。 首先,我需要整理不同的通信方式,按父子组件、兄弟组件、跨层级组件来分类。比如父传子用props,子传父用自定义事件,兄弟组件可以用事件总线或者Vuex。然后还有provide/inject用于祖先和后代之间的通信,Vuex适用于大型应用的状态管理。 然后要考虑用户可能的实际需求,比如简单场景可能不需要Vuex,而复杂应用则需要。同时,要提到每种方法的优缺点,比如事件总线在项目较大时可能难以维护,而Vuex虽然强大但需要一定的学习成本。 还需要结合引用中的示例,比如引用2中的props示例,引用3中的Vuex示例,这样能让回答更有依据。此外,引用4提到第8章专门讲组件通信,可能有一些系统性的总结,可以强调系统学习的重要性。 用户可能想知道在什么情况下选择哪种方法,所以最佳实践部分需要分场景讨论,比如简单父子通信用props和事件,跨层级用provide/inject,复杂状态用Vuex或Pinia。同时,要提到组合式API带来的变化,比如useContext的替代方案。 最后,生成相关问题时要覆盖常见疑问,比如性能优化、Vue3的变化、事件总线的问题,以及如何选择状态管理工具。这样用户如果有后续问题,可以引导他们深入探索。</think>### Vue.js 组件通信的方法与最佳实践 Vue.js 组件通信是构建复杂应用的核心能力之一。根据不同的场景和需求,Vue 提供了多种通信方式,以下是主要方法及其最佳实践: --- #### 一、基础通信方式 1. **Props(父传子)** 父组件通过属性向子组件传递数据,子组件通过 `props` 接收。 ```javascript // 父组件 <ChildComponent :message="parentMessage" /> // 子组件 props: ['message'] ``` **最佳实践**: - 使用类型验证(如 `type: String`)提升代码健壮性[^2] - 避免直接修改 `props`,应通过事件通知父组件更新数据 2. **自定义事件(子传父)** 子组件通过 `$emit` 触发事件,父组件监听并响应。 ```javascript // 子组件 this.$emit('update-data', newData); // 父组件 <ChildComponent @update-data="handleData" /> ``` **最佳实践**: - 事件名使用 kebab-case(如 `update-data`)保持规范 --- #### 二、跨层级通信 3. **事件总线(Event Bus)** 通过空的 Vue 实例作为中央事件枢纽,实现任意组件通信。 ```javascript // 创建事件总线 export const eventBus = new Vue(); // 组件A发送事件 eventBus.$emit('global-event', payload); // 组件B监听事件 eventBus.$on('global-event', callback); ``` **最佳实践**: - 适用于小型项目,复杂场景建议改用 Vuex[^3] - 需手动清理事件监听(`beforeDestroy` 中调用 `$off`) 4. **provide/inject** 祖先组件通过 `provide` 提供数据,后代组件通过 `inject` 注入。 ```javascript // 祖先组件 provide() { return { theme: this.theme }; } // 后代组件 inject: ['theme'] ``` **最佳实践**: - 适合深层嵌套组件,但会破坏组件独立性[^4] - Vue 3 中支持响应式数据(需显式标记 `ref` 或 `reactive`) --- #### 三、全局状态管理 5. **Vuex(官方状态管理库)** 通过集中式存储管理全局状态,适用于中大型项目。 ```javascript // store.js mutations: { increment(state) { state.counter++; } } // 组件中使用 this.$store.commit('increment'); ``` **最佳实践**: - 遵循单向数据流:组件 → 调用 `actions` → 提交 `mutations` → 修改 `state`[^3] - 模块化拆分复杂状态(`modules`) - Vue 3 推荐使用 Pinia(更简洁的 API 设计) --- #### 四、最佳实践总结 | 场景 | 推荐方式 | 说明 | |------|----------|------| | 父子组件简单通信 | Props + 事件 | 最直接、易维护 | | 兄弟组件通信 | Vuex/Pinia 或事件总线 | 事件总线适合简单场景,复杂场景用状态管理 | | 跨层级通信 | provide/inject 或 Vuex | 深层嵌套优先 provide/inject | | 全局共享状态 | Vuex/Pinia | 中大型项目必备 | **性能优化建议**: - 避免滥用 Vuex,仅全局状态使用 - 使用计算属性缓存频繁访问的数据 - 对大型列表采用虚拟滚动(如 `vue-virtual-scroller`) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值