vue指令如何实现组件通信

发布时间:2023-02-01 16:11:05 作者:iii
来源:亿速云 阅读:157

本文小编为大家详细介绍“vue指令如何实现组件通信”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue指令如何实现组件通信”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

vue指令实现组件通信的方法:1、父组件通过“props”的方式向子组件传递数据,而通过“$emit”子组件可以向父组件通信;2、通过“ref/$refs”属性实现组件通信;3、通过eventBus事件总线实现组件通信;4、使用Vuex实现组件通信;5、通过“$attrs”与“$listeners”实现组件通信等。

Vue实现组件间通信的七种方式

1. props / $emit

父组件通过props的方式向子组件传递数据,而通过$emit 子组件可以向父组件通信:

props的特点:

代码示例:

父传子(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的用法)

$emit 绑定一个自定义事件,当这个事件被执行的时候就会将参数传递给父组件,而父组件通过v-on监听并接收参数

父组件:

<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

ref:这个属性用在子组件上,它的引用就指向了该子组件的实例,可以通过实例来访问组件的数据和方法;如果在普通的 DOM 元素上使用,引用指向的就是 DOM元素

父组件:

<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:

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>

在firstCom组件中发送事件:

<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)接收事件

在secondCom组件中接收事件:

<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>

在上述代码中,这就相当于将num值存贮在了事件总线中,在其他组件中可以直接访问。事件总线就相当于一个桥梁,不用组件通过它来通信。虽然看起来比较简单,但是这种方法也有不变之处,如果项目过大,使用这种方式进行通信,后期维护起来会很困难。

4.Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.

Vuex 解决了多个视图依赖于同一状态和来自不同视图的行为需要变更同一状态的问题,将开发者的精力聚焦于数据的更新而不是数据在组件之间的传递上

Vuex各个模块:

Vuex使用步骤:

(1)这里我们先新建 store文件夹, 对Vuex进行一些封装处理

在 store 文件夹下添加 index.js 文件

// 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
})

(2)在 store 文件夹下添加 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)
   },
 }
}

(3)然后在项目的 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),
})

(4)封装很愉快结束了了,然后就正常操作即可

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

现在我们来讨论另一种情况:如果我们给出的组件关系图中A组件与D组件是隔代关系, 那它们之前进行通信有哪些方式呢?

  1. 使用props绑定来进行一级一级的信息传递, 如果D组件中状态改变需要传递数据给A, 使用事件系统一级级往上传递

  2. 使用eventBus,这种情况下还是比较适合使用, 但是碰到多人合作开发时, 代码维护性较低, 可读性也低

  3. 使用Vuex来进行数据管理, 但是如果仅仅是传递数据, 而不做中间处理,使用Vuex处理感觉有点大材小用了.

所以就有了 $attrs / $listeners ,通常配合 inheritAttrs 一起使用。

inheritAttrs

默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。

通过设置 inheritAttrs 到 false,这些默认行为将会被去掉。而通过实例 property $attrs 可以让这些 attribute 生效,且可以通过 v-bind 显性的绑定到非根元素上。

注意:这个选项不影响 class 和 style 绑定,Vue对class和style做了特殊处理

简单来说就是

代码示例:

父组件:

<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)

这种方式就是vue中依赖注入,该方法用于 父子组件之间 的通信。当然这里所说的父子不一定是真正的父子,也可以是祖孙组件,在层数很深的情况下,可以使用这种方式来进行传值。就不用一层一层的传递数据了。

provide和inject是vue提供的两个钩子,和data、methods是同级的。并且provide的书写形式和data一样。

注意: 依赖注入所提供的属性是非响应式的。

用法:

父组件:

provide() { 
   return {    
       num: this.num  
   };
}

子组件:

inject: ['num']

还有另一种写法,这种写法可以访问父组件中的所有属性:

provide() {
return {
   app: this
 };
}
data() {
return {
   num: 111
 };
}

inject: ['app']
console.log(this.app.num)

读到这里,这篇“vue指令如何实现组件通信”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注亿速云行业资讯频道。

推荐阅读:
  1. vue组件及通信
  2. vue组件通信

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

vue

上一篇:vue如何修改table行高

下一篇:css如何实现滚动条不占用高度

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》