>  기사  >  웹 프론트엔드  >  8가지 Vue 컴포넌트 통신 방법에 대한 자세한 설명, 소장하러 오세요!

8가지 Vue 컴포넌트 통신 방법에 대한 자세한 설명, 소장하러 오세요!

青灯夜游
青灯夜游앞으로
2021-04-22 13:38:213406검색

이 글에서는 vue의 8가지 구성 요소 통신 방법에 대해 자세히 설명합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.

8가지 Vue 컴포넌트 통신 방법에 대한 자세한 설명, 소장하러 오세요!

vue는 데이터 기반 뷰 업데이트를 위한 프레임워크이므로 vue에서는 구성 요소 간의 데이터 통신이 매우 중요합니다. 그렇다면 구성 요소 간의 데이터 통신은 어떻게 발생합니까?

우선, 새해를 맞아 집에 가서 낯선 사람들이 가득한 방에 앉아 있는 것과 같은 통신 방식을 더 쉽게 이해하려면 vue의 구성 요소 간에 어떤 관계가 존재하는지 알아야 합니다. 서로 어떻게 부르는지 먼저 그 사람과 어떤 관계인지 알아야 해요. (학습 영상 공유: vue 영상 튜토리얼)

vue 컴포넌트 내 관계 설명:

8가지 Vue 컴포넌트 통신 방법에 대한 자세한 설명, 소장하러 오세요!

위 그림과 같이 A와 B, A와 C, B와 D, C의 관계 및 E 구성 요소는 아버지와 아들의 관계입니다. B와 C의 관계는 A와 D의 관계이고, D와 E는 사촌 관계입니다. 위의 관계를 다음과 같이 분류합니다.

    부모와 자식 컴포넌트 간 통신
  • 부모와 자식 컴포넌트가 아닌 컴포넌트(형제 컴포넌트, 세대 구분 컴포넌트 등) 간 통신
이 글에서는 컴포넌트 간 통신 방법 8가지를 소개합니다. 다음 목차에 표시된 대로 다양한 시나리오에서 사용하는 방법을 소개합니다. 효과적인 방법으로 구현된 구성 요소 간의 통신 방법을 선택하여 친구들이 구성 요소 간의 통신을 더 잘 이해할 수 있도록 돕습니다.

8가지 Vue 컴포넌트 통신 방법에 대한 자세한 설명, 소장하러 오세요!

1. props / $emit

상위 구성 요소는 props를 하위에 전달합니다. 구성 요소는 데이터를 전달하고 하위 구성 요소는 $emit를 통해 상위 구성 요소와 통신할 수 있습니다. props / $emit


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

1. 父组件向子组件传值

下面通过一个例子说明父组件如何向子组件传递数据:在子组件article.vue中如何获取父组件section.vue中的数据articles:['红楼梦', '西游记','三国演义']

// section父组件
<template>
  <div class="section">
    <com-article :articles="articleList"></com-article>
  </div>
</template>

