首頁 web前端 js教程 在vue元件中事件如何傳遞

在vue元件中事件如何傳遞

Jun 14, 2018 pm 03:44 PM
vue 事件傳遞

最近的工作需要用到vue,所以最近接觸最多的就是vue,下面我給大家介紹下vue組件間事件傳遞,需要的朋友參考下吧

由於新工作需要用vue,所以最近接觸最多的也是vue,因為之前一直在用react,所以對於vue上手還是很快的。

我也盡量找一些他們兩個的異同點,除了多了一些輔助用的方法以外,最大的不同應該是對於組件間的通信,不僅有props,還有一種事件監聽,也是可以透過組件間傳遞的。

但是,在vue2. 中,vue引入了diff演算法和虛擬dom來提升效率。我們知道這些事為了處理頻繁更新dom元素所提出的一種優化方案,可頻繁變動更新以及事件監聽的初始化之間是否會有矛盾,當組件需要變動時,有沒有對註冊過的事件進行解綁?我們來寫一些簡單的程式碼印證一下。

我們寫兩個p做的按鈕,一個是寫的html程式碼,一個是透過元件的形式插入,兩個按鈕完全一樣,但我們加一個disabled的屬性在外層,並透過if- else來判斷disabled從而顯示不同的按鈕(當然正常場景下我們不會這麼去寫程式碼,這裡只是透過這種方式模擬一種特殊場景,我們自行考慮在我們的業務中是否存在這種場景)。

<template>
 <p class="test">
 <p class="btn" v-if="disabled" @click="handleClick">可点击</p>
 <p class="btn" v-else >不可点击</p>
 <Button v-if="disabled" @clickTest="handleClick">可点击</Button>
 <Button v-else>不可点击</Button>
 </p>
</template>

<script>
import Button from &#39;./Button&#39;
export default {
 data () {
 return {
  disabled: true
 }
 },
 methods: {
 handleClick() {
  alert(&#39;可点击&#39;)
 }
 },
 components: {
 Button,
 },
 mounted() {
 setTimeout(() => {
  this.disabled = false
 }, 1000)
 }
}
</script>
<style>
.btn{
 margin: 100px auto;
 width: 200px;
 line-height: 50px;
 border: 1px solid #42b983;
 border-radius: 5px;
 color: #42b983;
}
</style>
登入後複製

我們加一點樣式,讓他盡量好看一點,看著很簡單,兩個按鈕,可點擊時為他綁定一個點擊事件,不可點擊時不為他綁定。不同點是一個是直接寫的html程式碼,一個是元件。元件的程式碼如下:

<template>
 <p class="btn" @click="handleClick"><slot></slot></p>
</template>
<script>
 export default {
  methods: {
   handleClick() {
    this.$emit(&#39;clickTest&#39;)
   }
  }
 }
</script>
登入後複製

然後在mounted週期加一個1秒的settimeout將disabled變成false,然後我們測試一下

當disabled還是true得時候,兩個按鈕點選都會跳出可點選的alert。但當disebled變成false的時候,上面用html寫的不會再彈框,可是下面用元件寫的就還是會彈跳窗。

這種問題出現時是非常不好定位的,因為程式碼上很顯然不會去調取這個clicktest事件,而在頁面上,我們也能確定按鈕已經變成不可點擊的那一個了。那為什麼這個事件還是會被調取呢?

這先要從diff演算法說起,傳統的diff tree演算法的演算法複雜度是O(n^3),而react在引入diff演算法時,拋除了跨級移動的情況,即只比對同一層的節點異同,讓演算法複雜度降低到了O(n),讓我們可以肆無忌憚(當然也要適可而止)的頻繁刷新整個頁面。

(呵呵,沒圖)

diff有一個策略是擁有相同類別的兩個元件將會產生相似的樹狀結構,擁有不同類別的兩個元件將會產生不同的樹形結構。所以它的比對順序就是

1)tree diff

2)component diff

3)element diff

