本篇文章為大家帶來了關於vue的相關知識,主要介紹了Vue組件間通信方式,Vue組件間通信一直是個重要的話題,雖然官方推出的Vuex狀態管理方案可以很好的解決元件之間的通訊問題,但是在元件庫內部使用Vuex往往會比較重,下面一起來看一下,希望對大家有幫助。
【相關推薦:javascript影片教學、vue.js教學】
在Vue元件庫在開發過程中,Vue元件之間的通訊一直是個重要的議題,雖然官方推出的Vuex 狀態管理方案可以很好的解決元件之間的通訊問題,但是在元件庫內部使用Vuex 往往會比較重,本文將系統的羅列出幾種不使用Vuex,比較實用的組件間的通訊方式,供大家參考。
元件之間通訊的場景
在進入我們今天的主題之前,我們先來總結下Vue元件之間通訊的幾個場景,一般可分為以下幾種場景:
- 父子元件之間的通訊
- 兄弟元件之間的通訊
- #隔代元件之間的通訊
父子元件之間的通訊
父子元件之間的通訊應該是Vue 元件通訊中最簡單也最常見的一種了,概括為兩個部分:父元件透過prop向子元件傳遞數據,子元件透過自訂事件向父元件傳遞資料。
父元件透過prop 向子元件傳遞資料
Vue元件的資料流向都遵循單向資料流的原則,所有的prop 都使得其父子prop 之間形成了一個單向下行綁定:父級prop 的更新會向下流動到子元件中,但反過來則不行。這樣會防止從子元件意外變更父級元件的狀態,從而導致你的應用的資料流向難以理解。
額外的,每次父級元件發生變更時,子元件中所有的 prop 都會刷新為最新的值。這意味著你不應該在一個子元件內部改變 prop。如果你這樣做了,Vue 會在瀏覽器的控制台中發出警告。
父元件ComponentA:
<template> <p> <component-b title="welcome"></component-b> </p> </template> <script> import ComponentB from './ComponentB' export default { name: 'ComponentA', components: { ComponentB } } </script>
子元件ComponentB:
<template> <p> <p>{{title}}</p> </p> </template> <script> export default { name: 'ComponentB', props: { title: { type: String, } } } </script>
子元件透過自訂事件向父元件傳遞資料
在子元件中可以透過 $emit
向父元件發生一個事件,在父元件中透過 v-on
/@
進行監聽。
子元件ComponentA:
<template> <p> <component-b :title="title" @title-change="titleChange"></component-b> </p> </template> <script> import ComponentB from './ComponentB' export default { name: 'ComponentA', components: { ComponentB }, data: { title: 'Click me' }, methods: { titleChange(newTitle) { this.title = newTitle } } } </script>
子元件ComponentB:
<template> <p> <p @click="handleClick">{{title}}</p> </p> </template> <script> export default { name: 'ComponentB', props: { title: { type: String, } }, methods: { handleClick() { this.$emit('title-change', 'New title !') } } } </script>
這個範例非常簡單,在子元件ComponentB 裡面透過 $emit
發放一個事件 title-change
,在父元件ComponentA 透過 @title-change
綁定的 titleChange
事件進行監聽,ComponentB 傳遞給ComponentA 的資料在 titleChange
函數的傳參中可以取得。
兄弟元件之間的通訊
狀態提升
寫過React 的同學應該對元件的 狀態提升
概念並不陌生,React 裡面將元件依職責的不同分割為兩個類別:展示型元件(Presentational Component)
和 容器型元件(Container Component)
。
展示型元件不關心元件使用的資料是如何取得的,以及元件資料應該如何修改,它只需要知道有了這些資料後,元件UI是什麼樣子的即可。外部元件透過 props 傳遞給展示型元件所需的資料和修改這些資料的回呼函數,展示型元件只是它們的使用者。
容器型元件的職責是取得資料以及這些資料的處理邏輯,並把資料和邏輯透過 props 提供給子元件使用。
因此,參考React 元件中的 狀態提升
的概念,我們在兩個兄弟元件之上提供一個父元件,相當於容器元件,負責處理數據,兄弟元件透過props接收參數以及回呼函數,相當於展示組件,來解決兄弟組件之間的通訊問題。
ComponentA(兄弟元件A):
<template> <p> <p>{{title}}</p> <p @click="changeTitle">click me</p> </p> </template> <script> export default { name: 'ComponentA', props: { title: { type: String }, changeTitle: Function } } </script>
ComponentB(兄弟元件B):
<template> <p> <p>{{title}}</p> <p @click="changeTitle">click me</p> </p> </template> <script> export default { name: 'ComponentB', props: { title: { type: String }, changeTitle: Function } } </script>
#ComponentC (容器組件C):
<template> <p> <component-a :title="titleA" :change-title="titleAChange"></component-a> <component-b :title="titleB" :change-title="titleBChange"></component-b> </p> </template> <script> import ComponentA from './ComponentA' import ComponentB from './ComponentB' export default { name: 'ComponentC', components: { ComponentA, ComponentB }, data: { titleA: 'this is title A', titleB: 'this is title B' }, methods: { titleAChange() { this.titleA = 'change title A' }, titleBChange() { this.titleB = 'change title B' } } } </script>
可以看到,上述這種"狀態提升" 的方式是比較繁瑣的,特別是兄弟組件的通信還要藉助於父組件,組件複雜之後處理起來是相當麻煩的。
隔代元件之間的通訊
隔代元件之間的通訊可以透過以下幾種方式實現:
#-
$attrs
/$listeners
-
rovide
/inject
- 基于
$parent
/$children
实现的dispatch
和broadcast
attrs/attrs/listeners
Vue 2.4.0 版本新增了 $attrs
和 $listeners
两个方法。先看下官方对 $attrs
的介绍:
包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定(
class
和style
除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class
和style
除外),并且可以通过v-bind="$attrs"
传入内部组件——在创建高级别的组件时非常有用。
看个例子:
组件A(ComponentA):
<template> <component-a name="Lin" age="24" sex="male"></component-a> </template> <script> import ComponentB from '@/components/ComponentB.vue' export default { name: 'App', components: { ComponentA } } </script>
组件B(ComponetB):
<template> <p> I am component B <component-c v-bind="$attrs"></component-c> </p> </template> <script> import ComponentC from '@/components/ComponentC.vue' export default { name: 'ComponentB', inheritAttrs: false, components: { ComponentC } } </script>
组件C(ComponetC):
<template> <p> I am component C </p> </template> <script> export default { name: 'ComponentC', props: { name: { type: String } }, mounted: function() { console.log('$attrs', this.$attrs) } } </script>
这里有三个组件,祖先组件(ComponentA)、父组件(ComponentB)和子组件(ComponentC)。这三个组件构成了一个典型的子孙组件之间的关系。
ComponetA 给 ComponetB 传递了三个属性 name、age 和 sex,ComponentB 通过 v-bind="$attrs"
将这三个属性再透传给 ComponentC, 最后在 ComponentC 中打印 $attrs
的值为:
{age: '24', sex: 'male'}
为什么我们一开始传递了三个属性,最后只打印了两个属性 age 和 sex 呢?因为在 ComponentC 的props 中声明了 name 属性,$attrs
会自动排除掉在 props 中声明的属性,并将其他属性以对象的形式输出。
说白了就是一句话,$attrs
可以获取父组件中绑定的非 Props 属性。
一般在使用的时候会同时和 inheritAttrs
属性配合使用。
如果你不希望组件的根元素继承 attribute,你可以在组件的选项中设置 inheritAttrs: false
。
在 ComponentB 添加了 inheritAttrs=false
属性后,ComponentB 的dom结构中可以看到是不会继承父组件传递过来的属性:
如果不加上 inheritAttrs=false
属性,就会自动继承父组件传递过来的属性:
再看下 $listeners
的定义:
包含了父作用域中的 (不含
.native
修饰器的)v-on
事件监听器。它可以通过v-on="$listeners"
传入内部组件——在创建更高层次的组件时非常有用。
$listeners
也能把父组件中对子组件的事件监听全部拿到,这样我们就能用一个v-on
把这些来自于父组件的事件监听传递到下一级组件。
继续改造 ComponentB 组件:
<template> <p> I am component B <component-c v-bind="$attrs" v-on="$listeners"></component-c> </p> </template> <script> import ComponentC from '@/components/ComponentC.vue' export default { name: 'ComponentB', inheritAttrs: false, components: { ComponentC } } </script>
这里利用 $attrs
和 $listeners
方法,可以将祖先组件(ComponentA) 中的属性和事件透传给孙组件(ComponentC),这样就可以实现隔代组件之间的通信。
provide/inject
provide/inject
是 Vue 2.2.0 版本后新增的方法。
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。如果你熟悉 React,这与 React 的上下文特性很相似。
先看下简单的用法:
父级组件:
export default { provide: { name: 'Lin' } }
子组件:
export default { inject: ['name'], mounted () { console.log(this.name); // Lin } }
上面的例子可以看到,父组件通过 privide
返回的对象里面的值,在子组件中通过 inject
注入之后可以直接访问到。
但是需要注意的是,provide
和 inject
绑定并不是可响应的,按照官方的说法,这是刻意为之的。
也就是说父组件 provide 里面的name属性值变化了,子组件中 this.name 获取到的值不变。
如果想让 provide 和 inject 变成可响应的,有以下两种方式:
- provide 祖先组件的实例,然后在子孙组件中注入依赖,这样就可以在子孙组件中直接修改祖先组件的实例的属性,不过这种方法有个缺点就是这个实例上挂载很多没有必要的东西比如props,methods
- 使用 Vue 2.6 提供的 Vue.observable 方法优化响应式 provide
看一下第一种场景:
祖先组件组件(ComponentA):
export default { name: 'ComponentA', provide() { return { app: this } }, data() { return { appInfo: { title: '' } } }, methods: { fetchAppInfo() { this.appInfo = { title: 'Welcome to Vue world'} } } }
我们把整个 ComponentA.vue 的实例 this
对外提供,命名为 app
。接下来,任何组件只要通过 inject
注入 app 的话,都可以直接通过 this.app.xxx
来访问 ComponentA.vue 的 data
、computed
、methods
等内容。
子组件(ComponentB):
<template> <p> {{ title }} <button @click="fetchInfo">获取App信息</button> </p> </template> <script> export default { name: 'ComponentB', inject: ['app'], computed: { title() { return this.app.appInfo.title } }, methods: { fetchInfo() { this.app.fetchAppInfo() } } } </script>
这样,任何子组件,只要通过 inject
注入 app
后,就可以直接访问祖先组件中的数据了,同时也可以调用祖先组件提供的方法修改祖先组件的数据并反应到子组件上。
当点击子组件(ComponentB)的获取App信息按钮,会调用 this.app.fetchAppInfo
方法,也就是访问祖先组件(ComponentA)实例上的 fetchAppInfo 方法,fetchAppInfo 会修改fetchAppInfo的值。同时子组件(ComponentB)中会监听 this.app.appInfo 的变化,并将变化后的title值显示在组件上。
再看一下第二种场景,通过 Vue.observable
方法来实现 provide
和 inject
绑定并可响应。
基于上面的示例,改造祖先组件(ComponentA):
import Vue from 'vue' const state = Vue.observable({ title: '' }); export default { name: 'ComponentA', provide() { return { state } } }
使用 Vue.observable
定义一个可响应的对象 state,并在 provide 中返回这个对象。
改造子组件(ComponentB):
<template> <p> {{ title }} <button @click="fetchInfo">获取App信息</button> </p> </template> <script> export default { name: 'ComponentInject', inject: ['state'], computed: { title() { return this.state.title } }, methods: { fetchInfo() { this.state.title = 'Welcome to Vue world22' } } } </script>
与之前的例子不同的是,这里我们直接修改了 this.state.title 的值,因为 state 被定义成了一个可响应的数据,所以 state.title 的值被修改后,视图上的 title 也会立即响应并更新,从这里看,其实很像 Vuex
的处理方式。
以上两种方式对比可以发现,第二种借助于 Vue.observable
方法实现 provide
和 inject
的可响应更加简单高效,推荐大家使用这种方式。
基于 $parent/$children 实现的 dispatch 和 broadcast
先了解下 dispatch 和 broadcast 两个概念:
-
dispatch: 派发,指的是从一个组件内部向上传递一个事件,并在组件内部通过
$on
进行监听 -
broadcast: 广播,指的是从一个组件内部向下传递一个事件,并在组件内部通过
$on
进行监听
在实现 dispatch 和 broadcast 方法之前,先来看一下具体的使用方法。有 ComponentA.vue 和 ComponentB.vue 两个组件,其中 ComponentB 是 ComponentA 的子组件,中间可能跨多级,在 ComponentA 中向 ComponentB 通信:
组件ComponentA:
<template> <button @click="handleClick">派发事件</button> </template> <script> import Emitter from '../mixins/emitter.js'; export default { name: 'ComponentA', mixins: [Emitter], methods: { handleClick () { this.dispatch('ComponentB', 'on-message', 'Hello Vue.js') } } } </script>
组件ComponentB:
export default { name: 'ComponentB', created () { this.$on('on-message', this.showMessage) }, methods: { showMessage (text) { console.log(text) } } }
dispatch 的逻辑写在 emitter.js
中,使用的时候通过 mixins
混入到组件中,这样可以很好的将事件通信逻辑和组件进行解耦。
dispatch 的方法有三个传参,分别是:需要接受事件的组件的名字(全局唯一,用来精确查找组件)、事件名和事件传递的参数。
dispatch 的实现思路非常简单,通过 $parent
获取当前父组件对象,如果组件的name和接受事件的name一致(dispatch方法的第一个参数),在父组件上调用 $emit
发射一个事件,这样就会触发目标组件上 $on
定义的回调函数,如果当前组件的name和接受事件的name不一致,就递归地向上调用此逻辑。
dispath:
export default { methods: { dispatch(componentName, eventName, params) { let parent = this.$parent || this.$root; let name = parent.$options.name; while (parent && (!name || name !== componentName)) { parent = parent.$parent; if (parent) { name = parent.$options.name } } if (parent) { parent.$emit.apply(parent, [eventName].concat(params)); } } } }
broadcast逻辑和dispatch的逻辑差不多,只是一个是通过 $parent
向上查找,一个是通过 $children
向下查找,
export default { methods: { broadcast(componentName, eventName, params) { this.$children.forEach(child => { const name = child.$options.name if (name === componentName) { child.$emit.apply(child, [eventName].concat(params)) } else { broadcast.apply(child, [componentName, eventName].concat([params])) } }) } } }
【相关推荐:javascript视频教程、vue.js教程】
以上是Vue組件間的通訊方式詳析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

Vue.js與前端技術棧緊密集成,提升開發效率和用戶體驗。 1)構建工具:與Webpack、Rollup集成,實現模塊化開發。 2)狀態管理:與Vuex集成,管理複雜應用狀態。 3)路由:與VueRouter集成,實現單頁面應用路由。 4)CSS預處理器:支持Sass、Less,提升樣式開發效率。

