Skip to content

Commit

Permalink
lockScreen 优化,支持计算滚动条宽度
Browse files Browse the repository at this point in the history
  • Loading branch information
zdhxiong committed Nov 15, 2023
1 parent b4d4abe commit 8540228
Showing 1 changed file with 84 additions and 14 deletions.
98 changes: 84 additions & 14 deletions packages/shared/src/helpers/scroll.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,108 @@
import { getDocument } from 'ssr-window';
import { $ } from '@mdui/jq/$.js';
import '@mdui/jq/methods/addClass.js';
import '@mdui/jq/methods/append.js';
import '@mdui/jq/methods/appendTo.js';
import '@mdui/jq/methods/css.js';
import '@mdui/jq/methods/remove.js';
import '@mdui/jq/methods/removeClass.js';
import '@mdui/jq/methods/width.js';
import { isUndefined } from '@mdui/jq/shared/helper.js';

const locks = new Set();
const CSS_CLASS = 'mdui-lock-screen';
// 缓存滚动条宽度
let scrollBarSizeCached: number;

/**
* 获取滚动条宽度
* @param fresh 是否重新计算
*/
export const getScrollBarSize = (fresh?: boolean): number => {
if (isUndefined(document)) {
return 0;
}

if (fresh || scrollBarSizeCached === undefined) {
const $inner = $('<div>').css({
width: '100%',
height: '200px',
});

const $outer = $('<div>')
.css({
position: 'absolute',
top: '0',
left: '0',
pointerEvents: 'none',
visibility: 'hidden',
width: '200px',
height: '150px',
overflow: 'hidden',
})
.append($inner)
.appendTo(document.body);

const widthContained = $inner[0].offsetWidth;
$outer.css('overflow', 'scroll');
let widthScroll = $inner[0].offsetWidth;

if (widthContained === widthScroll) {
widthScroll = $outer[0].clientWidth;
}

$outer.remove();

scrollBarSizeCached = widthContained - widthScroll;
}

return scrollBarSizeCached;
};

const lockMap = new WeakMap<
HTMLElement, // 被锁定的元素
Set<HTMLElement> // 触发锁定的元素
>();
const className = 'mdui-lock-screen';

/**
* 锁定指定元素,禁止滚动。对同一个元素多次调用此方法,只会锁定一次
* @param element
* @param source 由该元素触发锁定
* @param target 锁定该元素的滚动状态,默认为 body
*/
export const lockScreen = (
element: HTMLElement,
target?: HTMLElement,
): void => {
export const lockScreen = (source: HTMLElement, target?: HTMLElement): void => {
const document = getDocument();
locks.add(element);
$(target || document.body).addClass(CSS_CLASS);

target ??= document.body;

if (!lockMap.has(target)) {
lockMap.set(target, new Set());
}

const lock = lockMap.get(target)!;
lock.add(source);

$(target)
.addClass(className)
.css('width', `calc(100% - ${getScrollBarSize()}px)`);
};

/**
* 解除指定元素的滚动状态锁定。
* @param element
* @param source 由该元素触发锁定
* @param target 锁定该元素的滚动状态,默认为 body
*/
export const unlockScreen = (
element: HTMLElement,
source: HTMLElement,
target?: HTMLElement,
): void => {
const document = getDocument();
locks.delete(element);

if (locks.size === 0) {
$(target || document.body).removeClass(CSS_CLASS);
target ??= document.body;

const lock = lockMap.get(target)!;
lock.delete(source);

if (lock.size === 0) {
lockMap.delete(target);
$(target).removeClass(className).width('');
}
};

0 comments on commit 8540228

Please sign in to comment.