vue はデータ駆動型のビュー更新用のフレームワークであるため、コンポーネント間のデータ通信は vue にとって非常に重要です。では、コンポーネント間のデータ通信はどのように行われるのでしょうか?まず、通信方法を理解しやすくするために、Vue のコンポーネント間にどのような関係があるかを知る必要があります。
vue コンポーネント内の関係の説明:
上の図に示すように、A と B、A と C、B構成要素 C と E の関係は父子関係、B と C の関係は兄弟、A と D、A と E の関係は世代関係、D と E の関係はいとこ (直接の親戚ではありません) 上記の関係の場合、クラスは次のとおりです:
親コンポーネントと子コンポーネント間の通信
Communication親以外のコンポーネントと子コンポーネントの間 (兄弟コンポーネント、世代が分離されたコンポーネントなど)
1. props / $emit
親コンポーネントは、props を通じて子コンポーネントにデータを渡し、$emit を通じて子コンポーネントは親コンポーネントと通信できます。
1. 親コンポーネントが子コンポーネントに値を渡す
親コンポーネントが子コンポーネントにデータを渡す方法: 子で親コンポーネントのセクション.vue を取得する方法コンポーネント記事.vue 記事内のデータ
// section父组件 <template> <p class="section"> <com-article :articles="articleList"></com-article> </p> </template> <script> import comArticle from './test/article.vue' export default { name: 'HelloWorld', components: { comArticle }, data() { return { articleList: ['one', 'two', 'three','four','fives'] } } } </script> // 子组件 article.vue <template> <p> <span v-for="(item, index) in articles" :key="index">{{item}}</span> </p> </template> <script> export default { props: ['articles'] } </script>
概要: prop は、上位レベルのコンポーネントから下位レベルのコンポーネント (親子コンポーネント) にのみ渡すことができます。これは、いわゆる一方向データです。流れ。また、prop は読み取り専用のため変更できず、すべての変更は無効となり、警告が発行されます。
2. 子コンポーネントは親コンポーネントに値を渡します
$emit についての私自身の理解は次のとおりです: $emit はカスタム イベントをバインドします。このステートメントが実行されると、パラメーター arg が親コンポーネントに渡され、親コンポーネントは v-on を介してパラメーターをリッスンして受け取ります。例を通して、子コンポーネントが親コンポーネントにデータを渡す方法を説明します。前の例に基づいて、ページによってレンダリングされた記事項目をクリックすると、親コンポーネントの添字
// 父组件中 <template> <p class="section"> <com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article> <p>{{currentIndex}}</p> </p> </template> <script> import comArticle from './test/article.vue' export default { name: 'HelloWorld', components: { comArticle }, data() { return { currentIndex: -1, articleList: ['one', 'two', 'three','four','fives'] } }, methods: { onEmitIndex(idx) { this.currentIndex = idx } } } </script> <template> <p> <p v-for="(item, index) in articles" :key="index" @click="emitIndex(index)">{{item}}</p> </p> </template> <script> export default { props: ['articles'], methods: { emitIndex(index) { this.$emit('onEmitIndex', index) } } } </script>
// 父组件中 <template> <p class="hello_world"> <p>{{msg}}</p> <com-a></com-a> <button @click="changeA">点击改变子组件值</button> </p> </template> <script> import ComA from './test/comA.vue' export default { name: 'HelloWorld', components: { ComA }, data() { return { msg: 'Welcome' } }, methods: { changeA() { // 获取到子组件A this.$children[0].messageA = 'this is new value' } } } </script> // 子组件中 <template> <p class="com_a"> <span>{{messageA}}</span> <p>获取父组件的值为: {{parentVal}}</p> </p> </template> <script> export default { data() { return { messageA: 'this is old' } }, computed:{ parentVal(){ return this.$parent.msg; } } } </script>
が配列に表示されます。$parent を取るなどの境界条件に注意してください#app で得られるものは new Vue() のインスタンスです。このインスタンスで $parent を取ると un 未定義になり、一番下の子コンポーネントで $children を取ると空の配列になります。また、$parent と $children の値が異なることに注意してください。$children の値は配列であり、$parent はオブジェクトです。
概要
上記 2 つのメソッドは、間の通信に使用されます。親コンポーネントと子コンポーネント、および props が通信に使用されます。親子コンポーネント通信の方が一般的ですが、どちらも非親子コンポーネント間の通信には使用できません。
3. Provide/ inject
コンセプト:
provide/ inject は vue2.2.0 の新しい API で、シンプルです。つまり、親コンポーネントは、provide を通じて変数を提供し、次に、inject を通じて子コンポーネントに変数を注入します。
注: ここでサブコンポーネントがどれほど深くネストされているかに関係なく、inject が呼び出されている限り、provide 内のデータを注入できます。また、現在の親コンポーネントの props 属性からデータを返すことに限定されません
検証例
# 次に、例を使用して上記の説明を検証します。 A.vue、B.vue、C.vue の 3 つのコンポーネントがあるとします。ここで、C は B のサブコンポーネントです。 B は A のサブコンポーネントです。
// A.vue <template> <p> <comB></comB> </p> </template> <script> import comB from '../components/test/comB.vue' export default { name: "A", provide: { for: "demo" }, components:{ comB } } </script> // B.vue <template> <p> {{demo}} <comC></comC> </p> </template> <script> import comC from '../components/test/comC.vue' export default { name: "B", inject: ['for'], data() { return { demo: this.for } }, components: { comC } } </script> // C.vue <template> <p> {{demo}} </p> </template> <script> export default { name: "C", inject: ['for'], data() { return { demo: this.for } } } </script>
4. ref / refs
ref: 通常の DOM 要素で使用される場合、参照DOM 要素を指します。サブコンポーネントで使用される場合、参照はコンポーネント インスタンスを指します。コンポーネントのメソッドを直接呼び出すことも、インスタンスを通じてデータにアクセスすることもできます。ref を使用してコンポーネントにアクセスする例を見てみましょう:
// 子组件 A.vue export default { data () { return { name: 'Vue.js' } }, methods: { sayHello () { console.log('hello') } } } // 父组件 app.vue <template> <component-a ref="comA"></component-a> </template> <script> export default { mounted () { const comA = this.$refs.comA; console.log(comA.name); // Vue.js comA.sayHello(); // hello } } </script>
5 、eventBus
eventBus はイベント バスとも呼ばれ、vue の通信ブリッジの概念として使用できます。コンポーネントは同じイベント センターを共有し、センターに登録できます。イベントを送信または受信することで、コンポーネントは他のコンポーネントに通知できます。
EventBus には不便な点もあります。プロジェクトが大規模になると、メンテナンスが困難な災害が簡単に発生する可能性があります。
EventBus を使用して Vue プロジェクトのコンポーネント間のデータ通信を実現するにはどうすればよいですか? 具体的には、次のような方法があります。次の手順
1. 初期化
最初に、他のモジュールが使用または監視できるように、イベント バスを作成してエクスポートする必要があります。
// event-bus.js import Vue from 'vue' export const EventBus = new Vue()
2. イベントの送信
##addingNum と showNum という 2 つのコンポーネントがあるとします。これら 2 つのコンポーネントは兄弟コンポーネントまたは親子コンポーネントにすることができます。ここでは例として兄弟コンポーネントを使用します。##
<template> <p> <show-num-com></show-num-com> <addition-num-com></addition-num-com> </p> </template> <script> import showNumCom from './showNum.vue' import additionNumCom from './additionNum.vue' export default { components: { showNumCom, additionNumCom } } </script> // addtionNum.vue 中发送事件 <template> <p> <button @click="additionHandle">+加法器</button> </p> </template> <script> import {EventBus} from './event-bus.js' console.log(EventBus) export default { data(){ return{ num:1 } }, methods:{ additionHandle(){ EventBus.$emit('addition', { num:this.num++ }) } } } </script>
// showNum.vue 中接收事件 <template> <p>计算和: {{count}}</p> </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>
イベント リスナーを削除したい場合は、次のように実行できます。 :
import { eventBus } from 'event-bus.js' EventBus.$off('addition', {})
6. Vuex
1. Vuex の概要 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. Vuex 解决了多个视图依赖于同一状态和来自不同视图的行为需要变更同一状态的问题,将开发者的精力聚焦于数据的更新而不是数据在组件之间的传递上 2、Vuex各个模块 state:用于数据的存储,是store中的唯一数据源 3、Vuex实例应用 七、localStorage / sessionStorage 这种通信比较简单,缺点是数据和状态比较混乱,不太容易维护。 通过window.localStorage.getItem(key)获取数据 通过window.localStorage.setItem(key,value)存储数据 注意用JSON.parse() / JSON.stringify() 做数据格式转换 localStorage / sessionStorage可以结合vuex, 实现数据的持久保存,同时使用vuex解决数据和状态混乱问题. 八 $attrs与 $listeners 现在我们来讨论一种情况, 我们一开始给出的组件关系图中A组件与D组件是隔代关系, 那它们之前进行通信有哪些方式呢? 使用props绑定来进行一级一级的信息传递, 如果D组件中状态改变需要传递数据给A, 使用事件系统一级级往上传递 使用eventBus,这种情况下还是比较适合使用, 但是碰到多人合作开发时, 代码维护性较低, 可读性也低 使用Vuex来进行数据管理, 但是如果仅仅是传递数据, 而不做中间处理,使用Vuex处理感觉有点大材小用了. 在vue2.4中,为了解决该需求,引入了$attrs 和$listeners , 新增了inheritAttrs 选项。 在版本2.4以前,默认情况下,父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外),将会“回退”且作为普通的HTML特性应用在子组件的根元素上。接下来看一个跨级通信的例子: 总结 常见使用场景可以分为三类: 以上がVue コンポーネントと通信する 8 つの方法の紹介 (コレクション)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。
getters:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算
mutations:类似函数,改变state数据的唯一途径,且不能用于处理异步事件
actions:类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作
modules:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护// 父组件
<template>
<p id="app">
<ChildA/>
<ChildB/>
</p>
</template>
<script>
import ChildA from './components/ChildA' // 导入A组件
import ChildB from './components/ChildB' // 导入B组件
export default {
name: 'App',
components: {ChildA, ChildB} // 注册A、B组件
}
</script>
// 子组件childA
<template>
<p id="childA">
<h1>我是A组件</h1>
<button @click="transform">点我让B组件接收到数据</button>
<p>因为你点了B,所以我的信息发生了变化:{{BMessage}}</p>
</p>
</template>
<script>
export default {
data() {
return {
AMessage: 'Hello,B组件,我是A组件'
}
},
computed: {
BMessage() {
// 这里存储从store里获取的B组件的数据
return this.$store.state.BMsg
}
},
methods: {
transform() {
// 触发receiveAMsg,将A组件的数据存放到store里去
this.$store.commit('receiveAMsg', {
AMsg: this.AMessage
})
}
}
}
</script>
// 子组件 childB
<template>
<p id="childB">
<h1>我是B组件</h1>
<button @click="transform">点我让A组件接收到数据</button>
<p>因为你点了A,所以我的信息发生了变化:{{AMessage}}</p>
</p>
</template>
<script>
export default {
data() {
return {
BMessage: 'Hello,A组件,我是B组件'
}
},
computed: {
AMessage() {
// 这里存储从store里获取的A组件的数据
return this.$store.state.AMsg
}
},
methods: {
transform() {
// 触发receiveBMsg,将B组件的数据存放到store里去
this.$store.commit('receiveBMsg', {
BMsg: this.BMessage
})
}
}
}
</script>
vuex的store,js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
// 初始化A和B组件的数据,等待获取
AMsg: '',
BMsg: ''
}
const mutations = {
receiveAMsg(state, payload) {
// 将A组件的数据存放于state
state.AMsg = payload.AMsg
},
receiveBMsg(state, payload) {
// 将B组件的数据存放于state
state.BMsg = payload.BMsg
}
}
export default new Vuex.Store({
state,
mutations
})
// app.vue
// index.vue
<template>
<p>
<child-com1
:name="name"
:age="age"
:gender="gender"
:height="height"
title="程序员成长"
></child-com1>
</p>
</template>
<script>
const childCom1 = () => import("./childCom1.vue");
export default {
components: { childCom1 },
data() {
return {
name: "zhang",
age: "18",
gender: "女",
height: "158"
};
}
};
</script>
// childCom1.vue
<template class="border">
<p>
<p>name: {{ name}}</p>
<p>childCom1的$attrs: {{ $attrs }}</p>
<child-com2 v-bind="$attrs"></child-com2>
</p>
</template>
<script>
const childCom2 = () => import("./childCom2.vue");
export default {
components: {
childCom2
},
inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在props声明的属性
props: {
name: String // name作为props属性绑定
},
created() {
console.log(this.$attrs);
// { "age": "18", "gender": "女", "height": "158", "title": "程序员成长" }
}
};
</script>
// childCom2.vue
<template>
<p class="border">
<p>age: {{ age}}</p>
<p>childCom2: {{ $attrs }}</p>
</p>
</template>
<script>
export default {
inheritAttrs: false,
props: {
age: String
},
created() {
console.log(this.$attrs);
// { "gender": "女", "height": "158", "title": "程序员成长指北" }
}
};
</script>
父子组件通信: props; $parent / $children; provide / inject ; ref ; $attrs / $listeners
兄弟组件通信: eventBus ; vuex
跨级通信: eventBus;Vuex;provide / inject 、$attrs / $listeners