-
Notifications
You must be signed in to change notification settings - Fork 367
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
84 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(''); | ||
} | ||
}; |