成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

關(guān)于vue事件監(jiān)聽的一個(gè)問題

sixgo / 3257人閱讀

摘要:可歸根結(jié)底,所謂事件監(jiān)聽,通常都是一個(gè)需要預(yù)處理的過程,即在你初始化你的實(shí)例時(shí)就需要去為其注冊(cè)監(jiān)聽。當(dāng)然既然用了,更好的利用給我們帶來的遍歷也很重要,所以對(duì)于這種很少會(huì)出現(xiàn)的麻煩,我們有一個(gè)預(yù)期,并可以快速定位并修復(fù)問題,就可以了

由于新工作需要用vue,所以最近接觸最多的也是vue,因?yàn)橹耙恢痹谟胷eact,所以對(duì)于vue上手還是很快的。
我也盡量找一些他們兩個(gè)的異同點(diǎn),除了多了一些輔助用的方法以外,最大的不同應(yīng)該是對(duì)于組件間的通信,不僅有props,還有一種事件監(jiān)聽,也是可以通過組件間傳遞的。
我們知道vue的事件監(jiān)聽是一個(gè)很方便的設(shè)計(jì),代碼上一目了然,而且給我們?cè)黾恿硕喾N修飾符(雖然我都沒怎么用過)來簡(jiǎn)化你的代碼??蓺w根結(jié)底,所謂事件監(jiān)聽,通常都是一個(gè)需要預(yù)處理的過程,即在你初始化你的實(shí)例時(shí)就需要去為其注冊(cè)監(jiān)聽。這當(dāng)然沒什么不好,我們之所以需要做事件監(jiān)聽,就是為了當(dāng)我們因?yàn)闃I(yè)務(wù)復(fù)雜而形成一個(gè)事件需要觸發(fā)多處回調(diào)時(shí),我們可以通過這種注冊(cè)監(jiān)聽機(jī)制更好的管理他們。這一點(diǎn)上他比react做的更好,如果在react里我們需要中途給某個(gè)事件添加更多回調(diào),我們需要手動(dòng)維護(hù)更多的代碼(這里說的事件監(jiān)聽機(jī)制單指vue的v-on方式,react本身dom上的事件是通過事件代理方式統(tǒng)一在document身上并通過每個(gè)dom的唯一id來維護(hù)一個(gè)hashMap來實(shí)現(xiàn)的)。
但是,在vue2.+中,vue引入了diff算法和虛擬dom來提升效率。我們知道這些事為了處理頻繁更新dom元素所提出的一種優(yōu)化方案,可頻繁變動(dòng)更新以及事件監(jiān)聽的初始化之間是否會(huì)有矛盾,當(dāng)組件需要變動(dòng)時(shí),有沒有對(duì)注冊(cè)過的事件進(jìn)行解綁? 我們來寫一些簡(jiǎn)單的代碼印證一下。

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




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


然后在mounted周期里加一個(gè)1秒的settimeout將disabled變?yōu)閒alse,然后我們測(cè)試一下
(靠!傳圖片失敗····· 我們用語言描述吧)
總之就是,當(dāng)disabled還是true得時(shí)候,兩個(gè)按鈕點(diǎn)擊都會(huì)彈出可點(diǎn)擊的alert。但當(dāng)disebled變?yōu)閒alse的時(shí)候,上面用html寫的不會(huì)再?gòu)椏?,可下面用組件寫的就還是會(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í),拋除了跨級(jí)移動(dòng)的情況,即只比對(duì)同一級(jí)的節(jié)點(diǎn)異同,讓算法復(fù)雜度降低到了O(n),讓我們可以肆無忌憚(當(dāng)然也要適可而止)的頻繁刷新整個(gè)頁面。
(呵呵,沒圖)
diff有一條策略是擁有相同類的兩個(gè)組件將會(huì)生成相似的樹形結(jié)構(gòu),擁有不同類的兩個(gè)組件將會(huì)生成不同的樹形結(jié)構(gòu)。所以它的比對(duì)順序就是
1)tree diff
2)component diff
3)element diff
回到我們的代碼上,我們?cè)谶M(jìn)行component diff時(shí),認(rèn)為他們是相同的組件,然后進(jìn)行element diff,即進(jìn)行新增 刪除和移動(dòng)
所以問題就是發(fā)生在了這里,在實(shí)例化組件的時(shí)候我們初始化了事件監(jiān)聽,但在替換相同組件里的dom時(shí),vue并沒有對(duì)已添加到組件上的事件監(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
:
1

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

那么我們?cè)撊绾稳セ乇苓@樣的問題呢,還是應(yīng)從diff的比對(duì)方式來解決問題,還是看代碼。

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)
      )
    )
  )
}

