Vue組件間怎麼通訊?組件通訊的幾種方式
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
父元件透過v-bind
綁定一個自訂的屬性,子元件透過props
接收父元件傳來的資料;子元件透過$emit
觸發事件,父元件用on()
或在子元件的自訂標籤上使用v-on
來監聽子元件觸發的自訂事件,從而接收子元件傳來的資料。 (學習影片分享:vue影片教學)
1、父元件向子元件傳值
下面透過一個範例來說明父元件向子元件傳值,父元件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傳過來的資料來修改父元件的對應狀態,也就是所謂的單向資料流。
2、子元件向父元件傳值
下面透過子元件點擊書籍列表,用$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:存取父元件實例
- $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中的數據。下面是具體程式碼:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">// 父组件
<template>
<div>
<h1 id="康熙">康熙</h1>
<son></son>
</div>
</template>
<script>
import Son from &#39;./components/Son.vue&#39;
export default {
components: {
Son
},
provide() {
return {
FatherToSon: this.FatherToSon,
FatherToGrandson: this.FatherToGrandson,
}
},
data() {
return {
FatherToSon: &#39;我是康熙,雍正,你是我儿子!&#39;,
FatherToGrandson: &#39;我是康熙,乾隆,你是我孙子!&#39;,
}
}
}
</script></pre><div class="contentsignin">登入後複製</div></div>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">// 子组件
<template>
<div>
<h1 id="雍正">雍正</h1>
<button>接收</button>
<grandson></grandson>
</div>
</template>
<script>
import Grandson from &#39;./Grandson.vue&#39;
export default {
components: {
Grandson
},
inject: [&#39;FatherToSon&#39;],
methods: {
receive() {
alert(this.FatherToSon)
}
}
}
</script></pre><div class="contentsignin">登入後複製</div></div>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">// 孙组件
<template>
<div>
<h1 id="乾隆">乾隆</h1>
<button>接收</button>
</div>
</template>
<script>
export default {
inject: [&#39;FatherToGrandson&#39;],
methods: {
receive() {
alert(this.FatherToGrandson)
}
}
}
</script></pre><div class="contentsignin">登入後複製</div></div>
注意:provide/inject只能從上往下傳值,且不是響應式,若要變成響應式的資料provide需要提供函數
五、
的$emit
/$on
eventBus是訊息傳遞的一種方式,基於一個訊息中心,訂閱和發布訊息的模式,稱為發布訂閱者模式。
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可以实现任何组件之前的通信,下面以兄弟组件为例1、初始化,全局引入
// main.js // 全局添加事件总线 Vue.prototype.$bus = new Vue()
2、发送事件
在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 id="组件A">组件A</h1> <button>发送</button> </div> </template> <script> export default { methods: { // 发送事件 send() { this.$bus.$emit('message', '欢迎使用eventBus!') } } } </script>
3、接收事件发送的事件
在ChildB组件中用$on
接收ChildA发送的事件
// ChildB组件 <template> <div> <h1 id="组件B">组件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
1、简介
当组件为两级嵌套时,一般采用props
和$emit
,但遇到多级组件嵌套时这种方法就不太适用了,如果不做中间处理,只传递数据用Vue組件間怎麼通訊?組件通訊的幾種方式有点大材小用了。因此在vue2.4
中为了解决这一需求,便引入了$attrs
和$listeners
, 新增了inheritAttrs
属性
-
$attrs
:当父组件传递了很多数据给子组件时,子组件没有声明props来进行接收,么子组件中的attrs属性就包含了所有父组件传来的数据(除开已经props声明了的);子组件还可以使用v−bind="$attrs"
的形式将所有父组件传来的数据(除开已经props声明了的)传向下一级子组件,通常和interitAttrs
属性一起使用。 -
$listeners
:包含了父组件中(不含.native
修饰器的)v-on 事件监听器,通过v-on="$listeners"
,可以将这些事件绑定给它自己的子组件2、实例
下面看一个例子:
// 父组件 <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 id="组件A">组件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 id="组件B">组件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获取父组件绑定的属性和方法
3、inheritAttrs
如果父组件传递了很多参数给子组件,而子组件没有用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
1、Vuex概述
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
状态管理包含以下几个部分:
- 状态(State),驱动应用的数据源
- 视图(View),以声明方式将状态映射到视图;
- 操作(Actions),响应在视图上的用户输入导致的状态变化
视图发生变化会导致数据源的改变,数据源发生变化则会改变视图,则上面表示是一个“单向数据流”。但是当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
因此,为了解决这种问题我们把组件的共享状态抽取出来,以一个全局单例模式管理。在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
2、 Vuex各个模块
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、甚至是嵌套子模块——从上至下进行同样方式的分割
3、Vuex举例
// 父组件 <template> <div> <h1 id="父组件">父组件</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 id="组件A">组件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 id="组件B">组件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
1、介绍
localStorage:本地存储对象,存储的数据是永久性数据,页面刷新,即使浏览器重启,除非主动删除不然存储的数据会一直存在
sessionStorage:与localStorage相似,但是只有在当前页面下有效,关闭页面或浏览器存储的数据将会清空
localStorage和sessionStorage常用的API:
setItem (key, value) —— 保存数据,以键值对的方式储存信息。 getItem (key) —— 获取数据,将键值传入,即可获取到对应的value值。 removeItem (key) —— 删除单个数据,根据键值移除对应的信息。 clear () —— 删除所有的数据 key (index) —— 获取某个索引的key
2、举例
// 存储 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) // 打印结果为:小红 }
3、setItem()和getItem()使用时的类型转换
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>
/$children
也比較方便;父元件也常使用ref
來取得子元件實例;也可使用provide
/inject
、$attrs
/$listeners
以及localStorage
/sessionStorage
-
兄弟元件通訊:簡單的資料傳遞可使用
eventBus
的$emit
/$on
;複雜的資料使用Vuex
比較方便;也可以使用localStorage
/sessionStorage
; -
跨級元件通訊:父子孫等嵌套元件通訊方式多使用
provide
/inject
和$attrs
/$listeners
;跨級組件通訊的資料如果不複雜可使用eventBus
和localStorage
/sessionStorage
;如果資料複雜可使用Vuex
,但要注意刷新介面Vuex儲存的資料會消失
結尾
本篇文章只是簡單記錄了一下平時使用的元件通訊方式,並沒有深入的介紹其細節,如果有錯誤的地方歡迎指正
以上是Vue組件間怎麼通訊?組件通訊的幾種方式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

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

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

使用vue框架開發前端專案時,我們部署的時候都會部署多套環境,往往開發、測試以及線上環境呼叫的介面網域都是不一樣的。如何能做到區分呢?那就是使用環境變數和模式。

Ace 是一個用 JavaScript 寫的可嵌入程式碼編輯器。它與 Sublime、Vim 和 TextMate 等原生編輯器的功能和效能相符。它可以很容易地嵌入到任何網頁和 JavaScript 應用程式中。 Ace 被維護為Cloud9 IDE的主要編輯器 ,並且是 Mozilla Skywriter (Bespin) 專案的繼承者。

前言:在vue3的開發中,reactive是提供實現響應式資料的方法。日常開發這個是使用頻率很高的api。這篇文章筆者就來探索其內部運作機制。

在當今前端開發中,Vue.js 已經成為了一個非常流行的框架。隨著 Vue.js 的不斷發展,單元測試變得越來越重要。今天,我們將探討如何在 Vue.js 3 中編寫單元測試,並提供一些最佳實踐和常見的問題及解決方案。

在Vue.js中,開發人員可以使用兩種不同的語法來建立使用者介面:JSX語法和範本語法。這兩種文法各有優劣,以下就來探討它們的差異和優劣勢。

在實際開發專案過程中有時候需要上傳比較大的文件,然後呢,上傳的時候相對來說就會慢一些,so,後台可能會要求前端進行文件切片上傳,很簡單哈,就是把比如說1個G的檔案流切割成若干個小的檔案流,然後分別請求介面傳遞這個小的檔案流。

自從Vue3 發布之後,composition API 這個詞走入寫Vue 同學的視野之中,相信大家也一直聽到composition API 比之前的options API 有多好多強,如今由於@vue/composition-api 插件的發布,Vue2的同學也可以上車咯,接下來我們主要以響應式的ref 和reactive 來深入分析一下,這個插件是怎麼實現此

在做 chatgpt 鏡像站的時候,發現有些鏡像站是沒做打字機的遊標效果的,就只是文字輸出,是他們不想做嗎?反正我想做。於是我仔細研究了一下,實現了打字機效果加遊標的效果,現在分享一下我的解決方案以及效果圖~
