Skip to content

Commit

Permalink
fix(cdk:scroll): update scroll blocked style
Browse files Browse the repository at this point in the history
fix #586
  • Loading branch information
danranVm committed Dec 23, 2021
1 parent efbfda1 commit 3ea4fdb
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 60 deletions.
84 changes: 48 additions & 36 deletions packages/cdk/scroll/src/strategy/blockScrollStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import { addClass, convertCssPixel, removeClass } from '@idux/cdk/utils'
import { addClass, removeClass } from '@idux/cdk/utils'

import { getScroll, setScroll } from '../utils'
import { getScrollBarSize } from '../utils'
import { ScrollStrategy } from './scrollStrategy'

export interface BlockScrollStrategyOptions {
Expand All @@ -17,13 +17,8 @@ export interface BlockScrollStrategyOptions {

const defaultClassName = 'cdk-scroll-block'

interface CacheStrategy extends BlockScrollStrategyOptions {
uid: number
cacheScroll: { scrollTop: number; scrollLeft: number }
cacheStyle: { top: string; left: string }
}

let cacheStrategy: CacheStrategy[] = []
const cacheStrategy = new Map<number, BlockScrollStrategyOptions>()
const cacheStyle = new Map<HTMLElement, { width: string; overflow: string; overflowX: string; overflowY: string }>()

let uuid = 0

Expand All @@ -44,58 +39,65 @@ export class BlockScrollStrategy implements ScrollStrategy {

/** Blocks scroll while the attached overlay is open. */
enable(): void {
const { uid, target, className } = this
if (cacheStrategy.some(item => item.uid === uid)) {
if (!this.isScrolled()) {
return
}

let cacheScroll: { scrollTop: number; scrollLeft: number }
let cacheStyle: { top: string; left: string }

const sameTargetTarget = cacheStrategy.find(item => item.target === target)
if (!sameTargetTarget) {
cacheScroll = getScroll(target)
cacheStyle = { top: target.style.top, left: target.style.left }
} else {
cacheScroll = sameTargetTarget.cacheScroll
cacheStyle = sameTargetTarget.cacheStyle
const { uid, target, className } = this
if (cacheStrategy.has(uid)) {
return
}
cacheStrategy.push({ uid, target, className, cacheScroll, cacheStyle })

if (!target.classList.contains(className) && this.isScrolled()) {
target.style.top = convertCssPixel(-cacheScroll.scrollTop)
target.style.left = convertCssPixel(-cacheScroll.scrollLeft)

addClass(target, className)
if (!Array.from(cacheStrategy.values()).some(item => item.target === target)) {
const scrollBarSize = getScrollBarSize(target === document.documentElement ? undefined : target)
cacheStyle.set(target, {
width: target.style.width,
overflow: target.style.overflow,
overflowX: target.style.overflowX,
overflowY: target.style.overflowY,
})

target.style.width = scrollBarSize !== 0 ? `calc(100% - ${scrollBarSize}px)` : ''
target.style.overflow = 'hidden'
target.style.overflowX = 'hidden'
target.style.overflowY = 'hidden'
}

this.addClassName()
cacheStrategy.set(uid, { target, className })
}

/** Unblocks scroll while the attached overlay is open. */
disable(): void {
const { uid, target, className } = this
const currStrategy = cacheStrategy.find(item => item.uid === uid)
const currStrategy = cacheStrategy.get(uid)
if (!currStrategy) {
return
}

cacheStrategy = cacheStrategy.filter(item => item.uid !== uid)
cacheStrategy.delete(uid)

if (!cacheStrategy.some(item => item.target === target && item.className === className)) {
const strategyArray = Array.from(cacheStrategy.values())
if (!strategyArray.some(item => item.target === target && item.className === className)) {
removeClass(target, className)
}

if (!cacheStrategy.some(item => item.target === target)) {
target.style.top = currStrategy.cacheStyle.top
target.style.left = currStrategy.cacheStyle.left
if (!strategyArray.some(item => item.target === target)) {
const style = cacheStyle.get(target)!

setScroll(currStrategy.cacheScroll, target)
target.style.width = style.width
target.style.overflow = style.overflow
target.style.overflowX = style.overflowX
target.style.overflowY = style.overflowY

cacheStyle.delete(target)
}
}

/** Re-lock scroll while the options change. */
update(options: BlockScrollStrategyOptions): void {
const { uid, target, className } = this
const currStrategy = cacheStrategy.find(item => item.uid === uid)
const currStrategy = cacheStrategy.get(uid)

if (currStrategy) {
this.disable()
Expand All @@ -114,6 +116,16 @@ export class BlockScrollStrategy implements ScrollStrategy {
private isScrolled(): boolean {
const { target } = this

return target.scrollHeight > target.clientHeight
return (
(target === document.documentElement && document.body.scrollWidth > window.innerWidth) ||
target.scrollHeight > target.clientHeight
)
}

private addClassName(): void {
const { target, className } = this
if (!target.classList.contains(className)) {
addClass(target, className)
}
}
}
24 changes: 0 additions & 24 deletions packages/components/style/core/default.less
Original file line number Diff line number Diff line change
@@ -1,26 +1,2 @@
@import '../themes/default.less';
@import './reset.less';

// Used when disabling global scrolling.
.@{cdk-prefix} {

&-scroll-block {
position: fixed;

// Necessary for the content not to lose its width. Note that we're using 100%, instead of
// 100vw, because 100vw includes the width plus the scrollbar, whereas 100% is the width
// that the element had before we made it `fixed`.
width: 100%;

// Note: this will always add a scrollbar to whatever element it is on, which can
// potentially result in double scrollbars. It shouldn't be an issue, because we won't
// block scrolling on a page that doesn't have a scrollbar in the first place.
overflow-y: scroll;

// https://github.com/angular/material2/issues/15051

body {
overflow-x: visible;
}
}
}

0 comments on commit 3ea4fdb

Please sign in to comment.