ホームページ > 記事 > ウェブフロントエンド > vue 命令がコンポーネント通信を実装する方法
Vue 命令はコンポーネント通信メソッドを実装します: 1. 親コンポーネントは「props」を通じて子コンポーネントにデータを渡し、子コンポーネントは「$emit」を通じて親コンポーネントと通信できます; 2. 「ref」を通じて/$refs"属性でコンポーネント通信を実現; 3.eventBusイベントバスでコンポーネント通信を実現; 4.Vuexを使ってコンポーネント通信を実現; 5."$attrs"や"$listeners"などでコンポーネント通信を実現
このチュートリアルの動作環境: Windows 10 システム、Vue バージョン 3、DELL G3 コンピューター
vue 命令はどのように実現するのかコンポーネント通信?
#Vue がコンポーネント間の通信を実装する 7 つの方法
props を介して子コンポーネントにデータを渡し、子コンポーネントは
$emit を介して親コンポーネントと通信できます。
##Parent Passing子へ: 親コンポーネントは、import を通じて子コンポーネントを導入し、登録します。子コンポーネントのラベルに渡す属性を追加します。子コンポーネントは、props を通じてそれを受け取ります。受け取りの形式は 2 つあります。1 つは配列形式 [ 2 つ目は、オブジェクト フォーム { }プロップは値を渡すことしかできません。親コンポーネントから子コンポーネントへ: Props は、親コンポーネントと子コンポーネントの間で一方向の下流バインディングを形成します。子コンポーネントのデータは、親コンポーネントが更新されるとそれに応じて更新されますが、子コンポーネントは親コンポーネントのデータを更新させることはできません。
- を子から親に渡すことです: 親コンポーネントはイベント メソッドを子コンポーネントに渡し、子コンポーネントは # を通じてイベントをトリガーします。 ##$emit
と親コンポーネントにコールバックします- プロップの特性:
props は 1 つ以上のデータを表示できます。受信したデータにはさまざまなデータ型があり、オブジェクトや関数を渡すこともできます。
- props 属性名の規則: 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 バインドa self イベントを定義します。このイベントが実行されると、パラメーターが親コンポーネントに渡され、親コンポーネントは 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>
Child を通じてパラメーターをリッスンして受け取ります。コンポーネント:
<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 要素
を指します。親コンポーネント: <pre class="brush:php;toolbar:false"><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></pre>
子コンポーネント:
<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手順は次のとおりです。 (1) コンポーネント間の通信を管理するイベント センターを作成します。
// event-bus.js import Vue from 'vue' export const EventBus = new Vue()
(2) イベントを送信します。 firstCom という 2 つの兄弟コンポーネントがあるとします。および 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) イベントを受信
Receive in 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>
4.Vuex
Vuex は、Vue.js アプリケーション専用に開発された状態管理パターンです。集中ストレージを使用してアプリケーションのすべてのコンポーネントの状態を管理し、対応するルールを使用して状態が予測可能な方法で変化することを保証します。
Vuex は、同じものに依存する複数のビューの問題を解決します。異なるビューからの動作が同じ状態を変更する必要があるという問題により、開発者のエネルギーはコンポーネント間のデータ転送ではなくデータの更新に集中します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 })5.$attrs与 $listeners
现在我们来讨论另一种情况:如果我们给出的组件关系图中A组件与D组件是隔代关系, 那它们之前进行通信有哪些方式呢?
- 使用props绑定来进行一级一级的信息传递, 如果D组件中状态改变需要传递数据给A, 使用事件系统一级级往上传递
- 使用eventBus,这种情况下还是比较适合使用, 但是碰到多人合作开发时, 代码维护性较低, 可读性也低
- 使用Vuex来进行数据管理, 但是如果仅仅是传递数据, 而不做中间处理,使用Vuex处理感觉有点大材小用了.
所以就有了 $attrs / $listeners ,通常配合 inheritAttrs 一起使用。
inheritAttrs
默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。
通过设置 inheritAttrs 到 false,这些默认行为将会被去掉。而通过实例 property $attrs 可以让这些 attribute 生效,且可以通过 v-bind 显性的绑定到非根元素上。
注意:这个选项不影响 class 和 style 绑定,Vue对class和style做了特殊处理
简单来说就是
- inheritAttrs:true 时继承除props之外的所有属性
- inheritAttrs:false 只继承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>6.$parent / $children
- 使用$parent可以让组件访问父组件的实例(访问的是上一级父组件的属性和方法)。
- 使用 $children 可以让组件访问子组件的实例,但是, $children 并不能保证顺序,并且访问的数据也不是响应式的。
注意:
- 通过 $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>7.依赖注入(provide / inject)
这种方式就是vue中依赖注入,该方法用于 父子组件之间 的通信。当然这里所说的父子不一定是真正的父子,也可以是祖孙组件,在层数很深的情况下,可以使用这种方式来进行传值。就不用一层一层的传递数据了。
provide和inject是vue提供的两个钩子,和data、methods是同级的。并且provide的书写形式和data一样。
- 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.父子组件间通信
- 子组件通过 props 属性来接受父组件的数据,然后父组件在子组件上注册监听事件,子组件通过 emit 触发事件来向父组件发送数据。
- 通过 ref 属性给子组件设置一个名字。父组件通过 $refs 组件名来获得子组件,子组件通过 $parent 获得父组件,这样也可以实现通信。
- 使用 provide/inject,在父组件中通过 provide提供变量,在子组件中通过 inject 来将变量注入到组件中。不论子组件有多深,只要调用了 inject 那么就可以注入 provide中的数据
2.跨代组件间通信
跨代组件间通信其实就是多层的父子组件通信,同样可以使用上述父子组件间通信的方法,只不过需要多层通信会比较麻烦。
3.兄弟组件间通信
通过 $parent + $refs 以父组件为中间人来获取到兄弟组件,也可以进行通信。
4.任意组件间通信
使用 eventBus ,其实就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。它的本质是通过创建一个空的 Vue 实例来作为消息传递的对象,通信的组件引入这个实例,通信的组件通过在这个实例上监听和触发事件,来实现消息的传递。
推荐学习:《vue.js视频教程》
以上がvue 命令がコンポーネント通信を実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。