欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue3中addEventListener的用法詳解

 更新時間:2023年08月23日 09:32:39   作者:遠(yuǎn)山無期  
vue3中定義全局指令時,往往會碰到一個問題:事件無法解綁,為什么會這樣,因為通常在指令的mounted鉤子中綁定事件,事件處理函數(shù)也定義在mounted中,本文講給大家講講vue3中addEventListener的妙用,需要的朋友可以參考下

緣起

vue3中定義全局指令時,往往會碰到一個問題:事件無法解綁。為什么會這樣,因為通常在指令的mounted鉤子中綁定事件,事件處理函數(shù)也定義在mounted中。在指令的unmounted鉤子函數(shù)中無法獲取到定義的事件處理函數(shù),所以綁定的事件無法銷毀,尤其當(dāng)這個事件是綁定在父組件,或者body上時,無法解綁事件,指令大量使用會造成性能問題。

removeEventListener 方法可以刪除使用 addEventListener 方法添加的事件。使用事件類型,事件偵聽器函數(shù)本身,以及可能影響匹配過程的各種可選擇的選項的組合來標(biāo)識要刪除的事件偵聽器,簡單說要使用removeEventListener移除事件,需要事件處理函數(shù)和添加時的事件處理函數(shù)是同一個。

如下一個判斷鼠標(biāo)點擊區(qū)域是否在指定區(qū)域內(nèi)的指令:

// 使用場景:僅在點擊select組件外部區(qū)域,收起下拉選項
import { Directive } from 'vue'
export const clickOutside: Directive = {
  mounted(el: Element, { value }) {
    const controller = new AbortController()
    controllerMap.set(el, controller)
    document.body.addEventListener(
      'click',
      (e) => {
        // 在外部區(qū)域點擊了
        if (!el.contains(e.target as Element)) {
          typeof value === 'function' && value()
        }
      }
    )
  }
}

如上指令,在銷毀時無法進(jìn)行事件的移除,導(dǎo)致事件處理函數(shù)無法被銷毀,占用內(nèi)存無法釋放:

尋解

查看mdn# addEventListener的解釋,發(fā)現(xiàn)了一個神奇的參數(shù):

  • signal 可選: AbortSignal,該 AbortSignalabort() 方法被調(diào)用時,監(jiān)聽器會被移除。

這不就可以完美解決了么,立馬優(yōu)化指令:

import { Directive } from 'vue'
const controllerMap = new WeakMap<Element, AbortController>()
export const clickOutside: Directive = {
  mounted(el: Element, { value }) {
    const controller = new AbortController()
    controllerMap.set(el, controller)
    document.body.addEventListener(
      'click',
      (e) => {
        // 在外部區(qū)域點擊了
        if (!el.contains(e.target as Element)) {
          typeof value === 'function' && value()
        }
      },
      {
        capture: true, // 為了防止v-if切換導(dǎo)致的判斷誤差,在捕獲階段觸發(fā)事件
        signal: controller.signal
      }
    )
  },
  beforeUnmount(el) {
    const controller = controllerMap.get(el)
    controller?.abort() // 移除事件
  }
}

如上,在指令銷毀時,觸發(fā)beforeUnmount事件,調(diào)用控制對象控制器對象abort方法移除事件

注意:當(dāng)我們點擊某塊區(qū)域的時候,需要先判斷是否在指定的區(qū)域內(nèi),然后再執(zhí)行相應(yīng)的邏輯,這時要求判斷是否在區(qū)域內(nèi)的點擊事件,要優(yōu)先執(zhí)行,所以要設(shè)置指令的點擊事件在事件捕獲階段觸發(fā), 即:capture: true

場景

如下場景:

<template>
  <div class="edit-cell" v-clickOutside="clickOutside">
    <template v-if="!edit">
      <a-tooltip :title="value" v-if="value.length > 20">
        <div class="text text-ellipsis">
          {{ value || '--' }}
        </div>
      </a-tooltip>
      <div v-else>{{ value || '--' }}</div>
      &nbsp;
      <edit-outlined class="editable-cell-icon icon" @click="enableEdit" />
    </template>
    <template v-else>
      <component
        :is="EditComponent"
        ref="editComponentRef"
        :placeholder="$t('correction.create.modal.form.projectName.err')"
        class="text-edit"
        :maxLength="200"
        @input="change"
        style="height: 60px; resize: none"
        :value="currentValue"
        @pressEnter="pressEnter"
      />
      &nbsp;
      <check-outlined class="editable-cell-icon-check icon" @click="save" />
    </template>
  </div>
