在 vue js 中有条件地绑定自定义指令以“在元素事件外部单击”

2024-01-15

参考

根据条件添加 vue 指令 https://stackoverflow.com/questions/37526888/add-vue-directive-on-condition

检测点击外部元素 https://stackoverflow.com/questions/36170425/detect-click-outside-element

我正在为元素列表的“点击外部场景”编写自定义指令。

基本上,当单击列表中的某个项目时,它会进入选择模式。现在,如果在其他地方发生单击,我需要取消选择模式。 为此,我需要检测外部点击。 我从中找出了它的指令 为此我想出了

  const clickOutside = {
  bind: function (el, binding, vnode) {
    console.log('bind called')

    document.body.addEventListener('click', (event) => {
      // check that click was outside the el and his childrens
      if (!(el == event.target || el.contains(event.target))) {
        // and if it did, call handle method provided in attribute value
        console.log('directive working')
        vnode.context[binding.expression](event);
      }
    })
  },
  unbind: function (el) {
    document.body.removeEventListener('click', el.event)
    console.log('unbind called')
  }
}
export {
  clickOutside
}

来自上面的参考文献

现在,我只希望每个列表项在处于选定模式时监听外部点击。

所以我需要完成类似的事情

<div id="list-item"  v-on-click-outside="outSideClickHandler" //trigger only when selected>
</div>

