国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Vue實例方法之事件的實現(xiàn)

SwordFly / 3076人閱讀

摘要:例子觸發(fā)自定義事件二源碼分析事件的初始化工作我們在使用自定義事件的的時候,肯定有個地方是需要來存我們的事件和回調(diào)的地方。這里不做過多討論自定義事件的掛載方式自定義事件的掛載是在方法中實現(xiàn)的。

開始

這段時間一直在看vue的源碼,源碼非常多和雜,所以自己結(jié)合資料和理解理出了一個主線,然后根據(jù)主線去剝離其他的一些知識點,然后將各個知識點逐一學(xué)習(xí)。這里主要是分析的事件系統(tǒng)的實現(xiàn)。

正文 一、了解使用方式

在分析之前先了解下幾個api的使用方式:

vm.$on(event, callback)

參數(shù)

{string | Array} event (數(shù)組只在 2.2.0+ 中支持)

{Function} callback

用法$on事件需要兩個參數(shù),一個是監(jiān)聽的當(dāng)前實例上的事件名,一個是事件觸發(fā)的回調(diào)函數(shù),回調(diào)函數(shù)接受的是在事件出發(fā)的時候額外傳遞的參數(shù)。

例子:

vm.$on("test", function (msg) {
  console.log(msg)
})
vm.$emit("test", "hi")
// => "hi"
vm.$once(event, callback)

$once事件整體上來說和$on事件的使用方式差不多,但是event只支持字符串也就是說只支持單個事件。并且該事件再觸發(fā)一次后就移除了監(jiān)聽器。

例子

vm.$once("testonce", function (msg) {
  console.log(msg)
})
vm.$off([event, callback])

參數(shù)

{string | Array} event(僅在 2.2.2+ 支持數(shù)組)

{Function} [callback]

用法:移除自定義事件監(jiān)聽器

如果沒有提供參數(shù),則移除所有的事件監(jiān)聽器

如果只提供了事件,則移除該事件所有的監(jiān)聽器;

如果同時提供了事件與回調(diào),則只移除這個回調(diào)的監(jiān)聽器。

例子

vm.$off()
vm.$off("test")
vm.$off("test1", function (msg) {
  console.log(msg)
})
vm.$off(["test1","test2"], function (msg) {
  console.log(msg)
})
vm.$emit(event, [..args])

參數(shù)

{string} event 要觸發(fā)的事件名

[...args]可選

用法

觸發(fā)當(dāng)前實例上的事件。附加參數(shù)都會傳給監(jiān)聽器回調(diào)。

例子

vm.$emit("test", "觸發(fā)自定義事件")
二、源碼分析
事件的初始化工作

我們在使用自定義事件的api的時候,肯定有個地方是需要來存我們的事件和回調(diào)的地方。在vue中大部分的初始化工作都是在core/instance/init.jsinitMixin方法中。所以我們能夠在initMixin看到initEvents方法。

// initEvents
export function initEvents (vm: Component) {
  vm._events = Object.create(null)
  vm._hasHookEvent = false
  // init parent attached events
  const listeners = vm.$options._parentListeners
  if (listeners) {
    updateComponentListeners(vm, listeners)
  }
}

上面的代碼可以看到,在初始化Vue事件的時候,在vm實例上面掛載了一個_events的空對象。后面我們自己調(diào)用的自定義事件都存在里面。

因為vue本身在組件嵌套的時候就有子組件使用父組件的事件的時候。所以就可以通過updateComponentListeners方法把父組件事件監(jiān)聽器(比如click)傳遞給子組件。(這里不做過多討論)

自定義事件的掛載方式

自定義事件的掛載是在eventsMixin方法中實現(xiàn)的。這里面將四個方法掛在Vue的原型上面。

Vue.prototype.$on
Vue.prototype.$once
Vue.prototype.$off
Vue.prototype.$emit
Vue.prototype.$on的實現(xiàn)
Vue.prototype.$on = function (event: string | Array, fn: Function): Component {
const vm: Component = this
    if (Array.isArray(event)) {
      for (let i = 0, l = event.length; i < l; i++) {
        this.$on(event[i], fn)
      }
    } else {
      (vm._events[event] || (vm._events[event] = [])).push(fn)
      // optimize hook:event cost by using a boolean flag marked at registration
      // instead of a hash lookup
      if (hookRE.test(event)) {
        vm._hasHookEvent = true
      }
    }
    return vm
}

第一個參數(shù)就是自定義事件,因為可能是數(shù)組,所以判斷如果是數(shù)組,那么就循環(huán)調(diào)用this.$on方法。
如果不是數(shù)組,那么就直接向最開始定義的_events對象集合里面添加自定義事件。

所以這個時候_events對象生成的格式大概就是下面:

vm._events={
    "test":[fn,fn...],
    "test1":[fn,fn...]
}
Vue.prototype.$once 的實現(xiàn)
Vue.prototype.$once = function (event: string, fn: Function): Component {
    const vm: Component = this
    function on () {
      vm.$off(event, on)
      fn.apply(vm, arguments)
    }
    on.fn = fn
    vm.$on(event, on)
    return vm
}

這里定義了一個on函數(shù)。接著把fn賦值給on.fn。最后在調(diào)用的是vm.$on。這里傳入的就是事件名和前面定義的on函數(shù)。on函數(shù)在執(zhí)行的時候會先移除_events中對應(yīng)的事件,然后調(diào)用fn

所以分析下得到的是:

