我有一个简单的vuejs指令,可以在装载时向多姆元素添加事件监听器.我的问题是,我真的需要在稍后卸载该元素之前删除该事件监听器吗?无论如何,该元素最终都会从多姆中删除,但将监听器留在原地是否会继续消耗内存?

我的指令如下.如果我不需要清理事件监听器,它会更加简化.

/**
 * Show a confirmation popup when the element is clicked.
 */
const NAME = 'vConfirm'
let id     = 0;
export default {
    beforeMount(el, binding) {
        id++;
        // save event handler on element, so it can be cleaned up when its unmounted; is this even needed since the
        // element is being removed from the DOM when it's unmounted?
        el[`${NAME}${id}`] = (e) => {
            const message = binding.value || 'Are you sure?';
            if (!window.confirm(message)) {
                e.preventDefault();
                e.stopPropagation();
            }
        }
        el.addEventListener(binding.arg ?? 'click', el[`${NAME}${id}`], true);
    },
    beforeUnmount(el, binding) {
        el.removeEventListener(binding.arg ?? 'click', el[`${NAME}${id}`])
        delete el[`${NAME}${id}`];
    }
}

推荐答案

由于您的事件监听器没有在外部作用域中被引用,因此它将被垃圾收集.

但Vue不喜欢使用指令,因为它们是以多姆为中心的,但Vue是以VDom为中心的.

所以您可以考虑创建这样的组件:

VUE SFC PLAYGROUND

<script setup>
import { ref } from 'vue';
import Confirm from './Confirm.vue';

function navigate(msg){
  alert(msg + '...');
}

const agreed = ref(false);

</script>

<template>
  <div class="links">
    <confirm :is-valid="agreed" @close="agreed = false">
      <template #prompt><label>
        <input v-model="agreed" type="checkbox">I agree</label></template>
      <a target="_blank" href="https://stackoverflow.com" @click="navigate('Opening stackoverflow')">Open stackoverflow</a>
      <a target="_blank" href="https://vuejs.org" @click="navigate('Opening vuejs.org')">Open vuejs.org</a>
    </confirm>
  </div>
</template>

Confirm.vue

<script setup>
import {useSlots, ref, mergeProps} from 'vue';

defineProps({
  isValid:{type: Boolean, default: true}
});
const $emit = defineEmits(['close']);

const $slots = useSlots();
const $dialog = ref();

let confirmed = false;
let target = null;
const render = () => {
  return $slots.default().map(vnode => (vnode.props = mergeProps({onClick}, vnode.props ?? {}), vnode));
};

function onClick(e){
  if(confirmed){
    confirmed = false;
    return;
  }
  $dialog.value.showModal();
  e.stopImmediatePropagation();
  e.preventDefault();
  target = e.target;
}

function confirm(){
  confirmed = true;
  cancel();
  setTimeout(() => target.click());
}

function cancel(){
  $emit('close');
  $dialog.value.close();
}

</script>

<template>
  <render/>
  <dialog ref="$dialog">
    <slot name="prompt">Are you sure?</slot>
    <div class="buttons">
      <button :disabled="!isValid" @click="confirm">Yes</button>
      <button @click="cancel">Cancel</button>
    </div>
  </dialog>
</template>

Vue.js相关问答推荐

为什么在Vue.js中修改非react 性似乎是react 性的?

VueJS使所有组件崩溃,而不是只有一个

在VITE-VUE APP-DEV模式上重定向HTTP请求

为什么v-show需要组件的包装元素?

云Firestore保存额外的用户数据

使用 jquery-chosen 插件更新 vuejs 模型值

Vue + Webpack 构建显示空白页面

如何像 React 中的 {...props} 一样在 Vue 中解构 props?

NuxtServerInit 在 Vuex 模块模式下不起作用 - Nuxt.js

JavaScript/VueJS:判断数组是否包含具有特定值元素的对象

如何在 vue 3 中获取路由的参数?

[Vue 警告]:无效的props:propsscrollThreshold的类型判断失败.期望的数字,得到字符串

npm run dev 和 npm run production 的区别

如何将数据属性设置为从 Vuex getter 返回的值

'vue' 未被识别为内部或外部命令

重新加载页面正在 vue 组件中的插槽上闪烁内容

在 nuxt.js 页面中包含外部 javascript 文件

克隆元素并附加到 DOM 的正确方法

laravel vuejs/axios put request Formdata 为空

在 vue.js 应用程序中将静态内容(例如国家代码)存储在哪里?