node.contains(otherNode)
--------------------------
This function checks to see if an element is in the page's body. As contains is inclusive and determining if the body contains itself isn't the intention of isInPage this case explicitly returns false.
解绑时只要删掉nodeList中对应的那个节点,如果移除整个事件,会影响其他组件
所以我的指令就是下面这样:
var nodeList = [];
var ctx = '@@clickoutside';
var seed = 0;
var cb = (e) => {
var length = nodeList.length;
var target = e.target;
for (var i = 0; i < length; i++) {
if (!nodeList[i].contains(target)) {
nodeList[i][ctx].handler();
}
}
}
document.addEventListener('mouseup', cb);
export default {
bind(el, binding, vnode) {
nodeList.push(el);
el[ctx] = {
id: seed++,
handler: function() {
// 注意通过vnode.context取到我们的cb
vnode.context[binding.expression]();
}
}
},
unbind(el) {
// 注意这里不能直接removeEventListener这样会影响同一个页面上的同名组件的使用了
var len = nodeList.length;
for (var i = 0; i < len; i++) {
if (nodeList[i][ctx].id === el[ctx].id) {
nodeList.splice(i, 1);
break;
}
}
delete el[ctx];
}
}
背景
我有一个input和一个panel板子,在做这个组件的过程中,我卡在了当我鼠标点击板子以外的区域,板子要收起来这个步骤上。
遇到的问题
原先想法: 原本就是监听document.body的mouseclick事件,target不是我的文本框就收起来(如何判断是不是我特定文本框,我用的是样式判断)这就会导致多个相同组件会同时触发这个回调,这显然不正确,后来又想说再加个唯一标识区分,但总觉得怪怪的,于是看了一下element-ui的实现。
参考element-ui 的v-clickoutside
我发现element-ui 中有很多组件都会有这种功能,然后我找了一个date-picker组件看了下。发现它实现了一个clickoutside的指令,然后就深入看了一下
1.为什么用指令而没有直接写一个绑定函数
参考了使用Vue Directive封装DOM操作这篇文章,我觉得讲的很好,为什么要使用directive呢?
我个人觉得,最明显的优势在于vue指令中提供的钩子是与组件的生命周期关联的,利于我们绑定事件,销毁事件。
2.指令基础
探究clickouside 指令
element-ui 中这个可能考虑的事件比较多,写的偏复杂了一点,我就抽下大致的思路,然后写一个我要的
所以我的指令就是下面这样:
参考资料
1.使用Vue Directive封装DOM操作 https://elegenthus.github.io/post/VueDirectivesTest/ 2.Vue:指令(directive)简介 https://axiu.me/coding/vue-directive/ 3.Vue.js 指令 http://imweb.io/topic/570a12a906f2400432c139aa