搬运自:https://juejin.im/post/5cd10959f265da03a00fe5c6
效果:
demo地址: https://codepen.io/deepkolos/pen/OYPNNv?editors=1011
vue:
<template> <div @appear="onAppear" @disappear="onDisappear">box</div> </template> <script> export default { methods: { onAppear() { console.log('onAppear') }, onDisappear() { console.log('onDisappear') } } } </script>
js:
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; }; }