Skip to content

Commit

Permalink
Merge pull request ustbhuangyi#1091 from ustbhuangyi/fix-slide-willch…
Browse files Browse the repository at this point in the history
…ange

Fix slide willchange
  • Loading branch information
theniceangel authored Oct 20, 2020
2 parents e554b02 + 661aa83 commit 2fffc60
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 117 deletions.
4 changes: 2 additions & 2 deletions packages/examples/vue/components/slide/banner.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
momentum: false,
bounce: false,
stopPropagation: true,
probeType: 2
probeType: 3
})
this.slide.on('scrollEnd', this._onScrollEnd)
Expand All @@ -59,7 +59,7 @@
})
},
_onScrollEnd () {
console.log(this.slide.getCurrentPage())
console.log('CurrentPage => ', this.slide.getCurrentPage())
},
nextPage() {
this.slide.next()
Expand Down
39 changes: 21 additions & 18 deletions packages/slide/src/SlidePages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default class SlidePages {
refresh() {
this.pagesMatrix = new PagesMatrix(this.scroll)
const { pageX, pageY } = this.currentPage
// when refresh or resize, currenpage.(x|y) need recaculate
// when refresh or resize, currentPage.(x|y) need recaculate
const { x, y } = this.pagesMatrix.getPageStats(pageX, pageY)
this.currentPage = { pageX, pageY, x, y }
this.checkSlideLoop()
Expand Down Expand Up @@ -176,33 +176,36 @@ export default class SlidePages {
return this.getPageIndexByDirection(Direction.Negative)
}

nearestPage(
x: number,
y: number,
directionX: number,
directionY: number
): Page {
getNearestPage(x: number, y: number): Page {
const pageIndex = this.pagesMatrix.getNearestPageIndex(x, y)

let { pageX, pageY } = pageIndex
let newX
let newY

let newX = this.pagesMatrix.getPageStats(pageX, 0).x
let newY = this.pagesMatrix.getPageStats(0, pageY).y

return {
x: newX,
y: newY,
pageX,
pageY,
}
}

getPageByDirection(page: Page, directionX: number, directionY: number): Page {
let { pageX, pageY } = page
if (pageX === this.currentPage.pageX) {
pageX += directionX
pageX = between(pageX, 0, this.pagesMatrix.pageLengthOfX - 1)
pageX = between(pageX + directionX, 0, this.pagesMatrix.pageLengthOfX - 1)
}
if (pageY === this.currentPage.pageY) {
pageY += directionY
pageY = between(pageY, 0, this.pagesMatrix.pageLengthOfY - 1)
pageY = between(pageY + directionY, 0, this.pagesMatrix.pageLengthOfY - 1)
}

newX = this.pagesMatrix.getPageStats(pageX, 0).x
newY = this.pagesMatrix.getPageStats(0, pageY).y
const x = this.pagesMatrix.getPageStats(pageX, 0).x
const y = this.pagesMatrix.getPageStats(0, pageY).y

return {
x: newX,
y: newY,
x,
y,
pageX,
pageY,
}
Expand Down
10 changes: 9 additions & 1 deletion packages/slide/src/__mocks__/SlidePages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const SlidePage = jest.fn().mockImplementation(() => {
pageY: 0,
}
}),
nearestPage: jest.fn().mockImplementation(() => {
getNearestPage: jest.fn().mockImplementation(() => {
return {
pageX: 0,
pageY: 0,
Expand All @@ -66,6 +66,14 @@ const SlidePage = jest.fn().mockImplementation(() => {
}),
resetLoopPage: jest.fn(),
getPageIndexByDirection: jest.fn(),
getPageByDirection: jest.fn().mockImplementation(() => {
return {
pageX: 0,
pageY: 0,
x: 0,
y: 0,
}
}),
}
})

Expand Down
4 changes: 2 additions & 2 deletions packages/slide/src/__tests__/SlidePages.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,8 @@ describe('slide test for SlidePages class', () => {
})
})

it('should work well with nearestPage()', () => {
const pageIndex = slidePages.nearestPage(0, 0, 1, 1)
it('should work well with getNearestPage()', () => {
const pageIndex = slidePages.getNearestPage(30, 0)

expect(pageIndex).toMatchObject({
pageX: 1,
Expand Down
60 changes: 10 additions & 50 deletions packages/slide/src/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ describe('slide test for SlidePage class', () => {
it('should call modifyCurrentPage() when BScroll trigger scrollEnd hook', () => {
const spyFn = jest.spyOn(Slide.prototype, 'startPlay')
slide = new Slide(scroll)
scroll.trigger(scroll.eventTypes.scrollEnd)
scroll.trigger(scroll.eventTypes.scrollEnd, { x: 0, y: 0 })
expect(spyFn).toBeCalled()
})

Expand Down Expand Up @@ -179,12 +179,6 @@ describe('slide test for SlidePage class', () => {

expect(slide.pages.refresh).toBeCalled()
expect(slide.pages.getInitialPage).toBeCalled()
expect(slide.pages.setCurrentPage).toBeCalledWith({
pageX: 0,
pageY: 0,
x: 10,
y: 10,
})
expect(position).toMatchObject({
x: 10,
y: 10,
Expand All @@ -208,51 +202,17 @@ describe('slide test for SlidePage class', () => {
expect(scrollMeta.newY).toBe(0)
expect(scrollMeta.time).toBe(400)

expect(slide.pages.setCurrentPage).toBeCalledWith({
x: 0,
y: 0,
pageX: 0,
pageY: 0,
})

expect(slide.pages.getWillChangedPage).toBeCalledWith({
x: 0,
y: 0,
pageX: 0,
pageY: 0,
})
})

it('should call setTouchFlag when scroller.hooks.scroll triggered', () => {
const position = {
x: 0,
y: 0,
}
scroll.scroller.hooks.trigger(
scroll.scroller.hooks.eventTypes.scroll,
position
expect(slide.pages.getPageByDirection).toBeCalledWith(
{
x: 0,
y: 0,
pageX: 0,
pageY: 0,
},
0,
0
)

expect(slide.pages.getWillChangedPage).not.toBeCalled()

const scrollMeta = {
newX: -1,
newY: -1,
time: 0,
}
// set isTouching = true
scroll.scroller.hooks.trigger(
scroll.scroller.hooks.eventTypes.momentum,
scrollMeta
)
scroll.scroller.hooks.trigger(
scroll.scroller.hooks.eventTypes.scroll,
position
)

expect(slide.pages.getWillChangedPage).toBeCalled()
})

it('should start a new autoPlay timer when scroller.hooks.checkClick triggered', () => {
const spyFn = jest.spyOn(Slide.prototype, 'startPlay')
slide = new Slide(scroll)
Expand Down
80 changes: 38 additions & 42 deletions packages/slide/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ export default class Slide implements PluginAPI {
private thresholdY: number
private hooksFn: Array<[EventEmitter, string, Function]>
private resetLooping = false
private isTouching = false
private willChangeToPage: Page
private autoplayTimer: number = 0
private prevContent: HTMLElement
Expand Down Expand Up @@ -208,15 +207,10 @@ export default class Slide implements PluginAPI {
scrollerHooks.eventTypes.momentum,
this.modifyScrollMetaHandler
)
this.registerHooks(
scrollerHooks,
scrollerHooks.eventTypes.beforeStart,
this.setTouchFlag
)
this.registerHooks(
scrollerHooks,
scrollerHooks.eventTypes.scroll,
this.scrollMoving
this.scrollHandler
)
// a click operation will clearTimer, so restart a new one
this.registerHooks(
Expand Down Expand Up @@ -307,36 +301,34 @@ export default class Slide implements PluginAPI {
nearestPage(x: number, y: number): Page {
const { scrollBehaviorX, scrollBehaviorY } = this.scroll.scroller
const {
absStartPos: absStartPosX,
maxScrollPos: maxScrollPosX,
minScrollPos: minScrollPosX,
direction: directionX,
} = scrollBehaviorX
const {
absStartPos: absStartPosY,
maxScrollPos: maxScrollPosY,
minScrollPos: minScrollPosY,
direction: directionY,
} = scrollBehaviorY

let triggerThreshold = true
return this.pages.getNearestPage(
between(x, maxScrollPosX, minScrollPosX),
between(y, maxScrollPosY, minScrollPosY)
)
}

private satisfyThreshold(x: number, y: number): boolean {
const { scrollBehaviorX, scrollBehaviorY } = this.scroll.scroller

let satisfied = true
if (
Math.abs(x - absStartPosX) <= this.thresholdX &&
Math.abs(y - absStartPosY) <= this.thresholdY
Math.abs(x - scrollBehaviorX.absStartPos) <= this.thresholdX &&
Math.abs(y - scrollBehaviorY.absStartPos) <= this.thresholdY
) {
triggerThreshold = false
}
if (!triggerThreshold) {
return this.pages.currentPage
satisfied = false
}

return this.pages.nearestPage(
between(x, maxScrollPosX, minScrollPosX),
between(y, maxScrollPosY, minScrollPosY),
directionX,
directionY
)
return satisfied
}

private refreshHandler(content: HTMLElement) {
if (!this.satisfyInitialization()) {
return
Expand All @@ -362,7 +354,6 @@ export default class Slide implements PluginAPI {
this.initialised = true
position.x = initPage.x
position.y = initPage.y
this.pages.setCurrentPage(initPage)
}
)
}
Expand Down Expand Up @@ -409,11 +400,14 @@ export default class Slide implements PluginAPI {
}
}

private modifyCurrentPage() {
this.isTouching = false
if (!this.options.loop) {
private modifyCurrentPage(point: Position) {
// if in animation, and force stopping
if (this.scroll.scroller.animater.forceStopped) {
return
}
const newPage = this.nearestPage(point.x, point.y)
this.pages.setCurrentPage(newPage)
this.pageWillChangeTo(newPage)
// triggered by resetLoop
if (this.resetLooping) {
this.resetLooping = false
Expand All @@ -428,7 +422,6 @@ export default class Slide implements PluginAPI {
// since it is a seamless scroll
return true
}
this.pageWillChangeTo(this.pages.currentPage)
}

private goTo(pageX: number, pageY: number, time?: number, easing?: EaseItem) {
Expand All @@ -445,8 +438,6 @@ export default class Slide implements PluginAPI {
return
}
time = time === undefined ? this.getEaseTime(deltaX, deltaY) : time
this.pages.setCurrentPage(newPage)
this.pageWillChangeTo(this.pages.currentPage)
this.scroll.scroller.scrollTo(x, y, time, scrollEasing)
}

Expand Down Expand Up @@ -490,7 +481,18 @@ export default class Slide implements PluginAPI {
time: number
[key: string]: any
}) {
const newPage = this.nearestPage(scrollMeta.newX, scrollMeta.newY)
const { scrollBehaviorX, scrollBehaviorY, animater } = this.scroll.scroller
const newX = scrollMeta.newX
const newY = scrollMeta.newY

const newPage =
this.satisfyThreshold(newX, newY) || animater.forceStopped
? this.pages.getPageByDirection(
this.nearestPage(newX, newY),
scrollBehaviorX.direction,
scrollBehaviorY.direction
)
: this.pages.currentPage

scrollMeta.time = this.getEaseTime(
scrollMeta.newX - newPage.x,
Expand All @@ -499,14 +501,12 @@ export default class Slide implements PluginAPI {
scrollMeta.newX = newPage.x
scrollMeta.newY = newPage.y
scrollMeta.easing = this.options.easing || ease.bounce
this.pages.setCurrentPage(newPage)
this.pageWillChangeTo(this.pages.currentPage)
}

private scrollMoving(point: Position) {
if (this.isTouching) {
const newPos = this.nearestPage(point.x, point.y)
this.pageWillChangeTo(newPos)
private scrollHandler({ x, y }: Position) {
if (this.satisfyThreshold(x, y)) {
const newPage = this.nearestPage(x, y)
this.pageWillChangeTo(newPage)
}
}

Expand All @@ -521,10 +521,6 @@ export default class Slide implements PluginAPI {
}
}

private setTouchFlag() {
this.isTouching = true
}

private registerHooks(hooks: EventEmitter, name: string, handler: Function) {
hooks.on(name, handler, this)
this.hooksFn.push([hooks, name, handler])
Expand Down
2 changes: 1 addition & 1 deletion packages/vuepress-docs/docs/en-US/plugins/observe-dom.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@ yarn add @better-scroll/observe-dom
</demo>

:::warning
For version <= `2.0.4`, because the internal implementation of the plugin uses [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver), it cannot detect whether the load of the img tag is complete, so for images with uncertain heights inside the content, you need to wait for the image to load before calling `bs.refresh()` to recalculate the scrollable size. If the browser does not support MutationObserver, the fallback inside the plugin is to recalculate the scrollable size every second.
For version <= `2.0.5`, because the internal implementation of the plugin uses [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver), it cannot detect whether the load of the img tag is complete, so for images with uncertain heights inside the content, you need to wait for the image to load before calling `bs.refresh()` to recalculate the scrollable size. If the browser does not support MutationObserver, the fallback inside the plugin is to recalculate the scrollable size every second.
:::
2 changes: 1 addition & 1 deletion packages/vuepress-docs/docs/zh-CN/plugins/observe-dom.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,5 @@ yarn add @better-scroll/observe-dom


:::warning 注意
对于 `2.0.4` 版本及之前版本,由于插件的内部实现使用的是 [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver),它无法探测到 img 标签的是否加载完成,因此对于 content 内部含有不确定高度的图片,需要等图片加载完成再调用 bs.refresh() 来重新计算可滚动尺寸。如果浏览器不支持 MutationObserver,插件内部的降级方案是每秒重新计算可滚动的尺寸。
对于 `2.0.5` 版本及之前版本,由于插件的内部实现使用的是 [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver),它无法探测到 img 标签的是否加载完成,因此对于 content 内部含有不确定高度的图片,需要等图片加载完成再调用 bs.refresh() 来重新计算可滚动尺寸。如果浏览器不支持 MutationObserver,插件内部的降级方案是每秒重新计算可滚动的尺寸。
:::

0 comments on commit 2fffc60

Please sign in to comment.