@better-scroll/scroll-bar
Version:
scrollbar is used to BetterScroll, which behaves like browser scrollbar
138 lines (125 loc) • 4.28 kB
text/typescript
import BScroll from '@better-scroll/core'
import Indicator, {
IndicatorOptions,
IndicatorDirection,
OffsetType,
} from './indicator'
import { extend } from '@better-scroll/shared-utils'
export type ScrollbarOptions = Partial<ScrollbarConfig> | true
export interface ScrollbarConfig {
fade: boolean
fadeInTime: number
fadeOutTime: number
interactive: boolean
customElements: HTMLElement[]
minSize: number
scrollbarTrackClickable: boolean
scrollbarTrackOffsetType: OffsetType
scrollbarTrackOffsetTime: number
}
declare module '@better-scroll/core' {
interface CustomOptions {
scrollbar?: ScrollbarOptions
}
}
export default class ScrollBar {
static pluginName = 'scrollbar'
options: ScrollbarConfig
indicators: Indicator[]
constructor(public scroll: BScroll) {
this.handleOptions()
this.createIndicators()
this.handleHooks()
}
private handleHooks() {
const scroll = this.scroll
scroll.hooks.on(scroll.hooks.eventTypes.destroy, () => {
for (let indicator of this.indicators) {
indicator.destroy()
}
})
}
private handleOptions() {
const userOptions = (this.scroll.options.scrollbar === true
? {}
: this.scroll.options.scrollbar) as Partial<ScrollbarConfig>
const defaultOptions: ScrollbarConfig = {
fade: true,
fadeInTime: 250,
fadeOutTime: 500,
interactive: false,
customElements: [],
minSize: 8,
scrollbarTrackClickable: false,
scrollbarTrackOffsetType: OffsetType.Step,
scrollbarTrackOffsetTime: 300,
}
this.options = extend(defaultOptions, userOptions)
}
private createIndicators() {
let indicatorOptions: IndicatorOptions
const scroll: BScroll = this.scroll
const indicators: Indicator[] = []
const scrollDirectionConfigKeys = ['scrollX', 'scrollY']
const indicatorDirections = [
IndicatorDirection.Horizontal,
IndicatorDirection.Vertical,
]
const customScrollbarEls = this.options.customElements
for (let i = 0; i < scrollDirectionConfigKeys.length; i++) {
const key = scrollDirectionConfigKeys[i]
// wanna scroll in specified direction
if (scroll.options[key]) {
const customElement = customScrollbarEls.shift()
const direction = indicatorDirections[i]
let isCustom = false
let scrollbarWrapper = customElement
? customElement
: this.createScrollbarElement(direction)
// internal scrollbar
if (scrollbarWrapper !== customElement) {
scroll.wrapper.appendChild(scrollbarWrapper)
} else {
// custom scrollbar passed by users
isCustom = true
}
indicatorOptions = {
wrapper: scrollbarWrapper,
direction,
...this.options,
isCustom,
}
indicators.push(new Indicator(scroll, indicatorOptions))
}
}
this.indicators = indicators
}
private createScrollbarElement(
direction: IndicatorDirection,
scrollbarTrackClickable = this.options.scrollbarTrackClickable
) {
let scrollbarWrapperEl: HTMLDivElement = document.createElement('div')
let scrollbarIndicatorEl: HTMLDivElement = document.createElement('div')
scrollbarWrapperEl.style.cssText =
'position:absolute;z-index:9999;overflow:hidden;'
scrollbarIndicatorEl.style.cssText =
'box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px;'
scrollbarIndicatorEl.className = 'bscroll-indicator'
if (direction === IndicatorDirection.Horizontal) {
scrollbarWrapperEl.style.cssText +=
'height:7px;left:2px;right:2px;bottom:0;'
scrollbarIndicatorEl.style.height = '100%'
scrollbarWrapperEl.className = 'bscroll-horizontal-scrollbar'
} else {
scrollbarWrapperEl.style.cssText +=
'width:7px;bottom:2px;top:2px;right:1px;'
scrollbarIndicatorEl.style.width = '100%'
scrollbarWrapperEl.className = 'bscroll-vertical-scrollbar'
}
if (!scrollbarTrackClickable) {
scrollbarWrapperEl.style.cssText += 'pointer-events:none;'
}
scrollbarWrapperEl.appendChild(scrollbarIndicatorEl)
return scrollbarWrapperEl
}
}