#回到我們的程式碼上,我們在進行component diff時,認為他們是相同的組件,然後進行element diff,即進行新增刪除和移動所以問題就是發生在了這裡,在實例化組件的時候我們初始化了事件監聽,但在替換相同元件裡的dom時,vue並沒有對已加入元件上的事件監聽做刪除。

我們看一下vue的程式碼,###
Vue.prototype.$emit = function (event: string): Component {
 const vm: Component = this
 if (process.env.NODE_ENV !== &#39;production&#39;) {
  const lowerCaseEvent = event.toLowerCase()
  if (lowerCaseEvent !== event && vm._events[lowerCaseEvent]) {
  tip(
   `Event "${lowerCaseEvent}" is emitted in component ` +
   `${formatComponentName(vm)} but the handler is registered for "${event}". ` +
   `Note that HTML attributes are case-insensitive and you cannot use ` +
   `v-on to listen to camelCase events when using in-DOM templates. ` +
   `You should probably use "${hyphenate(event)}" instead of "${event}".`
  )
  }
 }
 let cbs = vm._events[event]
 if (cbs) {
  cbs = cbs.length > 1 ? toArray(cbs) : cbs
  const args = toArray(arguments, 1)
  for (let i = 0, l = cbs.length; i < l; i++) {
  try {
   cbs[i].apply(vm, args)
  } catch (e) {
   handleError(e, vm, `event handler for "${event}"`)
  }
  }
 }
 return vm
 }
登入後複製
###vue是透過vdom裡的_events屬性下確定是否有綁定事件的。我們看一下不可點擊的按鈕的_events###
:
clickTest
:
Array(1)
0
:
ƒ invoker()
length
:
登入後複製
###發現clicktest還在。這就是問題所在了。 ######那我們該如何去迴避這樣的問題呢,還是該從diff的比對方式來解決問題,還是看程式碼。 ###
function sameVnode (a, b) {
 return (
 a.key === b.key && (
  (
  a.tag === b.tag &&
  a.isComment === b.isComment &&
  isDef(a.data) === isDef(b.data) &&
  sameInputType(a, b)
  ) || (
  isTrue(a.isAsyncPlaceholder) &&
  a.asyncFactory === b.asyncFactory &&
  isUndef(b.asyncFactory.error)
  )
 )
 )
}
登入後複製
###也就是對diff來說,所謂相同的第一判定原則就是key。 ######key也是react引入diff時添加的屬性,用來判斷前後vdom樹上是否為統一元素(注意是同級關係上),所以我們只需要在程式碼上加上key,就可以避免這個問題###
<Button key="1" v-if="disabled" @clickTest="handleClick">可点击</Button>
<Button key="2" v-else>不可点击</Button>
登入後複製
###這樣,我們在點擊按鈕時,就不會再出彈框了。 ######key的作用很廣泛,當我們在遍歷數組生成dom時,添加一個可確定的唯一id(注意不應該用數組索引),會優化我們的比對效率以及更少的操作dom 。我們也會在某個p上添加key以確保他不會因為兄弟元素的變動而被重新渲染(這類p一般會被綁定react或vue以外的事件或動作,如在這個p中生成了一個canvas等)。 ######那麼除了在元件上加上這種不必要key值以外,還有別的方法可以解決嗎? ######有的,這裡有一種很反vue但是類別react的方式,就是把回呼事件透過props的方式傳遞,向下面著這樣,###
<Button v-if="disabled" :clickTest="handleClick">可点击</Button>
<Button v-else>不可点击</Button>
  props: {
   &#39;clickTest&#39;: {
    type: Function
   }
  },
  methods: {
   handleClick() {
    //this.$emit(&#39;clickTest&#39;)
    this.clickTest && this.clickTest()
   }
  }
登入後複製

虽然vue给了我们更方便的事件传递的方式,但props里是允许我们去传递任何类型的,我的期望是在真实的dom上或者在公共组件的入口处以外的地方,都是通过props的方式来传递结果的。虽然这种方式很不vue,而且也享受不到v-on给我们带来的遍历,但是这样确实可以减少不必要的麻烦。

