[Vue] 如何利用intersectionOberver实现全
2019-05-07 本文已影响33人
DeepKolos
期望的使用方式
<template>
<div @appear="onAppear" @disappear="onDisappear">box</div>
</template>
<script>
export default {
methods: {
onAppear() { console.log('onAppear') },
onDisappear() { console.log('onDisappear') }
}
}
</script>
那么就需要让如下操作生效
el.addEventListener('appear', callback)
el.addEventListener('disappear', callback)
el.removeEventListener('appear', callback)
el.removeEventListener('disappear', callback)
那么问题来, intersectionOberver
是作为appear
, disappear
事件的触发者, 就需要Hook addEventListener
和removeEventListener
做一些注册工作了.
extend(EventTarget.prototype, 'addEventListener', function(eventName) {
let node = this;
let ioContext = node.__IO__;
if (eventName === 'appear' || eventName === 'disappear') {
// 一个节点需要一个 io 即可
if (node.__IO__) {
ioContext.listenerNum++;
return;
}
let io = new IntersectionObserver(entries => {
const ioContext = node.__IO__;
const { visible: lastVisible } = ioContext;
const entry = entries[entries.length - 1];
const ratio = entry.intersectionRatio;
const visible = entry.isIntersecting && ratio >= 0;
if (lastVisible === undefined) {
ioContext.visible = visible;
} else if (visible !== lastVisible) {
ioContext.visible = visible;
node.dispatchEvent(
new CustomEvent(visible ? 'appear' : 'disappear', {
bubbles: false // appear/disappear是节点相关的事件不能冒泡
})
);
}
});
node.__IO__ = {
instance: io,
listenerNum: 1
};
io.observe(node);
}
});
extend(EventTarget.prototype, 'removeEventListener', function(eventName) {
let node = this;
let ioContext = node.__IO__;
if (eventName === 'appear' || eventName === 'disappear') {
// 当事件为没有监听器的时候就可以把 io 注销, 释放内存
if (--ioContext.listenerNum === 0) {
ioContext.instance.disconnect();
ioContext.instance = null;
node.__IO__ = null;
}
}
});
function extend(obj, fnName, cb) {
const oldFn = obj[fnName];
obj[fnName] = function wrap() {
let ret;
oldFn && (ret = oldFn.apply(this, arguments));
cb && cb.apply(this, arguments);
return ret;
};
}
实际效果如下:
appear,disappear.gif