</template>
<script lang="ts" setup>
  import { EditOutlined, CheckOutlined } from '@ant-design/icons-vue'
  const props = defineProps({
    value: {
      type: String,
      default: ''
    },
    type: {
      type: String as PropType<'input' | 'textarea'>,
      default: 'input'
    }
  })
  const emits = defineEmits<{
    change: [value: string]
  }>()
  const currentValue = ref<string>('')
  const EditComponent = computed(() =>
    props.type === 'input' ? 'NWInput' : 'ATextarea'
  )
  const edit = ref<boolean>(false)
  const change = ({ target }) => {
    currentValue.value = target?.value ?? ''
  }
  const pressEnter = () => {
    emits('change', currentValue.value)
    edit.value = false
  }
  const save = () => {
    emits('change', currentValue.value)
    edit.value = false
  }
  const editComponentRef = shallowRef()
  const enableEdit = () => {
    currentValue.value = props.value
    edit.value = true
    nextTick(() => {
      editComponentRef.value.focus()
    })
  }
  const clickOutside = () => {
    edit.value = false
  }
</script>
<style lang="less" scoped>
  .edit-cell {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    .text-edit,
    .text {
      flex: 1;
    }
    &:hover {
      .icon {
        visibility: visible;
      }
    }
    .icon {
      visibility: hidden;
    }
  }
  .text-ellipsis {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    text-align: left !important;
  }
</style>

另一種思路

可以將處理函數(shù)定義在指令外,所有指令共用同一個處理函數(shù),參數(shù)綁定在處理函數(shù)上,類似vue2中依賴收集時的:Dep.target,將當(dāng)前處理的watcher存儲在Dep函數(shù)的target屬性中,當(dāng)然這種方式只適用于串行的場景

到此這篇關(guān)于vue3中addEventListener的用法詳解的文章就介紹到這了,更多相關(guān)vue3 addEventListener用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue中iframe使用以及結(jié)合postMessage實現(xiàn)跨域通信

    vue中iframe使用以及結(jié)合postMessage實現(xiàn)跨域通信

    這篇文章主要介紹了vue中iframe使用以及結(jié)合postMessage實現(xiàn)跨域通信方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 在vue使用echarts報錯:invalid dom問題

    在vue使用echarts報錯:invalid dom問題

    這篇文章主要介紹了在vue使用echarts報錯:invalid dom問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Element-UI清空表單及驗證不生效的問題解決

    Element-UI清空表單及驗證不生效的問題解決

    本文主要介紹了Element-UI清空表單及驗證不生效的問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • 詳解VueRouter進(jìn)階之導(dǎo)航鉤子和路由元信息

    詳解VueRouter進(jìn)階之導(dǎo)航鉤子和路由元信息

    本篇文章主要介紹了詳解VueRouter進(jìn)階之導(dǎo)航鉤子和路由元信息,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • Vue.js與Flask/Django后端配合方式

    Vue.js與Flask/Django后端配合方式

    在現(xiàn)代Web開發(fā)中,Vue.js與Flask或Django配合使用,實現(xiàn)前后端分離,提高開發(fā)效率和應(yīng)用性能,本文介紹了整合Vue.js和Flask/Django的步驟,包括環(huán)境搭建、API編寫、項目配置,以及生產(chǎn)部署,此架構(gòu)不僅加快了開發(fā)進(jìn)程,還提高了項目的可維護(hù)性和可擴(kuò)展性
    2024-09-09
  • Vue3.0數(shù)據(jù)響應(yīng)式原理詳解

    Vue3.0數(shù)據(jù)響應(yīng)式原理詳解

    這篇文章主要介紹了Vue3.0數(shù)據(jù)響應(yīng)式原理詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • 在vue中動態(tài)修改css其中一個屬性值操作

    在vue中動態(tài)修改css其中一個屬性值操作

    這篇文章主要介紹了在vue中動態(tài)修改css其中一個屬性值操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • vue-property-decorator用法詳解

    vue-property-decorator用法詳解

    這篇文章主要介紹了vue-property-decorator用法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • axios中如何進(jìn)行同步請求(async+await)

    axios中如何進(jìn)行同步請求(async+await)

    這篇文章主要介紹了axios中如何進(jìn)行同步請求(async+await),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 如何解決element-ui動態(tài)加載級聯(lián)選擇器默認(rèn)選中問題

    如何解決element-ui動態(tài)加載級聯(lián)選擇器默認(rèn)選中問題

    這篇文章主要介紹了如何解決element-ui動態(tài)加載級聯(lián)選擇器默認(rèn)選中問題,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下
    2022-09-09

最新評論