Netflix選擇React來構建其用戶界面,因為React的組件化設計和虛擬DOM機制能夠高效處理複雜界面和頻繁更新。 1)組件化設計讓Netflix將界面分解成可管理的小組件,提高了開發效率和代碼可維護性。 2)虛擬DOM機制通過最小化DOM操作,確保了Netflix用戶界面的流暢性和高性能。

Vue.js被開發者喜愛因為它易於上手且功能強大。 1)其響應式數據綁定係統自動更新視圖。 2)組件系統提高了代碼的可重用性和可維護性。 3)計算屬性和偵聽器增強了代碼的可讀性和性能。 4)使用VueDevtools和檢查控制台錯誤是常見的調試技巧。 5)性能優化包括使用key屬性、計算屬性和keep-alive組件。 6)最佳實踐包括清晰的組件命名、使用單文件組件和合理使用生命週期鉤子。

Vue.js是一個漸進式的JavaScript框架,適用於構建高效、可維護的前端應用。其關鍵特性包括:1.響應式數據綁定,2.組件化開發,3.虛擬DOM。通過這些特性,Vue.js簡化了開發過程,提高了應用性能和可維護性,使其在現代Web開發中備受歡迎。

Vue.js和React各有優劣,選擇取決於項目需求和團隊情況。 1)Vue.js適合小型項目和初學者,因其簡潔和易上手;2)React適用於大型項目和復雜UI,因其豐富的生態系統和組件化設計。

Vue.js通過多種功能提升用戶體驗:1.響應式系統實現數據即時反饋;2.組件化開發提高代碼復用性;3.VueRouter提供平滑導航;4.動態數據綁定和過渡動畫增強交互效果;5.錯誤處理機制確保用戶反饋;6.性能優化和最佳實踐提升應用性能。

Vue.js在Web開發中的角色是作為一個漸進式JavaScript框架,簡化開發過程並提高效率。 1)它通過響應式數據綁定和組件化開發,使開發者能專注於業務邏輯。 2)Vue.js的工作原理依賴於響應式系統和虛擬DOM,優化性能。 3)實際項目中,使用Vuex管理全局狀態和優化數據響應性是常見實踐。

Vue.js是由尤雨溪在2014年發布的漸進式JavaScript框架,用於構建用戶界面。它的核心優勢包括:1.響應式數據綁定,數據變化自動更新視圖;2.組件化開發,UI可拆分為獨立、可複用的組件。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

記事本++7.3.1
好用且免費的程式碼編輯器

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),