Arahan Vue melaksanakan komunikasi komponen: 1. Komponen induk menghantar data kepada komponen anak melalui "props", dan komponen anak boleh berkomunikasi dengan komponen induk melalui "$emit" 2. Melalui "ref/; Atribut $refs" untuk merealisasikan komunikasi komponen; 3. Komunikasi komponen direalisasikan melalui bas acara eventBus; 4. Komunikasi komponen direalisasikan menggunakan Vuex; 5. Komunikasi komponen direalisasikan melalui "$attrs" dan "$pendengar", dsb.
Persekitaran pengendalian tutorial ini: sistem Windows 10, versi Vue 3, komputer DELL G3
Bagaimanakah arahan vue melaksanakan komunikasi komponen?
Tujuh cara untuk Vue melaksanakan komunikasi antara komponen
: props
$emit
Ibu bapa kepada anak: Komponen induk memperkenalkan kanak-kanak melalui Import Komponen dan daftar, tambahkan atribut yang akan dihantar pada teg sub-komponen, dan sub-komponen menerimanya melalui props Terdapat dua bentuk penerimaan: satu melalui borang tatasusunan ['properties to be accepted '], dan yang satu lagi adalah melalui bentuk objek { }Ciri prop:
- Daripada anak kepada ibu bapa: Komponen induk menghantar kaedah peristiwa kepada komponen anak Komponen anak mencetuskan acara melalui
dan memanggil semula komponen induk$emit
Props hanya boleh menghantar nilai daripada komponen induk kepada komponen anak. cara pengikatan hiliran antara komponen induk dan anak. Data komponen anak akan dikemas kini secara responsif apabila komponen induk dikemas kini walau bagaimanapun, komponen anak tidak boleh menyebabkan data komponen induk dikemas kini.Contoh kod:
- Props boleh mentakrifkan satu atau lebih data secara eksplisit. Data yang diterima boleh terdiri daripada pelbagai jenis data dan ia juga boleh menghantar objek atau fungsi.
- Peraturan nama atribut prop: Jika anda menggunakan kotak unta dalam prop, tag dalam templat perlu ditulis dalam bentuk sempang.
Bapa kepada anak lelaki (penggunaan 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>
anak kepada ibu bapa (penggunaan $emit)
<template> <div id="son"> <p>{{msg}}</p> <button @click="fn">按钮</button> </div> </template> <script> export default { name: "son", props: ["msg", "fn"] }; </script>
Komponen induk:
Subkomponen:<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>
。
Komponen induk:
<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>
eventBus
Langkah penggunaan adalah seperti berikut:
(1) Wujudkan pusat acara untuk menguruskan komunikasi antara komponen
(2) Hantar acara dengan andaian terdapat dua adik beradik komponen firstCom dan secondCom:// event-bus.js import Vue from 'vue' export const EventBus = new Vue()
<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>
<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
Modul Vuex:
- state:用于数据的存储,是store中的唯一数据源
- getters:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算
- mutations:类似函数,改变state数据的唯一途径,且不能用于处理异步事件
- actions:类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作
- modules:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护
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 })
现在我们来讨论另一种情况:如果我们给出的组件关系图中A组件与D组件是隔代关系, 那它们之前进行通信有哪些方式呢?
- 使用props绑定来进行一级一级的信息传递, 如果D组件中状态改变需要传递数据给A, 使用事件系统一级级往上传递
- 使用eventBus,这种情况下还是比较适合使用, 但是碰到多人合作开发时, 代码维护性较低, 可读性也低
- 使用Vuex来进行数据管理, 但是如果仅仅是传递数据, 而不做中间处理,使用Vuex处理感觉有点大材小用了.
所以就有了 $attrs / $listeners ,通常配合 inheritAttrs 一起使用。
默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。
通过设置 inheritAttrs 到 false,这些默认行为将会被去掉。而通过实例 property $attrs 可以让这些 attribute 生效,且可以通过 v-bind 显性的绑定到非根元素上。
注意:这个选项不影响 class 和 style 绑定,Vue对class和style做了特殊处理
简单来说就是
- $attrs:包含了父作用域中不被认为 (且不预期为) props 的特性绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件。当一个组件没有声明任何 props 时,它包含所有父作用域的绑定 (class 和 style 除外)。
- $listeners:包含了父作用域中的 (不含 .native 修饰符) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件。它是一个对象,里面包含了作用在这个组件上的所有事件监听器,相当于子组件继承了父组件的事件。
代码示例:
父组件:
<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>
注意:
- 通过 $parent 访问到的是上一级父组件的实例,可以使用 $root 来访问根组件的实例
- 在组件中使用$children拿到的是所有的子组件的实例,它是一个数组,并且是无序的
- 在根组件 #app 上拿 $parent 得到的是 new Vue()的实例,在这实例上再拿 $parent 得到的是undefined,而在最底层的子组件拿 $children 是个空数组
- $children 的值是数组,而 $parent是个对象
子组件:
<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>
这种方式就是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)
跨代组件间通信其实就是多层的父子组件通信,同样可以使用上述父子组件间通信的方法,只不过需要多层通信会比较麻烦。
通过 $parent + $refs 以父组件为中间人来获取到兄弟组件,也可以进行通信。
使用 eventBus ,其实就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。它的本质是通过创建一个空的 Vue 实例来作为消息传递的对象,通信的组件引入这个实例,通信的组件通过在这个实例上监听和触发事件,来实现消息的传递。
推荐学习:《vue.js视频教程》
Atas ialah kandungan terperinci Bagaimana arahan vue melaksanakan komunikasi komponen. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!