vm._events={
    "oncetest":[ 
          function on(){
              vm.$off(event,on)
              fn.apply(vm,arguments)
          } ,
          ...
     ]
}
Vue.prototype.$off的實現(xiàn)
Vue.prototype.$off = function (event?: string | Array, fn?: Function): Component {
    const vm: Component = this
    // all
    // 如果沒有傳任何參數(shù)的時候,直接清楚所有掛在_events對象上的所有事件。
    if (!arguments.length) {
      vm._events = Object.create(null)
      return vm
    }
    // array of events
    // 如果第一個參數(shù)是數(shù)組的話,那么就循環(huán)調(diào)用this.$off方法
    if (Array.isArray(event)) {
      for (let i = 0, l = event.length; i < l; i++) {
        this.$off(event[i], fn)
      }
      return vm
    }
    // specific event
    // 獲取對應(yīng)事件所有的回調(diào)可能是個數(shù)組
    const cbs = vm._events[event]
    // 沒有相關(guān)的事件的時候直接返回vm實例
    if (!cbs) {
      return vm
    }
    // 如果只傳入了事件名,那么清除該事件名下所有的事件。 也就是說 vm._events = {"test": null, ...}
    if (!fn) {
      vm._events[event] = null
      return vm
    }
    // 如果傳入的第二個參數(shù)為真,那么就去cbs里面遍歷,在cbs中找到和fn相等的函數(shù),然后通過splice刪除該函數(shù)。
    if (fn) {
      // specific handler
      let cb
      let i = cbs.length
      while (i--) {
        cb = cbs[i]
        if (cb === fn || cb.fn === fn) {
          cbs.splice(i, 1)
          break
        }
      }
    }
    return vm
}

上面主要就是實現(xiàn)的下面三種情況:

如果沒有提供參數(shù),則移除所有的事件監(jiān)聽器;

如果只提供了事件,則移除該事件所有的監(jiān)聽器;

如果同時提供了事件與回調(diào),則只移除這個回調(diào)的監(jiān)聽器。

Vue.prototype.$emit 的實現(xiàn)
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}".`
        )
      }
    }
    // 匹配到事件列表,該列表是一個json。
    let cbs = vm._events[event]
    if (cbs) {
      //將該json轉(zhuǎn)化成為真正的數(shù)組
      cbs = cbs.length > 1 ? toArray(cbs) : cbs
      const args = toArray(arguments, 1)
      // 循環(huán)遍歷調(diào)用所有的自定義事件。
      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
}

上面主要意思是:匹配到j(luò)son中相關(guān)key值的value,這個value先轉(zhuǎn)換成真正的數(shù)組,再循環(huán)遍歷數(shù)組,傳入給的參數(shù)執(zhí)行數(shù)組中的每個函數(shù)

最后

vue中的自定義事件主要目的是為了組件之間的通信。因為_events對象是掛在Vue實例上的。因此每個組件是都可以訪問到vm._events的值的,也能夠向其中push值的。

整個自定義事件系統(tǒng)呢就是在vm實例上掛載一個_events的對象,可以理解為一個json,其中json的key值就是自定義事件的名稱,一個key值可能對應(yīng)著多個自定義事件,因此json中每個key對應(yīng)的value都是一個數(shù)組,每次執(zhí)行事件監(jiān)聽都會向數(shù)組中push相關(guān)的函數(shù),最終通過$emit函數(shù)傳入的參數(shù),匹配到j(luò)son中相應(yīng)的key,val值,從而使用給定的參數(shù)執(zhí)行數(shù)組中的函數(shù)

最后的_events對象:

vm._events={
    "test1":[fn,fn,fn],
    "test2":[fn],
    "oncetest":[ 
          function on(){
              vm.$off(event,on)
              fn.apply(vm,arguments)
          },
          ... 
     ],
     ...
}

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/52328.html

相關(guān)文章

  • Vue實例方法事件實現(xiàn)

    摘要:例子觸發(fā)自定義事件二源碼分析事件的初始化工作我們在使用自定義事件的的時候,肯定有個地方是需要來存我們的事件和回調(diào)的地方。這里不做過多討論自定義事件的掛載方式自定義事件的掛載是在方法中實現(xiàn)的。 開始 這段時間一直在看vue的源碼,源碼非常多和雜,所以自己結(jié)合資料和理解理出了一個主線,然后根據(jù)主線去剝離其他的一些知識點,然后將各個知識點逐一學(xué)習(xí)。這里主要是分析的事件系統(tǒng)的實現(xiàn)。 正文 一、...

    劉德剛 評論0 收藏0
  • Vue原理】Event - 源碼版 綁定組件自定義事件

    摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關(guān)注公眾號也可以吧原理源碼版之綁定組件自定義事件組件 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于...

    amuqiao 評論0 收藏0
  • Vue.js起手式+Vue小作品實戰(zhàn)

    摘要:本文是小羊根據(jù)文檔進行解讀的第一篇文章,主要內(nèi)容涵蓋的基礎(chǔ)部分的知識的,文章順序基本按照官方文檔的順序,每個知識點現(xiàn)附上代碼,然后根據(jù)代碼給予個人的一些理解,最后還放上在線編輯的代碼以供練習(xí)和測試之用在最后,我參考上的一篇技博,對進行初入的 本文是小羊根據(jù)Vue.js文檔進行解讀的第一篇文章,主要內(nèi)容涵蓋Vue.js的基礎(chǔ)部分的知識的,文章順序基本按照官方文檔的順序,每個知識點現(xiàn)附上代...

    CompileYouth 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<