Vue구성요소 간 통신 방법은 무엇인가요? 다음 글에서는 Vue 컴포넌트의 통신 방법을 소개하겠습니다. 도움이 되셨으면 좋겠습니다!
vue의 두 가지 주요 기능은 반응형 프로그래밍과 구성 요소화입니다. Component는 Vue의 핵심 기능이지만 각 구성 요소 인스턴스의 범위는 서로 독립적이므로 서로 다른 구성 요소 간의 데이터가 서로 직접 참조할 수 없습니다. 컴포넌트 간에 데이터를 참조하려면 컴포넌트 통신을 사용해야 합니다. 통신하기 전에 먼저 컴포넌트 간의 관계를 이해해야 합니다.
위 그림과 같이:
아버지-자식 관계: A와 B, A와 C, B와 D, C와 E
형제 관계: B와 C
세대 간 관계(아마도 더 많은 세대가 떨어져 있을 수도 있음): A와 D, A와 E
교차 관계: B와 E, D와 E 등 .
props
/$emit
props
/$emit
父组件通过v-bind
绑定一个自定义的属性,子组件通过props
接收父组件传来的数据;子组件通过$emit
触发事件,父组件用on()
或者在子组件的自定义标签上使用v-on
来监听子组件触发的自定义事件,从而接收子组件传来的数据。(学习视频分享:vue视频教程)
下面通过一个例子来说明父组件向子组件传值,父组件parent.vue把数据books:['JavaScript高级程序设计', 'CSS新世界', '图解 HTTP 彩色版']
传给子组件child.vue,并在child.vue中展示出来
// 父组件parent.vue <template> <div> <child></child> </div> </template> <script> import Child from './components/Child.vue' export default { name: 'parent', components: { Child }, data() { return { books: ['JavaScript高级程序设计', 'CSS新世界', '图解 HTTP 彩色版'] } } } </script>
// 子组件child.vue <template> <div> <ul> <li>{{item}}</li> </ul> </div> </template> <script> export default { props: { books: { type: Array, default: () => { return [] } } } } </script>
注意:通过props传递数据是单向的,父组件数据变化时会传递给子组件,但子组件不能通过修改props传过来的数据来修改父组件的相应状态,即所谓的单向数据流。
下面通过子组件点击书籍列表,用$emit()
触发,然后再父组件中获取
// 子组件child.vue <template> <div> <ul> <li>{{item}}</li> </ul> </div> </template> <script> export default { props: { books: { type: Array, default: () => { return [] } } }, methods: { like(item) { this.$emit('likeBook', item) } } } </script>
// 父组件parent.vue <template> <div> <child></child> </div> </template> <script> import Child from './components/Child.vue' export default { name: 'parent', components: { Child }, data() { return { books: ['JavaScript高级程序设计', 'CSS新世界', '图解 HTTP 彩色版'] } }, methods: { likeBook(val) { alert('我最喜欢的书籍是《' + val + '》') } } } </script>
$parent
/$children
// 父组件parent.vue <template> <div> <child></child> <button>获取子组件数据</button> </div> </template> <script> import Child from './components/Child.vue' export default { name: 'parent', components: { Child }, data() { return { books: ['JavaScript高级程序设计', 'CSS新世界', '图解 HTTP 彩色版'] } }, methods: { getChildData() { alert(this.$children[0].msg) } } } </script>
// 子组件child.vue <template> <div> <ul> <li>{{item}}</li> </ul> </div> </template> <script> export default { name: 'child', data() { return { bookLists: [], msg: '我是子组件的值!' } }, mounted() { this.bookLists = this.$parent.books } } </script>
注意:$parent
拿到的是对象,如果是最顶层没有父组件的情况下拿到的是undefined
;$children
拿到的是数组,如果是做底层没有子组件的情况下,拿到的是空数组;这两种通信方式只能用于父子组件通信
ref
ref如果在普通Dom元素上使用,引用指向的就是 DOM 元素;如果在子组件上使用,引用就指向组件实例,可以通过实例直接调用组件的方法和数据
// 父组件parent.vue <template> <div> <child></child> <button>获取子组件数据</button> </div> </template> <script> import Child from './components/Child.vue' export default { name: 'parent', components: { Child }, methods: { getChildData() { const msg = this.$refs['child'].msg console.log(msg) this.$refs['child'].say() } } } </script>
// 子组件child.vue <script> export default { name: 'child', data() { return { msg: '我是子组件的值!' } }, methods: { say() { alert('你好,我是子组件!') } }, } </script>
provide
/inject
祖先组件通过provide
来提供变量,子孙组件通过inject
注入变量来获取祖先组件的数据,不管子孙组件嵌套有多深, 只要调用了inject 那么就可以注入provide中的数据。下面是具体代码:
// 父组件 <template> <div> <h1>康熙</h1> <son></son> </div> </template> <script> import Son from './components/Son.vue' export default { components: { Son }, provide() { return { FatherToSon: this.FatherToSon, FatherToGrandson: this.FatherToGrandson, } }, data() { return { FatherToSon: '我是康熙,雍正,你是我儿子!', FatherToGrandson: '我是康熙,乾隆,你是我孙子!', } } } </script>
// 子组件 <template> <div> <h1>雍正</h1> <button>接收</button> <grandson></grandson> </div> </template> <script> import Grandson from './Grandson.vue' export default { components: { Grandson }, inject: ['FatherToSon'], methods: { receive() { alert(this.FatherToSon) } } } </script>
// 孙组件 <template> <div> <h1>乾隆</h1> <button>接收</button> </div> </template> <script> export default { inject: ['FatherToGrandson'], methods: { receive() { alert(this.FatherToGrandson) } } } </script>
注意:provide/inject只能从上往下传值,且不是响应式,若要变成响应式的数据provide需要提供函数
eventBus
的$emit
/$on
상위 구성 요소는 v-bind
를 통해 사용자 정의 속성을 바인딩합니다. > 및 하위 구성 요소는 props
를 통해 상위 구성 요소로부터 데이터를 수신하고 하위 구성 요소는 $emit
를 통해 이벤트를 트리거하며 상위 구성 요소는 on()을 사용합니다.
또는 하위 구성 요소에서 사용자 정의 태그에 v-on
을 사용하면 하위 구성 요소에서 트리거된 사용자 정의 이벤트를 수신하여 하위 구성 요소로부터 데이터를 수신할 수 있습니다. (학습 영상 공유: vue video tutorial
)
books:['JavaScript Advanced) 데이터를 저장합니다. 프로그래밍', 'CSS 신세계', '그림 HTTP 색상 버전']
은 하위 구성 요소 child.vue에 전달되어 child.vue🎜// main.js // 全局添加事件总线 Vue.prototype.$bus = new Vue()
// 父组件parent.vue <template> <div> <childa></childa> <childb></childb> </div> </template> <script> import ChildA from './components/childA' import ChildB from './components/childB' export default { components: { ChildA, ChildB } } </script>🎜
$emit()
로 트리거한 다음 상위 구성 요소에서 가져옵니다. 🎜// ChildA组件 <template> <div> <h1>组件A</h1> <button>发送</button> </div> </template> <script> export default { methods: { // 发送事件 send() { this.$bus.$emit('message', '欢迎使用eventBus!') } } } </script>
// ChildB组件 <template> <div> <h1>组件B</h1> </div> </template> <script> export default { mounted() { // 接收事件 this.$bus.$on('message', data => { alert('我是组件B,我收到的消息为:' + data) }) }, beforeDestroy() { this.$bus.$off('message') } } </script>🎜
$parent
/ $children
🎜// 父组件 <template> <div> <childa></childa> </div> </template> <script> import ChildA from './components/childA' export default { name: 'parent', components: { ChildA, }, data() { return { name: '小明', age: 18, sex: '男' } }, methods: { // 获取名字 getName() { console.log('我的名字是' + this.name) }, // 获取年龄 getAge() { console.log('我今年' + this.age + '岁'); } } } </script>
// 子组件A <template> <div> <h1>组件A</h1> {{ msgA }} <hr> <childb></childb> </div> </template> <script> import ChildB from './childB.vue' export default { name: 'ChildA', components: { ChildB }, data() { return { msgA: null, height: '175cm' } }, props: { sex: { type: String, default: '' } }, mounted() { this.msgA = this.$attrs console.log('组件A获取的$listeners:', this.$listeners) }, methods: { // 获取身高 getHeight() { console.log('我的身高是' + this.height); } } } </script>🎜참고:
$parent
는 객체를 가져옵니다. 최상위 구성 요소이고 상위 구성 요소가 없는 경우 정의되지 않음
의 경우 $children
은 배열을 가져옵니다. . 맨 아래 레이어에 하위 구성 요소가 없으면 빈 배열을 얻습니다. 두 가지 통신 방법은 상위-하위 구성 요소 통신에만 사용할 수 있습니다🎜🎜3. 일반 Dom 요소에 사용된 경우 참조는 DOM 요소를 가리키고, 하위 구성 요소에 사용된 경우 참조는 DOM 요소를 가리킵니다. 인스턴스를 통해 구성 요소의 메서드와 데이터를 직접 호출할 수 있습니다. // 孙组件B <template> <div> <h1>组件B</h1> {{ msgB }} </div> </template> <script> export default { name: 'ChildB', data() { return { msgB: null } }, mounted() { this.msgB = this.$attrs console.log('组件B获取的$listeners:', this.$listeners) } } </script>
// 孙组件B export default { name: 'ChildB', inheritAttrs: false, data() { return { msgB: null } }, mounted() { this.msgB = this.$attrs console.log('组件B获取的$listeners:', this.$listeners) } }🎜 4.
provide
/inject
🎜🎜 상위 구성 요소는 provide
를 통해 제공됩니다. 하위 구성 요소는 inject를 통해 변수를 주입합니다. code>를 사용하여 상위 구성 요소의 데이터를 가져옵니다. 하위 구성 요소가 아무리 깊게 중첩되어 있어도 inject가 호출되는 한 제공되는 데이터를 주입할 수 있습니다. 다음은 구체적인 코드입니다: 🎜<pre class="brush:php;toolbar:false">// 父组件
<template>
<div>
<h1>父组件</h1>
<hr>
<childa></childa>
<hr>
<childb></childb>
</div>
</template>
<script>
import ChildA from &#39;./components/ChildA&#39;
import ChildB from &#39;./components/ChildB&#39;
export default {
name: &#39;parent&#39;,
components: {
ChildA,
ChildB
}
}
</script></pre>
<pre class="brush:php;toolbar:false">// 子组件A
<template>
<div>
<h1>组件A</h1>
<p>A获取的值: {{ count }}</p>
<button>ChildA-add</button>
</div>
</template>
<script>
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
// 改变store里count的值
add(num) {
this.$store.dispatch(&#39;countAdd&#39;, num)
}
}
}
</script>
<style>
</style></pre>
<pre class="brush:php;toolbar:false">// 子组件B
<template>
<div>
<h1>组件B</h1>
<p>B获取的值: {{ countB }}</p>
<button>ChildB-add</button>
</div>
</template>
<script>
import { mapMutations, mapGetters } from &#39;Vue 구성 요소 간에 통신하는 방법은 무엇입니까? 구성 요소 통신의 여러 가지 방법&#39;
export default {
computed: {
...mapGetters({
countB: &#39;getCount&#39;
})
},
methods: {
...mapMutations([&#39;countAdd&#39;]),
// 改变store里count的值
add(num) {
this.countAdd(num)
}
}
}
</script>
<style>
</style></pre>🎜<imgreferrerpolicy src="https://img.php.cn/upload/article/000/000/024/67e3a6aa5a54ba35c984d3e430aed821-4.gif" alt="값 전달을 위한 제공 및 주입" title="값 전달을 위한 제공 및 주입" loading="lazy"></imgreferrerpolicy>🎜참고: 제공/주입은 위에서 아래로 값만 전달할 수 있으며 원하는 경우 응답하지 않습니다. 반응형 데이터 제공이 되려면 <code>eventBus
🎜🎜eventBus의 $emit
/$on
이 제공되어야 합니다. 메시지 센터를 기반으로 하는 메시지 전달의 메시지 구독 및 게시 패턴을 게시-구독자 패턴이라고 합니다. 🎜eventBus는 이벤트 버스라고도 합니다. Vue에서는 eventBus를 통신 브리지 개념으로 사용할 수 있습니다. 마치 모든 구성 요소가 동일한 이벤트 센터를 공유하고 이벤트를 센터에 보내거나 수신하도록 등록할 수 있으므로 구성 요소가 다른 구성 요소에 병렬로 위아래로 알릴 수 있습니다. 🎜$emit('name',args)
: name:发布的消息名称 , args:发布的消息$on('name',fn)
: name:订阅的消息名称, fn: 订阅的消息$once('name',fn)
: name:订阅的消息名称, fn: 订阅的消息。与$on相似但是只触发一次,一旦触发之后,监听器就会被移除$off('name',callback)
:name:事件名称,callback:回调监听器
eventbus可以实现任何组件之前的通信,下面以兄弟组件为例
// main.js // 全局添加事件总线 Vue.prototype.$bus = new Vue()
在parent.vue引入ChildA和ChildB组件,使它们成为兄弟组件
// 父组件parent.vue <template> <div> <childa></childa> <childb></childb> </div> </template> <script> import ChildA from './components/childA' import ChildB from './components/childB' export default { components: { ChildA, ChildB } } </script>
在ChildA组件中用$emit
发送事件
// ChildA组件 <template> <div> <h1>组件A</h1> <button>发送</button> </div> </template> <script> export default { methods: { // 发送事件 send() { this.$bus.$emit('message', '欢迎使用eventBus!') } } } </script>
在ChildB组件中用$on
接收ChildA发送的事件
// ChildB组件 <template> <div> <h1>组件B</h1> </div> </template> <script> export default { mounted() { // 接收事件 this.$bus.$on('message', data => { alert('我是组件B,我收到的消息为:' + data) }) }, beforeDestroy() { this.$bus.$off('message') } } </script>
注意:$on
监听的事件不会自动移除监听,因此在不用时最好使用$off
移除监听以免产生问题
$attrs
/$listeners
当组件为两级嵌套时,一般采用props
和$emit
,但遇到多级组件嵌套时这种方法就不太适用了,如果不做中间处理,只传递数据用Vue 구성 요소 간에 통신하는 방법은 무엇입니까? 구성 요소 통신의 여러 가지 방법有点大材小用了。因此在vue2.4
中为了解决这一需求,便引入了$attrs
和$listeners
, 新增了inheritAttrs
属性
$attrs
:当父组件传递了很多数据给子组件时,子组件没有声明props来进行接收,么子组件中的attrs属性就包含了所有父组件传来的数据(除开已经props声明了的);子组件还可以使用v−bind="$attrs"
的形式将所有父组件传来的数据(除开已经props声明了的)传向下一级子组件,通常和interitAttrs
属性一起使用。$listeners
:包含了父组件中(不含.native
修饰器的)v-on 事件监听器,通过v-on="$listeners"
,可以将这些事件绑定给它自己的子组件
下面看一个例子:
// 父组件 <template> <div> <childa></childa> </div> </template> <script> import ChildA from './components/childA' export default { name: 'parent', components: { ChildA, }, data() { return { name: '小明', age: 18, sex: '男' } }, methods: { // 获取名字 getName() { console.log('我的名字是' + this.name) }, // 获取年龄 getAge() { console.log('我今年' + this.age + '岁'); } } } </script>
// 子组件A <template> <div> <h1>组件A</h1> {{ msgA }} <hr> <childb></childb> </div> </template> <script> import ChildB from './childB.vue' export default { name: 'ChildA', components: { ChildB }, data() { return { msgA: null, height: '175cm' } }, props: { sex: { type: String, default: '' } }, mounted() { this.msgA = this.$attrs console.log('组件A获取的$listeners:', this.$listeners) }, methods: { // 获取身高 getHeight() { console.log('我的身高是' + this.height); } } } </script>
// 孙组件B <template> <div> <h1>组件B</h1> {{ msgB }} </div> </template> <script> export default { name: 'ChildB', data() { return { msgB: null } }, mounted() { this.msgB = this.$attrs console.log('组件B获取的$listeners:', this.$listeners) } } </script>
$attrs获取的结果:
$listeners获取的结果:
如代码和图所示组件A中props
声明接收了sex属性,因此组件中$attrs
获取的是父组件中绑定的除去sex属性的值;组件A中使用了v-bind="$attrs"
和v-on="$listeners"
,则组件B获取不仅是组件A中本身绑定的属性和方法还包含组件A获取父组件绑定的属性和方法
如果父组件传递了很多参数给子组件,而子组件没有用props完全接收,那么没有接收的这些属性作为普通的 HTML attribute
应用在子组件的根元素上
如果你不希望子组件的根元素继承特性,你可以在组件的选项中设置inheritAttrs: false
以上面的组件B为例,当Vue 구성 요소 간에 통신하는 방법은 무엇입니까? 구성 요소 통신의 여러 가지 방법(inheritAttrs默认为true)
当Vue 구성 요소 간에 통신하는 방법은 무엇입니까? 구성 요소 통신의 여러 가지 방법
// 孙组件B export default { name: 'ChildB', inheritAttrs: false, data() { return { msgB: null } }, mounted() { this.msgB = this.$attrs console.log('组件B获取的$listeners:', this.$listeners) } }
Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
状态管理包含以下几个部分:
视图发生变化会导致数据源的改变,数据源发生变化则会改变视图,则上面表示是一个“单向数据流”。但是当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
因此,为了解决这种问题我们把组件的共享状态抽取出来,以一个全局单例模式管理。在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
1、state
:存储应用中需要共享的状态,是Vuex中的唯一数据源。
2、getters
:类似Vue中的计算属性computed
,getter 的返回值会根据它的依赖被缓存起 来,且只有当它的依赖值发生了改变才会被重新计算。
3、mutations
:更改 Vuex 的 store 中的状态(state)的唯一方法,且mutation 必须是同步函数
4、actions
:类似于 mutation,提交的是 mutation,而不是直接变更状态;可以包含任意异步操作
5、modules
:将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
// 父组件 <template> <div> <h1>父组件</h1> <hr> <childa></childa> <hr> <childb></childb> </div> </template> <script> import ChildA from './components/ChildA' import ChildB from './components/ChildB' export default { name: 'parent', components: { ChildA, ChildB } } </script>
// 子组件A <template> <div> <h1>组件A</h1> <p>A获取的值: {{ count }}</p> <button>ChildA-add</button> </div> </template> <script> export default { computed: { count() { return this.$store.state.count } }, methods: { // 改变store里count的值 add(num) { this.$store.dispatch('countAdd', num) } } } </script> <style> </style>
// 子组件B <template> <div> <h1>组件B</h1> <p>B获取的值: {{ countB }}</p> <button>ChildB-add</button> </div> </template> <script> import { mapMutations, mapGetters } from 'Vue 구성 요소 간에 통신하는 방법은 무엇입니까? 구성 요소 통신의 여러 가지 방법' export default { computed: { ...mapGetters({ countB: 'getCount' }) }, methods: { ...mapMutations(['countAdd']), // 改变store里count的值 add(num) { this.countAdd(num) } } } </script> <style> </style>
store.js
import Vue from 'vue' import Vuex from 'Vue 구성 요소 간에 통신하는 방법은 무엇입니까? 구성 요소 통신의 여러 가지 방법' Vue.use(Vuex) export default new Vuex.Store({ state: { count: 0, }, getters: { getCount: (state) => { return state.count } }, mutations: { countAdd(state, num) { state.count += num } }, actions: { countAdd(context, num) { context.commit('countAdd', num) } }, modules: { } })
localStorage
/sessionStorage
localStorage:本地存储对象,存储的数据是永久性数据,页面刷新,即使浏览器重启,除非主动删除不然存储的数据会一直存在
sessionStorage:与localStorage相似,但是只有在当前页面下有效,关闭页面或浏览器存储的数据将会清空
localStorage和sessionStorage常用的API:
setItem (key, value) —— 保存数据,以键值对的方式储存信息。 getItem (key) —— 获取数据,将键值传入,即可获取到对应的value值。 removeItem (key) —— 删除单个数据,根据键值移除对应的信息。 clear () —— 删除所有的数据 key (index) —— 获取某个索引的key
// 存储 setItem() { window.localStorage.setItem('name1', '小明') window.sessionStorage.setItem('name2', '小红') }
// 接收 receive() { const name1 = window.localStorage.getItem('name1') const name2 = window.sessionStorage.getItem('name2') console.log(name1) // 打印结果为:小明 console.log(name2) // 打印结果为:小红 }
localStorage和sessionStorage通过setItem()
存储数据会自动转换为String
类型,但是通过getItem()
其类型并不会转换回来(localStorage和sessionStorage使用方法一样,下面均以localStorage为例)
const num = 1 window.localStorage.setItem('num', num) const numRec = window.localStorage.getItem('num') console.log(numRec, typeof(numRec)) // 1 string
因此正确的存储方式应该为:存储之前用JSON.stringify()
方法将数据转换成json字符串
形式;需要使用数据的时候用JSON.parse()
方法将之前存储的字符串转换成json对象
const num = 1 window.localStorage.setItem('num', JSON.stringify(num)) const obj = { name: '小红', age: 18 } window.localStorage.setItem('obj', JSON.stringify(obj)) const numRec = JSON.parse(window.localStorage.getItem('num')) console.log(numRec, typeof(numRec)) // 1 'number' const objRec = JSON.parse(window.localStorage.getItem('obj')) console.log(objRec, typeof(objRec)) // {name: '小红', age: 18} 'object'
注意:localStorage.setItem()和sessionStorage.setItem()不能直接存储对象,必须使用JSON.stringify()
和JSON.parse()
转换实现
以上8种通信方式主要应用在以下三类场景:
props
/$emit
입니다. 단일 상위-하위 구성요소는 $ parent> code>/<code>$children
은 또한 더 편리합니다. 상위 구성 요소는 종종 ref
를 사용하여 하위 구성 요소 인스턴스를 얻습니다. provide를 사용할 수도 있습니다. code>/<code> 주입
, $attrs
/$listeners
및 localStorage
/sessionStorage
props
/$emit
,单一的父子组件通信使用$parent>
/$children
也比较方便;父组件也常使用ref
获取子组件实例;也可使用provide
/inject
、$attrs
/$listeners
以及localStorage
/sessionStorage
eventBus
的$emit
/$on
;复杂的数据使用Vuex
比较方便;也可以使用localStorage
/sessionStorage
;provide
/inject
和$attrs
/$listeners
;跨级组件通信的数据如果不复杂可使用eventBus
和localStorage
/sessionStorage
;如果数据复杂可使用Vuex
eventBus
의 $emit
/$on
을 사용할 수 있습니다. Vuex
code>가 더 편리합니다. localStorage
/sessionStorage
를 사용할 수도 있습니다. 부모, 자녀 및 다른 중첩 구성 요소 통신 방법은 대부분 provide
/inject
및 $attrs
/$listeners
를 사용합니다. 크로스레벨 구성 요소 간 통신은 복잡하지 않으며 eventBus를 사용할 수 있습니다
. 데이터가 복잡하면 localStorage
/sessionStorage
를 사용할 수 있습니다. code>Vuex
위 내용은 Vue 구성 요소 간에 통신하는 방법은 무엇입니까? 구성 요소 통신의 여러 가지 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!