<script>
export default{
data:{
selectedState:false;
},
methods:{
outSideClickHandler:{//......}
}
</script>

为什么不在点击外部处理程序内执行选定的检查?您还需要一种将单击的项目传递给处理程序的方法。

<div id="list-item" v-on-click-outside="outSideClickHandler(item)"></div>
outSideClickHandler(item) {
  return event => {
    if (item.selected) {
      // Handle the click outside
    }
  };
}

像这样调用指令中的处理程序:

binding.value(event);

您没有像您那样获得自定义指令的自动“表达式/语句”绑定v-on这就是为什么当您想向处理函数传递额外的参数时需要柯里化处理函数。

我的意思是参数传递给v-on可以是表达式或语句,例如:

@click="handler"        - handler is an expression (the function itself)
@click="handler(item)"  - handler(item) is a statement

但使用自定义指令时,您只能传递表达式;上面的第二行是不可能的,除非handler()返回另一个函数。


我认为存在一些混乱,因为您似乎想要一个自定义指令,该指令仅在列表项的这种特定情况下使用,但我上面的解决方案更多的是编写一个您可以使用的通用“点击外部”指令在任何情况下。

另外,我认为如果未选择列表项(出于性能原因?),您不希望指令注册任何事件侦听器。如果是这种情况,那么您可以改用事件委托。

无法有条件地启用/禁用指令,您必须执行类似的操作莫蒂的回答 https://stackoverflow.com/a/50288329/734040,两者都有点混乱。

这似乎可行,但使用自定义指令的重点是编写可重用的 dom 操作代码

您是否反对在指令之外编写 DOM 操作代码? Angular 1 就有这样的理念。除非您想在不同的情况下重用该指令,否则为这种情况编写指令可能会有点过分,只是为了“DOM 操作代码不会污染我的组件”。如果我要编写一个指令,那么我希望它尽可能通用,以便我可以在许多不同的情况下使用它。

在这种情况下我什至不需要传递该项目。因为我在 v-for 中有一个组件,而不是 div,并且我在该组件上绑定了自定义指令,其中处理程序是该组件的方法

然后我不确定为什么你想将其作为指令来实现,反正很少需要它。您只需在中注册正文点击事件即可mounted钩住并将其取出destroyed钩。所有点击外部逻辑都可以包含在组件本身内。


如果您主要关心的是不必为每个列表项注册主体单击事件侦听器,您可以执行以下操作:

const handlers = new Map();

document.addEventListener('click', e => {
    for (const handler of handlers.values()) {
        handler(e);
    }
});

Vue.directive('click-outside', {
    bind(el, binding) {
        const handler = e => {
            if (el !== e.target && !el.contains(e.target)) {
                binding.value(e);
            }
        };

        handlers.set(el, handler);
    },

    unbind(el) {
        handlers.delete(el);
    },
});

您可以更进一步,每当handlers为非空并在以下情况下删除侦听器handlers是空的。由你决定。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 vue js 中有条件地绑定自定义指令以“在元素事件外部单击” 的相关文章

  • 如何实时改变setInterval的速度

    我想知道如何实时更改 setInterval 的速度 例如 if score lt 10 repeater setInterval function spawnEnemy 1000 if score gt 10 repeater setIn
  • axios 请求中未发送正文数据

    我试图通过 axios 请求将数据发送到我的后端脚本 但正文看起来是空的 这是前端发送的请求 axios request method GET url http localhost 4444 next api headers Authori
  • 如何让Gmail像加载进度条一样

    我想在页面的中心和顶部创建一个像 Gmail 一样的加载进度条 并适用于所有浏览器 这是基本代码
  • 在 R 传单中添加不透明度滑块

    如何在 R leaflet 应用程序中添加滑块来控制特定图层的不透明度 对于这个应用程序 我不想使用闪亮 这里建议 在 R 传单应用程序中添加滑块 https stackoverflow com questions 37682619 add
  • 检测 Google 验证码的挑战窗口何时关闭

    我正在使用谷歌隐形验证码 有没有办法检测挑战窗口何时关闭 我所说的挑战窗口是指您必须选择一些图像进行验证的窗口 目前 我在按钮上放置了一个旋转器 一旦单击按钮 就会呈现验证码挑战 无法向用户提示另一个质询窗口 我以编程方式调用渲染函数 gr
  • JS 保留以零结尾的小数[重复]

    这个问题在这里已经有答案了 在JavaScript中 是否可以 锁定 十进制数 以保留以零结尾的 浮点数 例如 我有 2 个不同的数字 如下所示 伪代码 let a 1 0 let b 1 00 a b true should be fal
  • JavaScript 将键添加到数组中的每个值

    我下面有这个数组 它由一个简单的数组组成 我想要完成的是放一把钥匙id在每个数组值前面以实现类似的效果 id a id b id c id d 有没有一种简单的方法可以做到这一点 任何帮助将不胜感激 谢谢 var test a b c d
  • 检索 css3 缩放元素的宽度/高度

    我正在与 offsetWidth 属性的奇怪之处 我认为 作斗争 这是场景 比方说 我有一个span标签 在我的js中 在某个时刻我执行css3转换 对于这个元素 例如 el set styles transform scale scale
  • 全局传递 xhr onload 函数的值

    在我正在创建的应用程序中 我有以下 XMLHttpRequest 并且我正在尝试传递结果data在 的里面xhr onload 到在同一父函数中创建的数组中 var url http api soundcloud com resolve j
  • 如果没有 /// 标签,TypeScript 的“将 JavaScript 输出合并到文件中”选项无法推断出正确的脚本顺序

    我正在开发一个使用 将 JavaScript 输出合并到文件中 选项的 TypeScript 解决方案 我经常引用另一个文件中定义的项目 例如 In MyBaseClass ts export class MyBaseClass In My
  • 如果一个对象结构与另一个对象结构不匹配/不匹配,如何引发异常

    我将读取格式正确的用户输入对象 也就是说 输入对象现在可以具有接口中未定义的任何键或子结构 如果用户提供了无效的对象 我如何抛出异常 预定义接口 export interface InputStructureInterface tableN
  • ES6继承:使用`super`访问父类的属性

    JavaScript 的super关键字 当我在 Chrome Babel TypeScript 上运行代码时 得到了不同的结果 我的问题是哪个结果是正确的 规范的哪一部分定义了这种行为 下面的代码 class Point getX con
  • webpack中动态加载外部模块失败

    我正在尝试建立以下架构 一个核心 React 应用程序 它具有一些基本功能 并且能够在运行时加载其他 React 组件 这些额外的 React 组件可以按需加载 并且它们在构建核心应用程序时不可用 因此它们不能包含在核心应用程序的捆绑包中
  • 呃!尝试将包发布到 npm 时出现 403

    我正在尝试将包发布到 npm 您可以在此处查看存储库 https github com biowaffeln mdx state https github com biowaffeln mdx state 我登录到 npmnpm login
  • 如何动态调整jqgrid到当前窗口大小?

    如何动态调整jqgrid到当前窗口大小 基于javascript jQuery 最好的例子在这里 TinyMCE 去 http www tinymce com tryit full php http www tinymce com tryi
  • 如何为我的整个 Node.js 应用程序使用相同的 MySQL 连接?

    我有一个app js 我从那里运行我的整个应用程序 在 app js 内部 我require许多文件中都有代码 对于每个文件 我都这样做 var mysql require mysql var mclient mysql createCon
  • Javascript 浮点乘以 100 仍然有错误

    我有一个货币字段的文本输入 我在字段中输入 33 91 并在尝试使用 乘以 100 技术时得到以下结果 var curWth parseInt trans withdraw index val 100 3390 var curWth par
  • 如何在画布上所有其他内容后面绘制图像? [复制]

    这个问题在这里已经有答案了 我有一块画布 我想用drawImage在画布上当前内容后面绘制图像 由于画布上已经有内容 我正在使用字面上的画布来创建包含图像的画布 因此我无法真正先绘制图像 所以我无法使用drawImage在我呈现其余内容之前
  • Jwt 签名和前端登录身份验证

    我有这个特殊的 jwt sign 函数 Backend const token jwt sign id user id process env TOKEN SECRET expiresIn 1m res header auth token
  • d3.event.translate 在触摸设备的缩放上包含 NaN

    我使用 d3 为我的 svg 编写了一个自定义缩放函数 如下所示 Zoom behavior function myzoom xpos d3 event translate 0 ypos d3 event translate 1 vis a

随机推荐