干什么用的?
el.contains(node)
用来判断一个元素是否在另一个元素内.
一般组价库中的"下拉"和"气泡对话框"用这个特性来实现"点击组件外部关闭组件"功能.
17行实现clickOutside(点击元素外部触发)
本文并不是要讲如何实现一个"气泡"组件, 而是实现一个组件中的通用功能:点击元素外部触发, 希望帮助大家能举一反三.
源码 :
https://github.com/any86/6h/b...
最终目标
// 开始监听
const cancel = clickOutside(el, e=>{
// 点击el外部触发
});
// 取消监听
cancel();
原理
- 监听
document
的touchend
和click
事件. - 在事件回调中判断
event.target
(当前触发事件的元素)是否在"目标元素"内
代码详解请看代码注释.
实现代码
代码基于ts实现, 🤖不过只要会js就能看懂.
const eventNames = ['click', 'touchend'];
export default function (el: Node, callback: (ev:Event) => void) {
let isTouch = false;
function handler(ev: Event): void {
// touchend
if (eventNames[1] === ev.type) isTouch = true;
// 禁止移动端touchend触发后还触发click
if (eventNames[0] === ev.type && isTouch) return;
// 判断点击元素是否在el外
// 由于ev.target的类型是EventTarget,
// 而contains方法标注的参数类型是Node,
// 实际上EventTarget也是dom元素,
// 所以此处使用需要类型断言, 标注为Node类型
if (!el.contains(ev.target as Node)) callback(ev);
}
eventNames.forEach(name => {
document.addEventListener(name, handler);
});
return () => {
eventNames.forEach(name => {
document.removeEventListener(name, handler);
});
}
}
扩展
说个"锦上添花"的功能, 其实我们可以借助new Event()
模拟实现原生事件click-outside
, 这样我们可以在🤖vue中这么用:
<div @click-outside="onCall"></div>
此处的逻辑也很简单, 不展开讲解, 如有需要请看我之前发的文章: https://juejin.im/post/5e5f32...
计划(6h仓库)
工作中只要发现可复用的"短代码", 尽量保证代体积在1kb以内, 我都会用typescript封装成函数方便大家学习, 现已增加了2例:
@6h/be-full
任意元素全屏显示, 支持PC/移动端, 不到1kb.
@6h/click-outside
点击指点元素外部触发回调, 支持手机/桌面端.
🔥typescript系列课程
基础教程从这里开始
特别篇, 在vue3🔥源码中学会typescript🦕 - "is"
第六课, 什么是声明文件(declare)? 🦕 - 全局声明篇
新手前端学🔥typescript - 实战篇, 实现浏览器全屏(59行)
🔥往期热门文章
真.1px边框, 🚀 支持任意数量边和圆角, 1 个万金油的方法
微博
刚玩微博, 咱们可以互相关注, 嘿嘿
微信群
感谢大家的阅读, 如有疑问可以加我微信, 我拉你进入微信群(由于腾讯对微信群的100人限制, 超过100人后必须由群成员拉入)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。