(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = global || self, global.LockBodyScroll = factory()); }(this, function () { 'use strict'; /** * 解决滚动穿透问题 */ var eventInit = false; var hasPassiveEvents = false; var selector = '.can-scroll'; var lockedList = new Set(); // 检测浏览器是否支持passive events if (typeof window !== 'undefined') { var passiveTestOptions = { get passive() { hasPassiveEvents = true; return undefined; }, }; try { window.addEventListener('testPassive', null, passiveTestOptions); // @ts-ignore window.removeEventListener('testPassive', null, passiveTestOptions); } catch (e) { } } var LockBodyScroll = /** @class */ (function () { function LockBodyScroll(opts) { if (opts === void 0) { opts = { selector: '.can-scroll' }; } if (opts.selector) { selector = opts.selector; } } LockBodyScroll.prototype.lock = function () { lockedList.add(this); if (!eventInit) { if (typeof window !== 'undefined' && window.document) { // 阻止整个document的滚动 document.addEventListener('touchmove', LockBodyScroll.preventDefault, hasPassiveEvents ? { passive: false } : undefined); eventInit = true; this.lockScrollOverflow(); // 对于可滚动元素,限制它的超出范围滚动 } } }; /** * 对于所有可滚动元素,需要限制它的滚动范围不能超出容器,否则还会触发滚动穿透 */ LockBodyScroll.prototype.lockScrollOverflow = function () { var scrollEl = document.querySelectorAll(selector); [].forEach.call(scrollEl, function (el) { var initialY = 0; el.ontouchstart = function (e) { if (e.targetTouches.length === 1) { // 单点滑动 initialY = e.targetTouches[0].clientY; } }; el.ontouchmove = function (e) { if (e.targetTouches.length === 1) { // 单点滑动 var clientY = e.targetTouches[0].clientY - initialY; if (el.scrollHeight - 1 - el.scrollTop <= el.clientHeight && clientY < 0) { // 向下滑至底部 return e.preventDefault(); } if (el.scrollTop === 0 && clientY > 0) { // 向上滑至顶部 return e.preventDefault(); } } }; }); }; LockBodyScroll.prototype.unlock = function () { lockedList.delete(this); if (lockedList.size <= 0) { this.destroy(); } }; LockBodyScroll.prototype.destroy = function () { if (typeof window !== 'undefined' && window.document) { document.removeEventListener('touchmove', LockBodyScroll.preventDefault, // @ts-ignore hasPassiveEvents ? { passive: false } : undefined); } var scrollEl = document.querySelectorAll(selector); [].forEach.call(scrollEl, function (el) { el.ontouchstart = null; el.ontouchmove = null; }); eventInit = false; }; LockBodyScroll.preventDefault = function (e) { var scrollEl = document.querySelectorAll(selector); var isContain = [].some.call(scrollEl, function (el) { return el.contains(e.target); }); if (isContain) { return true; } e.preventDefault(); }; return LockBodyScroll; }()); return LockBodyScroll; }));