当然既然用了vue,更好的利用vue给我们带来的便利也很重要,所以对于这种很少会出现的麻烦,我们有一个预期,并可以快速定位并修复问题,就可以了。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在vue中如何通过v-for处理数组

使用vue如何实现收藏夹

在node.js中有关npm和webpack配置方法

如何通过js将当前时间格式化?

使用vue引入css,less相关问题

以上是在vue元件中事件如何傳遞的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

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

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

熱門話題

Java教學
1666
14
CakePHP 教程
1425
52
Laravel 教程
1327
25
PHP教程
1273
29
C# 教程
1253
24
vue中怎麼用bootstrap vue中怎麼用bootstrap Apr 07, 2025 pm 11:33 PM

在 Vue.js 中使用 Bootstrap 分為五個步驟:安裝 Bootstrap。在 main.js 中導入 Bootstrap。直接在模板中使用 Bootstrap 組件。可選:自定義樣式。可選:使用插件。

vue怎麼給按鈕添加函數 vue怎麼給按鈕添加函數 Apr 08, 2025 am 08:51 AM

可以通過以下步驟為 Vue 按鈕添加函數:將 HTML 模板中的按鈕綁定到一個方法。在 Vue 實例中定義該方法並編寫函數邏輯。

vue中的watch怎麼用 vue中的watch怎麼用 Apr 07, 2025 pm 11:36 PM

Vue.js 中的 watch 選項允許開發者監聽特定數據的變化。當數據發生變化時,watch 會觸發一個回調函數,用於執行更新視圖或其他任務。其配置選項包括 immediate,用於指定是否立即執行回調,以及 deep,用於指定是否遞歸監聽對像或數組的更改。

vue返回上一頁的方法 vue返回上一頁的方法 Apr 07, 2025 pm 11:30 PM

Vue.js 返回上一頁有四種方法:$router.go(-1)$router.back()使用 &lt;router-link to=&quot;/&quot;&gt; 組件window.history.back(),方法選擇取決於場景。

vue多頁面開發是啥意思 vue多頁面開發是啥意思 Apr 07, 2025 pm 11:57 PM

Vue 多頁面開發是一種使用 Vue.js 框架構建應用程序的方法,其中應用程序被劃分為獨立的頁面:代碼維護性:將應用程序拆分為多個頁面可以使代碼更易於管理和維護。模塊化:每個頁面都可以作為獨立的模塊,便於重用和替換。路由簡單:頁面之間的導航可以通過簡單的路由配置來管理。 SEO 優化:每個頁面都有自己的 URL,這有助於搜索引擎優化。

React與Vue:Netflix使用哪個框架? React與Vue:Netflix使用哪個框架? Apr 14, 2025 am 12:19 AM

NetflixusesAcustomFrameworkcalled“ Gibbon” BuiltonReact,notReactorVuedIrectly.1)TeamSperience:selectBasedonFamiliarity.2)ProjectComplexity:vueforsimplerprojects:reactforforforproproject,reactforforforcompleplexones.3)cocatizationneedneeds:reactoffipicatizationneedneedneedneedneedneeds:reactoffersizationneedneedneedneedneeds:reactoffersizatization needefersmoreflexibleise.4)

vue.js怎麼引用js文件 vue.js怎麼引用js文件 Apr 07, 2025 pm 11:27 PM

在 Vue.js 中引用 JS 文件的方法有三種:直接使用 &lt;script&gt; 標籤指定路徑;利用 mounted() 生命週期鉤子動態導入;通過 Vuex 狀態管理庫進行導入。

vue遍歷怎麼用 vue遍歷怎麼用 Apr 07, 2025 pm 11:48 PM

Vue.js 遍歷數組和對像有三種常見方法:v-for 指令用於遍歷每個元素並渲染模板;v-bind 指令可與 v-for 一起使用,為每個元素動態設置屬性值;.map 方法可將數組元素轉換為新數組。

See all articles