亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入淺析vue組件間事件傳遞

 更新時(shí)間:2017年12月29日 10:03:19   作者:灰色的龍貓  
最近的工作需要用到vue,所以最近接觸最多的就是vue,下面小編給大家介紹下vue組件間事件傳遞,需要的朋友參考下吧

由于新工作需要用vue,所以最近接觸最多的也是vue,因?yàn)橹耙恢痹谟胷eact,所以對于vue上手還是很快的。

我也盡量找一些他們兩個(gè)的異同點(diǎn),除了多了一些輔助用的方法以外,最大的不同應(yīng)該是對于組件間的通信,不僅有props,還有一種事件監(jiān)聽,也是可以通過組件間傳遞的。

但是,在vue2.+中,vue引入了diff算法和虛擬dom來提升效率。我們知道這些事為了處理頻繁更新dom元素所提出的一種優(yōu)化方案,可頻繁變動(dòng)更新以及事件監(jiān)聽的初始化之間是否會(huì)有矛盾,當(dāng)組件需要變動(dòng)時(shí),有沒有對注冊過的事件進(jìn)行解綁? 我們來寫一些簡單的代碼印證一下。

我們寫兩個(gè)div做的按鈕,一個(gè)是寫的html代碼,一個(gè)是通過組件的形式插入,兩個(gè)按鈕完全一樣,但我們加一個(gè)disabled的屬性在外層,并通過if-else來判斷disabled從而顯示不同的按鈕(當(dāng)然正常場景下我們不會(huì)這么去寫代碼,這里只是通過這種方式模擬一種特殊場景,我們自行考慮在我們的業(yè)務(wù)中是否存在這種場景)。

<template>
 <div class="test">
 <div class="btn" v-if="disabled" @click="handleClick">可點(diǎn)擊</div>
 <div class="btn" v-else >不可點(diǎn)擊</div>
 <Button v-if="disabled" @clickTest="handleClick">可點(diǎn)擊</Button>
 <Button v-else>不可點(diǎn)擊</Button>
 </div>
</template>

<script>
import Button from './Button'
export default {
 data () {
 return {
  disabled: true
 }
 },
 methods: {
 handleClick() {
  alert('可點(diǎn)擊')
 }
 },
 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>

我們加一點(diǎn)樣式,讓他盡量好看一點(diǎn),看著很簡單,兩個(gè)按鈕,可點(diǎn)擊時(shí)為他綁定一個(gè)點(diǎn)擊事件,不可點(diǎn)擊時(shí)不為他綁定。不同點(diǎn)是一個(gè)是直接寫的html代碼,一個(gè)是組件。組件的代碼如下:

<template>
 <div class="btn" @click="handleClick"><slot></slot></div>
</template>
<script>
 export default {
  methods: {
   handleClick() {
    this.$emit('clickTest')
   }
  }
 }
</script>

然后在mounted周期里加一個(gè)1秒的settimeout將disabled變?yōu)閒alse,然后我們測試一下

當(dāng)disabled還是true得時(shí)候,兩個(gè)按鈕點(diǎn)擊都會(huì)彈出可點(diǎn)擊的alert。但當(dāng)disebled變?yōu)閒alse的時(shí)候,上面用html寫的不會(huì)再彈框,可下面用組件寫的就還是會(huì)彈窗。

這種問題出現(xiàn)時(shí)是非常不好定位的,因?yàn)榇a上很顯然不會(huì)去調(diào)取這個(gè)clicktest事件,而在頁面上,我們也能確定按鈕已經(jīng)變?yōu)椴豢牲c(diǎn)擊的那一個(gè)了。那為什么這個(gè)事件還是會(huì)被調(diào)取呢?

這先要從diff算法說起,傳統(tǒng)的diff tree算法的算法復(fù)雜度是O(n^3),而react在引入diff算法時(shí),拋除了跨級移動(dòng)的情況,即只比對同一級的節(jié)點(diǎn)異同,讓算法復(fù)雜度降低到了O(n),讓我們可以肆無忌憚(當(dāng)然也要適可而止)的頻繁刷新整個(gè)頁面。

(呵呵,沒圖)

diff有一條策略是擁有相同類的兩個(gè)組件將會(huì)生成相似的樹形結(jié)構(gòu),擁有不同類的兩個(gè)組件將會(huì)生成不同的樹形結(jié)構(gòu)。所以它的比對順序就是

1)tree diff

2)component diff

3)element diff

回到我們的代碼上,我們在進(jìn)行component diff時(shí),認(rèn)為他們是相同的組件,然后進(jìn)行element diff,即進(jìn)行新增 刪除和移動(dòng)所以問題就是發(fā)生在了這里,在實(shí)例化組件的時(shí)候我們初始化了事件監(jiān)聽,但在替換相同組件里的dom時(shí),vue并沒有對已添加到組件上的事件監(jiān)聽做刪除。

我們看一下vue的代碼,

