Skip to content

Commit

Permalink
Merge pull request ustbhuangyi#1078 from ustbhuangyi/fix-movable
Browse files Browse the repository at this point in the history
Fix movable
  • Loading branch information
theniceangel authored Sep 20, 2020
2 parents 0ffe17a + c921f55 commit 52c0c08
Show file tree
Hide file tree
Showing 90 changed files with 1,885 additions and 534 deletions.
70 changes: 50 additions & 20 deletions packages/core/src/BScroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
EventEmitter,
} from '@better-scroll/shared-utils'
import { bubbling } from './utils/bubbling'
import { UnionToIntersection } from './utils/typesHelper'

interface PluginCtor {
pluginName: string
Expand Down Expand Up @@ -43,7 +44,8 @@ export class BScrollConstructor<O = {}> extends EventEmitter {
options: OptionsConstructor
hooks: EventEmitter
plugins: { [name: string]: any }
wrapper: HTMLElement;
wrapper: HTMLElement
content: HTMLElement;
[key: string]: any

static use(ctor: PluginCtor) {
Expand Down Expand Up @@ -76,6 +78,7 @@ export class BScrollConstructor<O = {}> extends EventEmitter {
constructor(el: ElementParam, options?: Options & O) {
super([
'refresh',
'contentChanged',
'enable',
'disable',
'beforeScrollStart',
Expand All @@ -94,29 +97,54 @@ export class BScrollConstructor<O = {}> extends EventEmitter {
warn('Can not resolve the wrapper DOM.')
return
}
const content = wrapper.children[0]
if (!content) {
warn('The wrapper need at least one child element to be scroller.')
return
}

this.plugins = {}
this.options = new OptionsConstructor().merge(options).process()

if (!this.setContent(wrapper).valid) {
return
}

this.hooks = new EventEmitter([
'refresh',
'enable',
'disable',
'destroy',
'beforeInitialScrollTo',
'contentChanged',
])
this.init(wrapper)
}

setContent(wrapper: MountedBScrollHTMLElement) {
let contentChanged = false
let valid = true
const content = wrapper.children[
this.options.specifiedIndexAsContent
] as HTMLElement
if (!content) {
warn(
'The wrapper need at least one child element to be content element to scroll.'
)
valid = false
} else {
contentChanged = this.content !== content
if (contentChanged) {
this.content = content
}
}
return {
valid,
contentChanged,
}
}

private init(wrapper: MountedBScrollHTMLElement) {
this.wrapper = wrapper

// mark wrapper to recognize bs instance by DOM attribute
wrapper.isBScrollContainer = true
this.scroller = new Scroller(wrapper, this.options)
this.scroller = new Scroller(wrapper, this.content, this.options)
this.scroller.hooks.on(this.scroller.hooks.eventTypes.resize, () => {
this.refresh()
})
Expand All @@ -129,7 +157,7 @@ export class BScrollConstructor<O = {}> extends EventEmitter {
this.applyPlugins()

// maybe boundary has changed, should refresh
this.refreshWithoutReset()
this.refreshWithoutReset(this.content)
const { startX, startY } = this.options
const position = {
x: startX,
Expand Down Expand Up @@ -191,10 +219,10 @@ export class BScrollConstructor<O = {}> extends EventEmitter {
])
}

private refreshWithoutReset() {
this.scroller.refresh()
this.hooks.trigger(this.hooks.eventTypes.refresh)
this.trigger(this.eventTypes.refresh)
private refreshWithoutReset(content: HTMLElement) {
this.scroller.refresh(content)
this.hooks.trigger(this.hooks.eventTypes.refresh, content)
this.trigger(this.eventTypes.refresh, content)
}

proxy(propertiesConfig: PropertyConfig[]) {
Expand All @@ -203,8 +231,16 @@ export class BScrollConstructor<O = {}> extends EventEmitter {
})
}
refresh() {
this.refreshWithoutReset()
this.scroller.resetPosition()
const { contentChanged, valid } = this.setContent(this.wrapper)
if (valid) {
const content = this.content
this.refreshWithoutReset(content)
if (contentChanged) {
this.hooks.trigger(this.hooks.eventTypes.contentChanged, content)
this.trigger(this.eventTypes.contentChanged, content)
}
this.scroller.resetPosition()
}
}

enable() {
Expand Down Expand Up @@ -235,12 +271,6 @@ export interface CustomAPI {
[key: string]: {}
}

type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never

type ExtractAPI<O> = {
[K in keyof O]: K extends string
? DefOptions[K] extends undefined
Expand Down
63 changes: 39 additions & 24 deletions packages/core/src/Options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import {
hasTouch,
Probe,
EventPassthrough,
extend,
} from '@better-scroll/shared-utils'

// type
export type tap = 'tap' | ''
export type bounceOptions = Partial<BounceConfig> | boolean
export type dblclickOptions = Partial<DblclickConfig> | boolean
export type Tap = 'tap' | ''
export type BounceOptions = Partial<BounceConfig> | boolean
export type DblclickOptions = Partial<DblclickConfig> | boolean

// interface
export interface BounceConfig {
Expand All @@ -34,8 +36,8 @@ export interface DefOptions {
directionLockThreshold?: number
eventPassthrough?: string
click?: boolean
tap?: tap
bounce?: bounceOptions
tap?: Tap
bounce?: BounceOptions
bounceTime?: number
momentum?: boolean
momentumLimitTime?: number
Expand Down Expand Up @@ -65,9 +67,10 @@ export interface DefOptions {
disableTouch?: boolean
autoBlur?: boolean
translateZ?: string
dblclick?: dblclickOptions
dblclick?: DblclickOptions
autoEndDistance?: number
outOfBoundaryDampingFactor?: number
specifiedIndexAsContent?: number
}

export interface Options extends DefOptions, CustomOptions {}
Expand All @@ -82,8 +85,8 @@ export class OptionsConstructor extends CustomOptions implements DefOptions {
directionLockThreshold: number
eventPassthrough: string
click: boolean
tap: tap
bounce: bounceOptions
tap: Tap
bounce: BounceConfig
bounceTime: number
momentum: boolean
momentumLimitTime: number
Expand Down Expand Up @@ -113,9 +116,10 @@ export class OptionsConstructor extends CustomOptions implements DefOptions {
disableTouch: boolean
autoBlur: boolean
translateZ: string
dblclick: dblclickOptions
dblclick: DblclickOptions
autoEndDistance: number
outOfBoundaryDampingFactor: number
specifiedIndexAsContent: number

constructor() {
super()
Expand Down Expand Up @@ -173,10 +177,15 @@ export class OptionsConstructor extends CustomOptions implements DefOptions {

this.autoEndDistance = 5
this.outOfBoundaryDampingFactor = 1 / 3
this.specifiedIndexAsContent = 0
}
merge(options?: Options) {
if (!options) return this
for (let key in options) {
if (key === 'bounce') {
this.bounce = this.resolveBounce(options[key]!)
continue
}
this[key] = options[key]
}
return this
Expand All @@ -189,8 +198,6 @@ export class OptionsConstructor extends CustomOptions implements DefOptions {

this.preventDefault = !this.eventPassthrough && this.preventDefault

this.resolveBounce()

// If you want eventPassthrough I have to lock one of the axes
this.scrollX =
this.eventPassthrough === EventPassthrough.Horizontal
Expand All @@ -213,19 +220,27 @@ export class OptionsConstructor extends CustomOptions implements DefOptions {
return this
}

resolveBounce() {
const directions = ['top', 'right', 'bottom', 'left']
const bounce = this.bounce
if (typeof bounce === 'boolean') {
this.bounce = makeMap(directions, bounce)
resolveBounce(bounceOptions: BounceOptions): BounceConfig {
const DEFAULT_BOUNCE = {
top: true,
right: true,
bottom: true,
left: true,
}
const NEGATED_BOUNCE = {
top: false,
right: false,
bottom: false,
left: false,
}

let ret: BounceConfig
if (typeof bounceOptions === 'object') {
ret = extend(DEFAULT_BOUNCE, bounceOptions)
} else {
ret = bounceOptions ? DEFAULT_BOUNCE : NEGATED_BOUNCE
}
}
}

function makeMap(keys: string[], val: boolean = true) {
const ret: { [key: string]: boolean } = {}
keys.forEach((key) => {
ret[key] = val
})
return ret
return ret
}
}
62 changes: 5 additions & 57 deletions packages/core/src/__mocks__/Options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const mockOptions = jest.fn().mockImplementation(() => {
top: true,
bottom: true,
left: true,
right: true
right: true,
},
bounceTime: 800,

Expand All @@ -37,7 +37,7 @@ const mockOptions = jest.fn().mockImplementation(() => {
stopPropagation: false,
preventDefault: true,
preventDefaultException: {
tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|AUDIO)$/
tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|AUDIO)$/,
},

HWCompositing: true,
Expand All @@ -47,64 +47,12 @@ const mockOptions = jest.fn().mockImplementation(() => {
disableMouse: true,
observeDOM: true,
autoBlur: true,

// plugins config

/**
* for slide
* slide: {
* loop: false,
* el: domEl,
* threshold: 0.1,
* stepX: 100,
* stepY: 100,
* speed: 400,
* easing: {
* style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
* fn: function (t) {
* return t * (2 - t)
* }
* }
* listenFlick: true
* }
*/
// slide: false

/**
* for mouse wheel
* mouseWheel: {
* speed: 20,
* invert: false,
* easeTime: 300
* }
*/
mouseWheel: false,

/**
* for zoom
* zoom: {
* start: 1,
* min: 1,
* max: 4
* }
*/
// zoom: false

/**
* for infinity
* infinity: {
* render(item, div) {
* },
* createTombstone() {
* },
* fetch(count) {
* }
* }
*/
infinity: false,

specifiedIndexAsContent: 0,
outOfBoundaryDampingFactor: 1 / 3,
merge: jest.fn(),
process: jest.fn()
process: jest.fn(),
}
})

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/__mocks__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const BScroll = jest.fn().mockImplementation((wrapper, options) => {
'destroy',
'beforeInitialScrollTo',
]),
scroller: new Scroller(wrapper, options),
scroller: new Scroller(wrapper, wrapper.children[0], options),
// own methods
proxy: jest.fn(),
refresh: jest.fn(),
Expand Down
Loading

0 comments on commit 52c0c08

Please sign in to comment.