也就是對(duì)diff來說,所謂相同的第一判定原則是key。
key也是react引入diff時(shí)添加的一個(gè)屬性,用來判斷前后vdom樹上是否為統(tǒng)一元素(注意是同級(jí)關(guān)系上),所以我們只需要在代碼上加key,就可以避免這個(gè)問題


這樣,我們?cè)邳c(diǎn)擊按鈕時(shí),就不會(huì)再出彈框了。
key的作用很廣泛,當(dāng)我們?cè)诒闅v數(shù)組生成dom時(shí),添加一個(gè)可確定的唯一id(注意不應(yīng)該用數(shù)組索引),會(huì)優(yōu)化我們的比對(duì)效率以及更少的操作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的方式傳遞,向下面著這樣,


        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給我們帶來的遍歷也很重要,所以對(duì)于這種很少會(huì)出現(xiàn)的麻煩,我們有一個(gè)預(yù)期,并可以快速定位并修復(fù)問題,就可以了

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/90439.html

相關(guān)文章

  • 人人都能懂Vue源碼系列—09—initEvents

    摘要:回調(diào)函數(shù)會(huì)接收所有傳入事件觸發(fā)函數(shù)的額外參數(shù)。這種方式類似于中的監(jiān)聽事件和觸發(fā)事件如果不是上面這種方法指定的鉤子函數(shù),就需要執(zhí)行源碼上半部分的代碼邏輯。 上篇文章中,我們主要講了initLiftcycle方法,它的作用是初始化vm實(shí)例中和生命周期相關(guān)的屬性。今天為大家介紹另一個(gè)方法——initEvents。從這個(gè)方法的名稱來看,我們知道它是和事件相關(guān)的方法,具體怎么相關(guān),我們先來看源碼...

    lovXin 評(píng)論0 收藏0
  • Vue.js中v-on(事件處理)

    摘要:不必?fù)?dān)心,因?yàn)樗械氖录幚矸椒ê捅磉_(dá)式都嚴(yán)格綁定在當(dāng)前視圖的上,它不會(huì)導(dǎo)致任何維護(hù)上的困難。當(dāng)一個(gè)被銷毀時(shí),所有的事件處理器都會(huì)自動(dòng)被刪除。 Vue.js的事件處理 監(jiān)聽事件 我們可以用 v-on 指令監(jiān)聽 DOM 事件來觸發(fā)一些 JavaScript 代碼。 {{msg}} var vm = new Vue({ el:.box, data:{ ...

    YuboonaZhang 評(píng)論0 收藏0
  • 關(guān)于input一些問題解決方法分享

    摘要:輸入框首尾清除空格在中監(jiān)聽鍵盤事件移動(dòng)端底部被彈出的鍵盤遮擋輸入框是通過一直放在頁面底部,當(dāng)點(diǎn)擊進(jìn)行輸入的時(shí)候,就會(huì)出現(xiàn)如下圖片情況有的機(jī)型會(huì)遮擋一些。 前言 input是我們接受來自用戶的數(shù)據(jù)常用標(biāo)簽,在前端開發(fā)中,相信每個(gè)人都會(huì)用到這個(gè)標(biāo)簽,所以在開發(fā)過程中也時(shí)候也會(huì)遇到一些問題,本文的內(nèi)容是我在跟input相愛相殺過程中產(chǎn)生的,在此記錄分享一下。如果喜歡的話可以點(diǎn)波贊/關(guān)注,支持...

    騫諱護(hù) 評(píng)論0 收藏0
  • 關(guān)于input一些問題解決方法分享

    摘要:輸入框首尾清除空格在中監(jiān)聽鍵盤事件移動(dòng)端底部被彈出的鍵盤遮擋輸入框是通過一直放在頁面底部,當(dāng)點(diǎn)擊進(jìn)行輸入的時(shí)候,就會(huì)出現(xiàn)如下圖片情況有的機(jī)型會(huì)遮擋一些。 前言 input是我們接受來自用戶的數(shù)據(jù)常用標(biāo)簽,在前端開發(fā)中,相信每個(gè)人都會(huì)用到這個(gè)標(biāo)簽,所以在開發(fā)過程中也時(shí)候也會(huì)遇到一些問題,本文的內(nèi)容是我在跟input相愛相殺過程中產(chǎn)生的,在此記錄分享一下。如果喜歡的話可以點(diǎn)波贊/關(guān)注,支持...

    vibiu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<