vue指令怎么实现组件通信
时间:2023-01-31 16:03
vue指令实现组件通信的方法:1、父组件通过“props”的方式向子组件传递数据,而通过“$emit”子组件可以向父组件通信;2、通过“ref/$refs”属性实现组件通信;3、通过eventBus事件总线实现组件通信;4、使用Vuex实现组件通信;5、通过“$attrs”与“$listeners”实现组件通信等。 本教程操作环境:Windows10系统、Vue 3版、DELL G3电脑 vue指令怎么实现组件通信? Vue实现组件间通信的七种方式 父组件通过 props的特点: 代码示例: 父组件: 子组件: $emit 绑定一个自定义事件,当这个事件被执行的时候就会将参数传递给父组件,而父组件通过v-on监听并接收参数 父组件: 子组件: ref:这个属性用在子组件上,它的引用就指向了该子组件的实例,可以通过实例来访问组件的数据和方法;如果在普通的 DOM 元素上使用,引用指向的就是 DOM元素 父组件: 子组件: 其原理就是:事件订阅发布, 使用步骤如下: firstCom和secondCom的父组件: 在firstCom组件中发送事件: 在secondCom组件中接收事件: 在上述代码中,这就相当于将num值存贮在了事件总线中,在其他组件中可以直接访问。事件总线就相当于一个桥梁,不用组件通过它来通信。虽然看起来比较简单,但是这种方法也有不变之处,如果项目过大,使用这种方式进行通信,后期维护起来会很困难。 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. Vuex 解决了多个视图依赖于同一状态和来自不同视图的行为需要变更同一状态的问题,将开发者的精力聚焦于数据的更新而不是数据在组件之间的传递上 Vuex各个模块: Vuex使用步骤: (1)这里我们先新建 store文件夹, 对Vuex进行一些封装处理 在 store 文件夹下添加 index.js 文件 (2)在 store 文件夹下添加 (3)然后在项目的 (4)封装很愉快结束了了,然后就正常操作即可 现在我们来讨论另一种情况:如果我们给出的组件关系图中A组件与D组件是隔代关系, 那它们之前进行通信有哪些方式呢? 所以就有了 $attrs / $listeners ,通常配合 inheritAttrs 一起使用。 默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。 通过设置 inheritAttrs 到 false,这些默认行为将会被去掉。而通过实例 property $attrs 可以让这些 attribute 生效,且可以通过 v-bind 显性的绑定到非根元素上。 注意:这个选项不影响 class 和 style 绑定,Vue对class和style做了特殊处理 简单来说就是 代码示例: 父组件: 儿子组件: 孙子组件: 注意: 子组件: 父组件: 这种方式就是vue中依赖注入,该方法用于 父子组件之间 的通信。当然这里所说的父子不一定是真正的父子,也可以是祖孙组件,在层数很深的情况下,可以使用这种方式来进行传值。就不用一层一层的传递数据了。 provide和inject是vue提供的两个钩子,和data、methods是同级的。并且provide的书写形式和data一样。 注意: 依赖注入所提供的属性是非响应式的。 用法: 父组件: 子组件: 还有另一种写法,这种写法可以访问父组件中的所有属性: 跨代组件间通信其实就是多层的父子组件通信,同样可以使用上述父子组件间通信的方法,只不过需要多层通信会比较麻烦。 通过 $parent + $refs 以父组件为中间人来获取到兄弟组件,也可以进行通信。 使用 eventBus ,其实就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。它的本质是通过创建一个空的 Vue 实例来作为消息传递的对象,通信的组件引入这个实例,通信的组件通过在这个实例上监听和触发事件,来实现消息的传递。 推荐学习:《vue.js视频教程》 以上就是vue指令怎么实现组件通信的详细内容,更多请关注gxlsystem.com其它相关文章!1. props / $emit
props
的方式向子组件传递数据,而通过$emit
子组件可以向父组件通信:$emit
触发事件,回调给父组件父传子(prop的用法)
<template>
<div id="father">
<son :msg="msg" :fn="myFunc"></son>
</div>
</template>
<script>
import son from "./son.vue";
export default {
name: "father",
components: {
son
},
data() {
msg: "我是父组件";
},
methods: {
myFunc() {
console.log("我是父组件的方法");
}
}
};
</script>
<template>
<div id="son">
<p>{{msg}}</p>
<button @click="fn">按钮</button>
</div>
</template>
<script>
export default {
name: "son",
props: ["msg", "fn"]
};
</script>
子传父($emit的用法)
<template>
<div id="father">
<son :arrList="arrList" @changeIndex="changeIndex"></son>
<p>{{currentIndex}}</p>
</div>
</template>
<script>
import son from './son.vue'
export default {
name: 'father',
components: { son},
data() {
return {
currentIndex: -1,
arrList: ['龙族', '绘梨衣', '前端','后端']
}
},
methods: {
changeIndex(index) {
this.currentIndex = index
}
}
}
</script>
<template>
<div>
<div v-for="(item, index) in arrList" :key="index" @click="emitIndex(index)">{{item}}</div>
</div>
</template>
<script>
export default {
props: ['arrList'],
methods: {
emitIndex(index) {
this.$emit('changeIndex', index) // 触发父组件的方法,并传递参数index
}
}
}
</script>
2.ref / $refs
。
<template>
<child ref="child"></component-a>
</template>
<script>
import child from './child.vue'
export default {
components: { child },
mounted () {
console.log(this.$refs.child.name); // mySon
this.$refs.child.sayHello(); // Hello father!
}
}
</script>
<template>
<div id="app"></div>
</template>
<script>
export default {
name:'child',
data () {
return {
name: 'mySon'
}
},
methods: {
sayHello () {
console.log('Hello father!')
}
}
}
</script>
3.eventBus(事件总线)
eventBus
又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所以组件都可以通知其他组件。(1)创建事件中心管理组件之间的通信
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
(2)发送事件 假设有两个兄弟组件firstCom和secondCom:
<template>
<div>
<first-com></first-com>
<second-com></second-com>
</div>
</template>
<script>
import firstCom from './firstCom.vue'
import secondCom from './secondCom.vue'
export default {
components: { firstCom, secondCom }
}
</script>
<template>
<div>
<button @click="add">点击增加</button>
</div>
</template>
<script>
import {EventBus} from './event-bus.js' // 引入事件中心
export default {
data(){
return{
num:0
}
},
methods:{
add(){
EventBus.$emit('addition', {
num:this.num++
})
}
}
}
</script>
(3)接收事件
<template>
<div>求和: {{count}}</div>
</template>
<script>
import { EventBus } from './event-bus.js'
export default {
data() {
return {
count: 0
}
},
mounted() {
EventBus.$on('addition', param => {
this.count = this.count + param.num;
})
}
}
</script>
4.Vuex
// index.js
// 自动挂载指定目录下的store
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
let modules = {}
// @/store/module 目录下的文件自动挂载为 store 模块
const subModuleList = require.context('@/store/modules', false, /.js$/)
subModuleList.keys().forEach(subRouter => {
const moduleName = subRouter.substring(2, subRouter.length - 3)
modules[moduleName] = subModuleList(subRouter).default
})
//也可自己手动挂载(自行选择)
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules
})
module
文件夹,在module文件夹再新建 user.js
文件// user.js
import user from '@/utils/user.js'
import userApi from '@/apis/user'
import { OPEN_ACCOUNT_STAGE, STAGE_STATUS } from '@/constant'
let getUserPromise = null
export default {
namespaced: true,
state() {
return {
userInfo: null, // 用户信息
isLogined: !!user.getToken(), // 是否已经登录
}
},
mutations: {
// 更新用户信息
updateUser(state, payload) {
state.isLogined = !!payload
state.userInfo = payload
},
},
actions: {
// 获取当前用户信息
getUserInfo(context, payload) {
//相关代码
},
// 登出
logout(context, payload = {}) {
// 是否手动退出
const { manual } = payload
if (manual) {
await userApi.postLogout()
}
user.clearToken()
context.commit('updateUser', null)
},
}
}
main.js
文件中引入import Vue from 'vue'
import App from '@/app.vue'
import { router } from '@/router'
import store from '@/store/index'
const vue = new Vue({
el: '#app',
name: 'root',
router,
store,
render: h => h(App),
})
this.$store.state.user.isLogined
this.$store.state.user.userInfo
this.$store.commit('user/updateUser', {})
await this.$store.dispatch('user/logout', { manual: true })
5.$attrs与 $listeners
inheritAttrs
<template>
<child :name="name" :age="age" :infoObj="infoObj" @updateInfo="updateInfo" @delInfo="delInfo" />
</template>
<script>
import Child from '../components/child.vue'
export default {
name: 'father',
components: { Child },
data () {
return {
name: '绘梨衣',
age: 22,
infoObj: {
from: '河北',
job: 'superman',
hobby: ['reading', 'writing', 'eating']
}
}
},
methods: {
updateInfo() {
console.log('update info');
},
delInfo() {
console.log('delete info');
}
}
}
</script>
<template>
<!-- 通过 $listeners 将父作用域中的事件,传入 grandSon 组件,使其可以获取到 father 中的事件 -->
<grand-son :height="height" :weight="weight" @addInfo="addInfo" v-bind="$attrs" v-on="$listeners" />
</template>
<script>
import GrandSon from '../components/grandSon.vue'
export default {
name: 'child',
components: { GrandSon },
props: ['name'],
data() {
return {
height: '170cm',
weight: '55kg'
};
},
created() {
console.log(this.$attrs);
// 结果:age, infoObj, 因为父组件共传来name, age, infoObj三个值,由
//于name被 props接收了,所以只有age, infoObj属性
console.log(this.$listeners); // updateInfo: f, delInfo: f
},
methods: {
addInfo () {
console.log('add info')
}
}
}
</script>
<template>
<div>
{{ $attrs }} --- {{ $listeners }}
<div>
</template>
<script>
export default {
props: ['weight'],
created() {
console.log(this.$attrs); // age, infoObj, height
console.log(this.$listeners)
// updateInfo: f, delInfo: f, addInfo: f
this.$emit('updateInfo')
// 可以触发 father 组件中的updateInfo函数
}
}
</script>
6.$parent / $children
用法:
<template>
<div>
<span>{{message}}</span>
<p>父组件的值为: {{parentVal}}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Vue'
}
},
computed:{
parentVal(){
return this.$parent.msg;
}
}
}
</script>
<template>
<div class="app">
<div>{{msg}}</div>
<child></child>
<button @click="change">点击改变子组件值</button>
</div>
</template>
<script>
import child from './child.vue'
export default {
components: { child },
data() {
return {
msg: 'Hello'
}
},
methods: {
change() {
// 获取到子组件
this.$children[0].message = 'JavaScript'
}
}
}
</script>
7.依赖注入(provide / inject)
provide() {
return {
num: this.num
};
}
inject: ['num']
provide() {
return {
app: this
};
}
data() {
return {
num: 111
};
}
inject: ['app']
console.log(this.app.num)
总结
1.父子组件间通信
2.跨代组件间通信
3.兄弟组件间通信
4.任意组件间通信