<script>
import comArticle from &#39;./test/article.vue&#39;
export default {
  name: &#39;HelloWorld&#39;,
  components: { comArticle },
  data() {
    return {
      articleList: [&#39;红楼梦&#39;, &#39;西游记&#39;, &#39;三国演义&#39;]
    }
  }
}
</script>
// 子组件 article.vue
<template>
  <div>
    <span v-for="(item, index) in articles" :key="index">{{item}}</span>
  </div>
</template>

<script>
export default {
  props: [&#39;articles&#39;]
}
</script>
总结: prop 只可以从上一级组件传递到下一级组件(父子组件),即所谓的单向数据流。而且 prop 只读,不可被修改,所有修改都会失效并警告。

2. 子组件向父组件传值

对于$emit 我自己的理解是这样的: $emit绑定一个自定义事件, 当这个语句被执行时, 就会将参数arg传递给父组件,父组件通过v-on监听并接收参数。 通过一个例子,说明子组件如何向父组件传递数据。
在上个例子的基础上, 点击页面渲染出来的ariticleitem, 父组件中显示在数组中的下标

// 父组件中
<template>
  <div class="section">
    <com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article>
    <p>{{currentIndex}}</p>
  </div>
</template>

<script>
import comArticle from &#39;./test/article.vue&#39;
export default {
  name: &#39;HelloWorld&#39;,
  components: { comArticle },
  data() {
    return {
      currentIndex: -1,
      articleList: [&#39;红楼梦&#39;, &#39;西游记&#39;, &#39;三国演义&#39;]
    }
  },
  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: [&#39;articles&#39;],
  methods: {
    emitIndex(index) {
      this.$emit(&#39;onEmitIndex&#39;, index)
    }
  }
}
</script>

二、  $children / $parent


8가지 Vue 컴포넌트 통신 방법에 대한 자세한 설명, 소장하러 오세요!

上面这张图片是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 &#39;./test/comA.vue&#39;
export default {
  name: &#39;HelloWorld&#39;,
  components: { ComA },
  data() {
    return {
      msg: &#39;Welcome&#39;
    }
  },

  methods: {
    changeA() {
      // 获取到子组件A
      this.$children[0].messageA = &#39;this is new value&#39;
    }
  }
}
</script>
// 子组件中
<template>
  <div class="com_a">
    <span>{{messageA}}</span>
    <p>获取父组件的值为:  {{parentVal}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      messageA: &#39;this is old&#39;
    }
  },
  computed:{
    parentVal(){
      return this.$parent.msg;
    }
  }
}
</script>
要注意边界情况,如在#app上拿$parent得到的是new Vue()的实例,在这实例上再拿$parent得到的是undefined,而在最底层的子组件拿$children是个空数组。也要注意得到$parent$children的值不一样,$children 的值是数组,而$parent是个对象

总结

上面两种方式用于父子组件之间的通信, 而使用props进行父子组件通信更加普遍; 二者皆不能用于非父子组件之间的通信。

三、provide/ inject


概念:

provide/ injectvue2.2.0新增的api, 简单来说就是父组件中通过provide来提供变量, 然后再子组件中通过inject

1. 상위 구성 요소가 하위 구성 요소에 값을 전달합니다.

🎜다음은 상위 구성 요소가 하위 구성 요소에 데이터를 전달하는 방법을 보여주는 예를 사용합니다. 하위 구성 요소 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 &#39;../components/test/comB.vue&#39;
  export default {
    name: "A",
    provide: {
      for: "demo"
    },
    components:{
      comB
    }
  }
</script>
// B.vue

<template>
  <div>
    {{demo}}
    <comC></comC>
  </div>
</template>

<script>
  import comC from &#39;../components/test/comC.vue&#39;
  export default {
    name: "B",
    inject: [&#39;for&#39;],
    data() {
      return {
        demo: this.for
      }
    },
    components: {
      comC
    }
  }
</script>
요약: props는 상위 구성 요소에서 하위 구성 요소(부모-자식 구성 요소)로만 전달될 수 있습니다. 이는 소위 단방향 데이터 흐름입니다. . 또한 prop은 읽기 전용이므로 수정할 수 없습니다. 모든 수정 사항이 유효하지 않으며 경고가 표시됩니다.

2. 하위 구성 요소는 상위 구성 요소에 값을 전달합니다.

🎜$emit에 대한 내 이해는 다음과 같습니다. $ Emit은 사용자 정의 이벤트를 바인딩합니다. 이 명령문이 실행되면 매개변수 arg가 상위 구성요소로 전달되고 상위 구성요소는 v-on을 통해 매개변수를 수신하고 수신합니다. 예를 통해 하위 구성 요소가 상위 구성 요소에 데이터를 전달하는 방법을 설명합니다. $children / $parent🎜🎜🎜🎜
🎜🎜8가지 Vue 컴포넌트 통신 방법에 대한 자세한 설명, 소장하러 오세요!🎜🎜🎜🎜위 사진은 vue에 대한 공식적인 설명입니다. code> $parent 및 $children은 구성 요소의 인스턴스에 액세스할 수 있습니다. 인스턴스를 가져온다는 것은 무엇을 의미합니까? 이 구성 요소의 모든 메서드와 데이터에 대한 액세스를 나타냅니다. 다음 단계는 지정된 구성 요소의 인스턴스를 가져오는 방법입니다. 🎜

사용 방법

// C.vue
<template>
  <div>
    {{demo}}
  </div>
</template>

<script>
  export default {
    name: "C",
    inject: [&#39;for&#39;],
    data() {
      return {
        demo: this.for
      }
    }
  }
</script>
// 子组件 A.vue

export default {
  data () {
    return {
      name: &#39;Vue.js&#39;
    }
  },
  methods: {
    sayHello () {
      console.log(&#39;hello&#39;)
    }
  }
}
#app에서 $parent 가져오기와 같은 경계 조건에 주의하세요. new Vue()의 인스턴스입니다. 이 인스턴스에서 $parent를 가져오면 정의되지 않음이 표시되고, 가져오면 하단 하위 구성 요소 $children은 빈 배열입니다. 또한 $parent$children의 값은 배열이지만 $children의 값은 다릅니다. $parent는 배열입니다. code>는 객체입니다.

요약

🎜위의 두 가지 방법은 상위 구성 요소와 하위 구성 요소 간의 통신에 사용되며 통신을 위해 props를 사용합니다. 상위 구성 요소와 하위 구성 요소 간의 통신이 더 일반적입니다. 상위 구성 요소와 하위 구성 요소 간의 통신에는 둘 다 사용할 수 없습니다. 🎜🎜3. 제공/주입

개념:🎜🎜provide/ injectvue2.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 &#39;../components/test/comB.vue&#39;
  export default {
    name: "A",
    provide: {
      for: "demo"
    },
    components:{
      comB
    }
  }
</script>
// B.vue

<template>
  <div>
    {{demo}}
    <comC></comC>
  </div>
</template>

<script>
  import comC from &#39;../components/test/comC.vue&#39;
  export default {
    name: "B",
    inject: [&#39;for&#39;],
    data() {
      return {
        demo: this.for
      }
    },
    components: {
      comC
    }
  }
</script>
// C.vue
<template>
  <div>
    {{demo}}
  </div>
</template>

<script>
  export default {
    name: "C",
    inject: [&#39;for&#39;],
    data() {
      return {
        demo: this.for
      }
    }
  }
</script>

四、ref / refs


ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例,可以通过实例直接调用组件的方法或访问数据, 我们看一个ref 来访问组件的例子:

// 子组件 A.vue

export default {
  data () {
    return {
      name: &#39;Vue.js&#39;
    }
  },
  methods: {
    sayHello () {
      console.log(&#39;hello&#39;)
    }
  }
}
// 父组件 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


eventBus  又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所以组件都可以通知其他组件。

eventBus也有不方便之处, 当项目较大,就容易造成难以维护的灾难

在Vue的项目中怎么使用eventBus来实现组件之间的数据通信呢?具体通过下面几个步骤

1. 初始化

首先需要创建一个事件总线并将其导出, 以便其他模块可以使用或者监听它.

// event-bus.js

import Vue from &#39;vue&#39;
export const EventBus = new Vue()

2. 发送事件

假设你有两个组件: additionNumshowNum, 这两个组件可以是兄弟组件也可以是父子组件;这里我们以兄弟组件为例:

<template>
  <div>
    <show-num-com></show-num-com>
    <addition-num-com></addition-num-com>
  </div>
</template>

<script>
import showNumCom from &#39;./showNum.vue&#39;
import additionNumCom from &#39;./additionNum.vue&#39;
export default {
  components: { showNumCom, additionNumCom }
}
</script>
// addtionNum.vue 中发送事件

<template>
  <div>
    <button @click="additionHandle">+加法器</button>    
  </div>
</template>

<script>
import {EventBus} from &#39;./event-bus.js&#39;
console.log(EventBus)
export default {
  data(){
    return{
      num:1
    }
  },

  methods:{
    additionHandle(){
      EventBus.$emit(&#39;addition&#39;, {
        num:this.num++
      })
    }
  }
}
</script>

3. 接收事件

// showNum.vue 中接收事件

<template>
  <div>计算和: {{count}}</div>
</template>

<script>
import { EventBus } from &#39;./event-bus.js&#39;
export default {
  data() {
    return {
      count: 0
    }
  },

  mounted() {
    EventBus.$on(&#39;addition&#39;, param => {
      this.count = this.count + param.num;
    })
  }
}
</script>

这样就实现了在组件addtionNum.vue中点击相加按钮, 在showNum.vue中利用传递来的    num 展示求和的结果.

4. 移除事件监听者

如果想移除事件的监听, 可以像下面这样操作:

import { eventBus } from &#39;event-bus.js&#39;
EventBus.$off(&#39;addition&#39;, {})

六、Vuex


1.  Vuex介绍

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.
Vuex 解决了多个视图依赖于同一状态来自不同视图的行为需要变更同一状态的问题,将开发者的精力聚焦于数据的更新而不是数据在组件之间的传递上

2. Vuex各个模块

  • state:用于数据的存储,是store中的唯一数据源

  • getters:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算

  • mutations:类似函数,改变state数据的唯一途径,且不能用于处理异步事件

  • actions:类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作

  • modules:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护

3. Vuex实例应用

// 父组件

<template>
  <div id="app">
    <ChildA/>
    <ChildB/>
  </div>
</template>

<script>
  import ChildA from &#39;./components/ChildA&#39; // 导入A组件
  import ChildB from &#39;./components/ChildB&#39; // 导入B组件

  export default {
    name: &#39;App&#39;,
    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: &#39;Hello,B组件,我是A组件&#39;
      }
    },
    computed: {
      BMessage() {
        // 这里存储从store里获取的B组件的数据
        return this.$store.state.BMsg
      }
    },
    methods: {
      transform() {
        // 触发receiveAMsg,将A组件的数据存放到store里去
        this.$store.commit(&#39;receiveAMsg&#39;, {
          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: &#39;Hello,A组件,我是B组件&#39;
      }
    },
    computed: {
      AMessage() {
        // 这里存储从store里获取的A组件的数据
        return this.$store.state.AMsg
      }
    },
    methods: {
      transform() {
        // 触发receiveBMsg,将B组件的数据存放到store里去
        this.$store.commit(&#39;receiveBMsg&#39;, {
          BMsg: this.BMessage
        })
      }
    }
  }
</script>

vuex的store,js

import Vue from &#39;vue&#39;
import Vuex from &#39;vuex&#39;
Vue.use(Vuex)
const state = {
  // 初始化A和B组件的数据,等待获取
  AMsg: &#39;&#39;,
  BMsg: &#39;&#39;
}

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제