Vue.prototype.$emit = function (event: string): Component {
 const vm: Component = this
 if (process.env.NODE_ENV !== 'production') {
  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屬性下確定是否有綁定事件的。我們看一下不可點(diǎn)擊的按鈕的_events

:
clickTest
:
Array(1)
0
:
ƒ invoker()
length
:

發(fā)現(xiàn)clicktest還在。這就是問題所在了。

那么我們該如何去回避這樣的問題呢,還是應(yīng)從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時(shí)添加的一個(gè)屬性,用來判斷前后vdom樹上是否為統(tǒng)一元素(注意是同級關(guān)系上),所以我們只需要在代碼上加key,就可以避免這個(gè)問題

<Button key="1" v-if="disabled" @clickTest="handleClick">可點(diǎn)擊</Button>
<Button key="2" v-else>不可點(diǎn)擊</Button>

這樣,我們在點(diǎn)擊按鈕時(shí),就不會(huì)再出彈框了。

key的作用很廣泛,當(dāng)我們在遍歷數(shù)組生成dom時(shí),添加一個(gè)可確定的唯一id(注意不應(yīng)該用數(shù)組索引),會(huì)優(yōu)化我們的比對效率以及更少的操作dom。我們也會(huì)在某個(gè)div上添加key以確保他不會(huì)因?yàn)樾值茉氐淖儎?dòng)而被重新渲染(這類div一般會(huì)被綁定react或vue以外的事件或動(dòng)作,如在這個(gè)div中生成了一個(gè)canvas等)。

那么除了在組件上加這種不必要key值以外,還有別的方法解決嗎?

有的,這里有一種很反vue但是類react的方式,就是把回調(diào)事件通過props的方式傳遞,向下面著這樣,

<Button v-if="disabled" :clickTest="handleClick">可點(diǎn)擊</Button>
<Button v-else>不可點(diǎn)擊</Button>
  props: {
   'clickTest': {
    type: Function
   }
  },
  methods: {
   handleClick() {
    //this.$emit('clickTest')
    this.clickTest && this.clickTest()
   }
  }

雖然vue給了我們更方便的事件傳遞的方式,但props里是允許我們?nèi)鬟f任何類型的,我的期望是在真實(shí)的dom上或者在公共組件的入口處以外的地方,都是通過props的方式來傳遞結(jié)果的。雖然這種方式很不vue,而且也享受不到v-on給我們帶來的遍歷,但是這樣確實(shí)可以減少不必要的麻煩。

當(dāng)然既然用了vue,更好的利用vue給我們帶來的便利也很重要,所以對于這種很少會(huì)出現(xiàn)的麻煩,我們有一個(gè)預(yù)期,并可以快速定位并修復(fù)問題,就可以了。

總結(jié)

以上所述是小編給大家介紹的vue組件間事件傳遞,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • vue中使用Tinymce的示例代碼

    vue中使用Tinymce的示例代碼

    這篇文章主要介紹了vue中使用Tinymce的示例,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-08-08
  • vue中多個(gè)文件下載實(shí)現(xiàn)打包壓縮下載示例

    vue中多個(gè)文件下載實(shí)現(xiàn)打包壓縮下載示例

    這篇文章主要為大家介紹了vue中多個(gè)文件下載實(shí)現(xiàn)打包壓縮下載的發(fā)發(fā)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Vue3中v-if和v-for優(yōu)先級實(shí)例詳解

    Vue3中v-if和v-for優(yōu)先級實(shí)例詳解

    Vue.js中使用最多的兩個(gè)指令就是v-if和v-for,下面這篇文章主要給大家介紹了關(guān)于Vue3中v-if和v-for優(yōu)先級的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • 關(guān)于ElementPlus中的表單驗(yàn)證規(guī)則詳解

    關(guān)于ElementPlus中的表單驗(yàn)證規(guī)則詳解

    這篇文章主要介紹了關(guān)于ElementPlus中的表單驗(yàn)證,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • vue中v-mode詳解及使用示例詳解

    vue中v-mode詳解及使用示例詳解

    這篇文章主要介紹了vue中v-mode詳解以及具體的使用示例,在組件中使用?v-model?時(shí),需要定義model選項(xiàng),指定綁定的prop和事件,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2024-03-03
  • 詳解Vue學(xué)習(xí)筆記進(jìn)階篇之列表過渡及其他

    詳解Vue學(xué)習(xí)筆記進(jìn)階篇之列表過渡及其他

    本篇文章主要介紹了詳解Vue學(xué)習(xí)筆記進(jìn)階篇之列表過渡及其他,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-07-07
  • vue3中虛擬dom的介紹與使用詳解

    vue3中虛擬dom的介紹與使用詳解

    Vue?是如何將一份模板轉(zhuǎn)換為真實(shí)的?DOM?節(jié)點(diǎn)的,又是如何高效地更新這些節(jié)點(diǎn)的呢,這些都離不開虛擬dom這個(gè)概念,下面我們就來了解下虛擬dom這個(gè)概念以及它是什么吧
    2024-01-01
  • Vue3?props的使用示例詳解

    Vue3?props的使用示例詳解

    這篇文章主要介紹了Vue3?props的使用詳解,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-10-10
  • Vue倒計(jì)時(shí)3秒后返回首頁Demo(推薦)

    Vue倒計(jì)時(shí)3秒后返回首頁Demo(推薦)

    這篇文章主要介紹了Vue倒計(jì)時(shí)3秒后返回首頁Demo,倒計(jì)時(shí)結(jié)束后要清除計(jì)時(shí)器,防止內(nèi)存泄漏,本文通過示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2023-11-11
  • 手寫可拖動(dòng)穿梭框組件CustormTransfer vue實(shí)現(xiàn)示例

    手寫可拖動(dòng)穿梭框組件CustormTransfer vue實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了手寫可拖動(dòng)穿梭框組件CustormTransfer vue實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11

最新評論