-
-
Notifications
You must be signed in to change notification settings - Fork 147
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(ui/layer): better layer implements and independence (#662)
- Loading branch information
Showing
9 changed files
with
241 additions
and
229 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
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,4 +1,4 @@ | ||
import Layer, { getLayerWrap } from './layer' | ||
|
||
export default Layer | ||
export { getLayerWrap } | ||
export * from './layer' | ||
export * from './wrap' | ||
export * from './scrollbar-helper' | ||
export * from './layer-manager' |
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 |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import type { ContextApi } from '~/types' | ||
import { getScrollbarHelper } from './scrollbar-helper' | ||
import { LayerWrap } from './wrap' | ||
import { Layer } from './layer' | ||
|
||
export class LayerManager { | ||
private wrap: LayerWrap | ||
private ctx: ContextApi | ||
|
||
constructor(ctx: ContextApi) { | ||
this.ctx = ctx | ||
|
||
this.wrap = new LayerWrap() | ||
document.body.appendChild(this.wrap.getWrap()) | ||
|
||
ctx.on('destroy', () => { | ||
this.wrap.getWrap().remove() | ||
}) | ||
|
||
// 记录页面原始 CSS 属性 | ||
getScrollbarHelper().init() | ||
} | ||
|
||
getEl() { | ||
return this.wrap.getWrap() | ||
} | ||
|
||
create(name: string, el?: HTMLElement | undefined) { | ||
const layer = new Layer(this.wrap, name, el) | ||
return layer | ||
} | ||
} |
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,161 +1,39 @@ | ||
import * as Utils from '../lib/utils' | ||
import * as Ui from '../lib/ui' | ||
import type { LayerWrap } from './wrap' | ||
|
||
export default class Layer { | ||
export class Layer { | ||
private $el: HTMLElement | ||
private wrap: LayerWrap | ||
private onAfterHide?: () => void | ||
|
||
private name: string | ||
private $wrap: HTMLElement | ||
private $mask: HTMLElement | ||
|
||
private maskClickHideEnable: boolean = true | ||
|
||
public static BodyOrgOverflow: string | ||
public static BodyOrgPaddingRight: string | ||
|
||
public afterHide?: Function | ||
|
||
constructor(name: string, el?: HTMLElement) { | ||
this.name = name | ||
const { $wrap, $mask } = getLayerWrap() | ||
this.$wrap = $wrap | ||
this.$mask = $mask | ||
|
||
this.$el = this.$wrap.querySelector(`[data-layer-name="${name}"].atk-layer-item`)! | ||
if (this.$el === null) { | ||
// 若传递 layer 元素为空 | ||
if (!el) { | ||
this.$el = Utils.createElement() | ||
this.$el.classList.add('atk-layer-item') | ||
} else { | ||
this.$el = el | ||
} | ||
} | ||
this.$el.setAttribute('data-layer-name', name) | ||
this.$el.style.display = 'none' | ||
|
||
// 添加到 layers wrap 中 | ||
this.$wrap.append(this.$el) | ||
} | ||
|
||
getName() { | ||
return this.name | ||
constructor(wrap: LayerWrap, name: string, el?: HTMLElement) { | ||
this.wrap = wrap | ||
this.$el = this.wrap.createItem(name, el) | ||
} | ||
|
||
getWrapEl() { | ||
return this.$wrap | ||
setOnAfterHide(func: () => void) { | ||
this.onAfterHide = func | ||
} | ||
|
||
getEl() { | ||
return this.$el | ||
} | ||
|
||
show() { | ||
this.fireAllActionTimer() | ||
|
||
this.$wrap.style.display = 'block' | ||
this.$mask.style.display = 'block' | ||
this.$mask.classList.add('atk-fade-in') | ||
this.$el.style.display = '' | ||
|
||
this.$mask.onclick = () => { | ||
if (this.maskClickHideEnable) this.hide() | ||
} | ||
|
||
// body style 禁止滚动 + 防抖 | ||
this.pageBodyScrollBarHide() | ||
this.wrap.show() | ||
} | ||
|
||
hide() { | ||
if (this.afterHide) this.afterHide() | ||
this.$wrap.classList.add('atk-fade-out') | ||
this.$el.style.display = 'none' | ||
|
||
// body style 禁止滚动解除 | ||
this.pageBodyScrollBarShow() | ||
|
||
this.newActionTimer(() => { | ||
this.$wrap.style.display = 'none' | ||
this.checkCleanLayer() | ||
}, 450) | ||
this.newActionTimer(() => { | ||
this.$wrap.style.display = 'none' | ||
this.$wrap.classList.remove('atk-fade-out') | ||
}, 200) | ||
} | ||
|
||
setMaskClickHide(enable: boolean) { | ||
this.maskClickHideEnable = enable | ||
} | ||
|
||
// 页面滚动条隐藏 | ||
pageBodyScrollBarHide() { | ||
document.body.style.overflow = 'hidden' | ||
|
||
const bpr = parseInt(window.getComputedStyle(document.body, null).getPropertyValue('padding-right'), 10) | ||
document.body.style.paddingRight = `${Ui.getScrollBarWidth() + bpr || 0}px` | ||
} | ||
|
||
// 页面滚动条显示 | ||
pageBodyScrollBarShow() { | ||
document.body.style.overflow = Layer.BodyOrgOverflow | ||
document.body.style.paddingRight = Layer.BodyOrgPaddingRight | ||
} | ||
|
||
// Timers | ||
private static actionTimers: {act: Function, tid: number}[] = [] | ||
|
||
private newActionTimer(func: Function, delay: number) { | ||
const act = () => { | ||
func() // 执行 | ||
Layer.actionTimers = Layer.actionTimers.filter(o => o.act !== act) // 删除 | ||
} | ||
|
||
const tid = window.setTimeout(() => act(), delay) | ||
|
||
Layer.actionTimers.push({ act, tid }) | ||
} | ||
|
||
private fireAllActionTimer() { | ||
Layer.actionTimers.forEach(item => { | ||
clearTimeout(item.tid) | ||
item.act() // 立即执行 | ||
this.wrap.hide(() => { | ||
this.$el.style.display = 'none' | ||
this.onAfterHide && this.onAfterHide() | ||
}) | ||
} | ||
|
||
/** 销毁 - 无动画 */ | ||
disposeNow() { | ||
this.$el.remove() | ||
this.pageBodyScrollBarShow() | ||
// this.$el dispose | ||
this.checkCleanLayer() | ||
} | ||
|
||
/** 销毁 */ | ||
dispose() { | ||
this.hide() | ||
this.$el.remove() | ||
// this.$el dispose | ||
this.checkCleanLayer() | ||
} | ||
|
||
checkCleanLayer() { | ||
if (this.getWrapEl().querySelectorAll('.atk-layer-item').length === 0) { | ||
this.$wrap.style.display = 'none' | ||
} | ||
} | ||
} | ||
|
||
export function getLayerWrap(): { $wrap: HTMLElement, $mask: HTMLElement } { | ||
let $wrap = document.querySelector<HTMLElement>(`.atk-layer-wrap`) | ||
if (!$wrap) { | ||
$wrap = Utils.createElement( | ||
`<div class="atk-layer-wrap" style="display: none;"><div class="atk-layer-mask"></div></div>` | ||
) | ||
document.body.appendChild($wrap) | ||
destroy() { | ||
this.wrap.hide(() => { | ||
this.$el.remove() | ||
this.onAfterHide && this.onAfterHide() | ||
}) | ||
} | ||
|
||
const $mask = $wrap.querySelector<HTMLElement>('.atk-layer-mask')! | ||
|
||
return { $wrap, $mask } | ||
} |
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 |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import * as Ui from '@/lib/ui' | ||
|
||
let bodyOrgOverflow: string | ||
let bodyOrgPaddingRight: string | ||
|
||
export function getScrollbarHelper() { | ||
return { | ||
init() { | ||
bodyOrgOverflow = document.body.style.overflow | ||
bodyOrgPaddingRight = document.body.style.paddingRight | ||
}, | ||
|
||
unlock() { | ||
document.body.style.overflow = bodyOrgOverflow | ||
document.body.style.paddingRight = bodyOrgPaddingRight | ||
}, | ||
|
||
lock() { | ||
document.body.style.overflow = 'hidden' | ||
const barPaddingRight = parseInt(window.getComputedStyle(document.body, null).getPropertyValue('padding-right'), 10) | ||
document.body.style.paddingRight = `${Ui.getScrollBarWidth() + barPaddingRight || 0}px` | ||
} | ||
} | ||
} |
Oops, something went wrong.