이 글에서는 vue의 8가지 구성 요소 통신 방법에 대해 자세히 설명합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.
vue는 데이터 기반 뷰 업데이트를 위한 프레임워크이므로 vue에서는 구성 요소 간의 데이터 통신이 매우 중요합니다. 그렇다면 구성 요소 간의 데이터 통신은 어떻게 발생합니까?
우선, 새해를 맞아 집에 가서 낯선 사람들이 가득한 방에 앉아 있는 것과 같은 통신 방식을 더 쉽게 이해하려면 vue의 구성 요소 간에 어떤 관계가 존재하는지 알아야 합니다. 서로 어떻게 부르는지 먼저 그 사람과 어떤 관계인지 알아야 해요. (학습 영상 공유: vue 영상 튜토리얼)
vue 컴포넌트 내 관계 설명:
위 그림과 같이 A와 B, A와 C, B와 D, C의 관계 및 E 구성 요소는 아버지와 아들의 관계입니다. B와 C의 관계는 A와 D의 관계이고, D와 E는 사촌 관계입니다. 위의 관계를 다음과 같이 분류합니다.
1.
props
/ $emit
props
를 하위에 전달합니다. 구성 요소는 데이터를 전달하고 하위 구성 요소는 $emit
를 통해 상위 구성 요소와 통신할 수 있습니다. props
/ $emit
父组件通过props
的方式向子组件传递数据,而通过$emit
子组件可以向父组件通信。
下面通过一个例子说明父组件如何向子组件传递数据:在子组件article.vue
中如何获取父组件section.vue
中的数据articles:['红楼梦', '西游记','三国演义']
// section父组件 <template> <div class="section"> <com-article :articles="articleList"></com-article> </div> </template> <script> import comArticle from './test/article.vue' export default { name: 'HelloWorld', components: { comArticle }, data() { return { articleList: ['红楼梦', '西游记', '三国演义'] } } } </script>
// 子组件 article.vue <template> <div> <span v-for="(item, index) in articles" :key="index">{{item}}</span> </div> </template> <script> export default { props: ['articles'] } </script>
总结: prop 只可以从上一级组件传递到下一级组件(父子组件),即所谓的单向数据流。而且 prop 只读,不可被修改,所有修改都会失效并警告。
对于$emit
我自己的理解是这样的: $emit
绑定一个自定义事件, 当这个语句被执行时, 就会将参数arg传递给父组件,父组件通过v-on监听并接收参数。 通过一个例子,说明子组件如何向父组件传递数据。
在上个例子的基础上, 点击页面渲染出来的ariticle
的item
, 父组件中显示在数组中的下标
// 父组件中 <template> <div class="section"> <com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article> <p>{{currentIndex}}</p> </div> </template> <script> import comArticle from './test/article.vue' export default { name: 'HelloWorld', components: { comArticle }, data() { return { currentIndex: -1, articleList: ['红楼梦', '西游记', '三国演义'] } }, methods: { onEmitIndex(idx) { this.currentIndex = idx } } } </script>
<template> <div> <div v-for="(item, index) in articles" :key="index" @click="emitIndex(index)">{{item}}</div> </div> </template> <script> export default { props: ['articles'], methods: { emitIndex(index) { this.$emit('onEmitIndex', index) } } } </script>
$children
/ $parent
上面这张图片是vue
官方的解释,通过$parent
和$children
就可以访问组件的实例,拿到实例代表什么?代表可以访问此组件的所有方法和data
。接下来就是怎么实现拿到指定组件的实例。
// 父组件中 <template> <div class="hello_world"> <div>{{msg}}</div> <com-a></com-a> <button @click="changeA">点击改变子组件值</button> </div> </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> <div class="com_a"> <span>{{messageA}}</span> <p>获取父组件的值为: {{parentVal}}</p> </div> </template> <script> export default { data() { return { messageA: 'this is old' } }, computed:{ parentVal(){ return this.$parent.msg; } } } </script>
要注意边界情况,如在#app
上拿$parent
得到的是new Vue()
的实例,在这实例上再拿$parent
得到的是undefined
,而在最底层的子组件拿$children
是个空数组。也要注意得到$parent
和$children
的值不一样,$children
的值是数组,而$parent
是个对象
上面两种方式用于父子组件之间的通信, 而使用props进行父子组件通信更加普遍; 二者皆不能用于非父子组件之间的通信。
provide
/ inject
provide
/ inject
是vue2.2.0
新增的api, 简单来说就是父组件中通过provide
来提供变量, 然后再子组件中通过inject
Article.vue<code>의 상위 구성요소 <code>section.vue
에서 데이터를 가져오는 방법articles:['A Dream of Red Mansions', 'Journey to the West', 'Romance of the Three Kingdoms']🎜// A.vue <template> <div> <comB></comB> </div> </template> <script> import comB from '../components/test/comB.vue' export default { name: "A", provide: { for: "demo" }, components:{ comB } } </script>
// B.vue <template> <div> {{demo}} <comC></comC> </div> </template> <script> import comC from '../components/test/comC.vue' export default { name: "B", inject: ['for'], data() { return { demo: this.for } }, components: { comC } } </script>
요약: props는 상위 구성 요소에서 하위 구성 요소(부모-자식 구성 요소)로만 전달될 수 있습니다. 이는 소위 단방향 데이터 흐름입니다. . 또한 prop은 읽기 전용이므로 수정할 수 없습니다. 모든 수정 사항이 유효하지 않으며 경고가 표시됩니다.
$emit
에 대한 내 이해는 다음과 같습니다. $ Emit
은 사용자 정의 이벤트를 바인딩합니다. 이 명령문이 실행되면 매개변수 arg가 상위 구성요소로 전달되고 상위 구성요소는 v-on을 통해 매개변수를 수신하고 수신합니다. 예를 통해 하위 구성 요소가 상위 구성 요소에 데이터를 전달하는 방법을 설명합니다. $children / $parent
🎜🎜🎜🎜vue
에 대한 공식적인 설명입니다. code> $parent 및 $children
은 구성 요소의 인스턴스에 액세스할 수 있습니다. 인스턴스를 가져온다는 것은 무엇을 의미합니까? 이 구성 요소의 모든 메서드와 데이터
에 대한 액세스를 나타냅니다. 다음 단계는 지정된 구성 요소의 인스턴스를 가져오는 방법입니다. 🎜// C.vue <template> <div> {{demo}} </div> </template> <script> export default { name: "C", inject: ['for'], data() { return { demo: this.for } } } </script>
// 子组件 A.vue export default { data () { return { name: 'Vue.js' } }, methods: { sayHello () { console.log('hello') } } }
#app
에서$parent
가져오기와 같은 경계 조건에 주의하세요.new Vue()
의 인스턴스입니다. 이 인스턴스에서$parent
를 가져오면정의되지 않음
이 표시되고, 가져오면 하단 하위 구성 요소$children
은 빈 배열입니다. 또한$parent
와$children
의 값은 배열이지만$children
의 값은 다릅니다.$parent
는 배열입니다. code>는 객체입니다.
제공
/주입
provide
/ inject
는 vue2.2.0
에서 추가한 새로운 API입니다. 간단히 말하면 를 통한 상위 구성 요소입니다. 제공하여 변수를 제공한 다음 하위 구성 요소에 <code>주입
을 통해 변수를 주입합니다. 🎜注意: 这里不论子组件嵌套有多深, 只要调用了inject
那么就可以注入provide
中的数据,而不局限于只能从当前父组件的props属性中回去数据
接下来就用一个例子来验证上面的描述:
假设有三个组件: A.vue、B.vue、C.vue 其中 C是B的子组件,B是A的子组件
// A.vue <template> <div> <comB></comB> </div> </template> <script> import comB from '../components/test/comB.vue' export default { name: "A", provide: { for: "demo" }, components:{ comB } } </script>
// B.vue <template> <div> {{demo}} <comC></comC> </div> </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> <div> {{demo}} </div> </template> <script> export default { name: "C", inject: ['for'], data() { return { demo: this.for } } } </script>
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>
eventBus
又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所以组件都可以通知其他组件。
eventBus也有不方便之处, 当项目较大,就容易造成难以维护的灾难
在Vue的项目中怎么使用eventBus
来实现组件之间的数据通信呢?具体通过下面几个步骤
首先需要创建一个事件总线并将其导出, 以便其他模块可以使用或者监听它.
// event-bus.js import Vue from 'vue' export const EventBus = new Vue()
假设你有两个组件: additionNum
和 showNum
, 这两个组件可以是兄弟组件也可以是父子组件;这里我们以兄弟组件为例:
<template> <div> <show-num-com></show-num-com> <addition-num-com></addition-num-com> </div> </template> <script> import showNumCom from './showNum.vue' import additionNumCom from './additionNum.vue' export default { components: { showNumCom, additionNumCom } } </script>
// addtionNum.vue 中发送事件 <template> <div> <button @click="additionHandle">+加法器</button> </div> </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> <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>
这样就实现了在组件addtionNum.vue
中点击相加按钮, 在showNum.vue
中利用传递来的 num
展示求和的结果.
如果想移除事件的监听, 可以像下面这样操作:
import { eventBus } from 'event-bus.js' EventBus.$off('addition', {})
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.
Vuex 解决了多个视图依赖于同一状态
和来自不同视图的行为需要变更同一状态
的问题,将开发者的精力聚焦于数据的更新而不是数据在组件之间的传递上
state
:用于数据的存储,是store中的唯一数据源
getters
:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算
mutations
:类似函数,改变state数据的唯一途径,且不能用于处理异步事件
actions
:类似于mutation
,用于提交mutation
来改变状态,而不直接变更状态,可以包含任意异步操作
modules
:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护
// 父组件 <template> <div id="app"> <ChildA/> <ChildB/> </div> </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> <div id="childA"> <h1>我是A组件</h1> <button @click="transform">点我让B组件接收到数据</button> <p>因为你点了B,所以我的信息发生了变化:{{BMessage}}</p> </div> </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> <div id="childB"> <h1>我是B组件</h1> <button @click="transform">点我让A组件接收到数据</button> <p>因为你点了A,所以我的信息发生了变化:{{AMessage}}</p> </div> </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 })
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特性应用在子组件的根元素上。接下来看一个跨级通信的例子:
// app.vue // index.vue <template> <div> <child-com1 :name="name" :age="age" :gender="gender" :height="height" title="程序员成长指北" ></child-com1> </div> </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"> <div> <p>name: {{ name}}</p> <p>childCom1的$attrs: {{ $attrs }}</p> <child-com2 v-bind="$attrs"></child-com2> </div> </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> <div class="border"> <p>age: {{ age}}</p> <p>childCom2: {{ $attrs }}</p> </div> </template> <script> export default { inheritAttrs: false, props: { age: String }, created() { console.log(this.$attrs); // { "gender": "女", "height": "158", "title": "程序员成长指北" } } }; </script>
更多编程相关知识,请访问:编程视频!!
위 내용은 8가지 Vue 컴포넌트 통신 방법에 대한 자세한 설명, 소장하러 오세요!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!