diff --git a/packages/taro-components-react/package.json b/packages/taro-components-react/package.json index 4c8ea2c0f730..010cb2858201 100644 --- a/packages/taro-components-react/package.json +++ b/packages/taro-components-react/package.json @@ -30,7 +30,7 @@ "classnames": "^2.2.5", "intersection-observer": "^0.7.0", "resolve-pathname": "^3.0.0", - "swiper": "6.7.5", + "swiper": "6.8.0", "weui": "^1.1.2" } } diff --git a/packages/taro-components-react/src/components/swiper/index.tsx b/packages/taro-components-react/src/components/swiper/index.tsx index ba6376c95397..086fc6a91397 100644 --- a/packages/taro-components-react/src/components/swiper/index.tsx +++ b/packages/taro-components-react/src/components/swiper/index.tsx @@ -24,6 +24,7 @@ interface SwiperProps { duration?: number current?: number displayMultipleItems?: number + circular?: boolean vertical?: boolean spaceBetween?: any previousMargin?: string @@ -70,6 +71,9 @@ class Swiper extends React.Component> { _$height = 0 $el: HTMLDivElement | null mySwiper: ISwiper + observer: MutationObserver + observerFirst: MutationObserver + observerLast: MutationObserver componentDidMount () { const { @@ -132,13 +136,6 @@ class Swiper extends React.Component> { if (that.props.autoplay && target.contains(_swiper.$el[0])) { _swiper.slideTo(that._$current) } - } else if (className.includes('swiper-wrapper')) { - if (e.addedNodes.length > 0 || e.removedNodes.length > 0) { - // @ts-ignore - _swiper.loopDestroy() - // @ts-ignore - _swiper.loopCreate() - } } } } @@ -161,14 +158,22 @@ class Swiper extends React.Component> { setTimeout(() => { this.mySwiper.update() }, 500) + + if (!this.mySwiper || !this.props.circular) return + + const wrapper = this.mySwiper.$wrapperEl[0] + this.observer = new MutationObserver(this.handleSwiperLoopListen) + + this.observer.observe(wrapper, { + childList: true + }) } UNSAFE_componentWillReceiveProps (nextProps) { if (this.mySwiper) { const nextCurrent = typeof nextProps.current === 'number' ? nextProps.current : this._$current || 0 - ;(this.mySwiper as any).loopDestroy() - ;(this.mySwiper as any).loopCreate() + this.handleSwiperLoop() // 是否衔接滚动模式 if (nextProps.circular) { if (!this.mySwiper.isBeginning && !this.mySwiper.isEnd) { @@ -214,6 +219,9 @@ class Swiper extends React.Component> { componentWillUnmount () { this.$el = null if (this.mySwiper) this.mySwiper.destroy() + this.observer.disconnect && this.observer.disconnect() + this.observerFirst.disconnect && this.observerFirst.disconnect() + this.observerLast.disconnect && this.observerLast.disconnect() } handleOnChange (e: Event) { @@ -230,6 +238,33 @@ class Swiper extends React.Component> { return parseFloat(s.replace(/r*px/i, '')) } + handleSwiperLoopListen = () => { + this.observerFirst?.disconnect && this.observerFirst.disconnect() + this.observerLast?.disconnect && this.observerLast.disconnect() + this.observerFirst = new MutationObserver(this.handleSwiperLoop) + this.observerLast = new MutationObserver(this.handleSwiperLoop) + const wrapper = this.mySwiper.$wrapperEl[0] + const list = wrapper.querySelectorAll('taro-swiper-item-core:not(.swiper-slide-duplicate)') + if (list.length >= 1) { + this.observerFirst.observe(list[0], { + characterData: true + }) + } else if (list.length >= 2) { + this.observerLast.observe(list[list.length - 1], { + characterData: true + }) + } + } + + handleSwiperLoop = debounce(() => { + if (this.mySwiper && this.props.circular) { + // @ts-ignore + this.mySwiper.loopDestroy() + // @ts-ignore + this.mySwiper.loopCreate() + } + }, 500) + render () { const { className, @@ -277,3 +312,14 @@ class Swiper extends React.Component> { } export { Swiper, SwiperItem } + +function debounce (fn, delay: number) { + let timer: NodeJS.Timeout + + return function (...arrs) { + clearTimeout(timer) + timer = setTimeout(function () { + fn(...arrs) + }, delay) + } +} diff --git a/packages/taro-components/__tests__/utils.js b/packages/taro-components/__tests__/utils.js index 6c131c197783..f97ff67b8fcc 100644 --- a/packages/taro-components/__tests__/utils.js +++ b/packages/taro-components/__tests__/utils.js @@ -7,7 +7,7 @@ export function waitForChange (dom) { timer = setTimeout(() => { observer.disconnect() resolve() - }, 500) + }, 1000) }) setTimeout(() => { diff --git a/packages/taro-components/package.json b/packages/taro-components/package.json index cbbfc95cdaf2..db66a95fb36b 100644 --- a/packages/taro-components/package.json +++ b/packages/taro-components/package.json @@ -44,7 +44,7 @@ "intersection-observer": "^0.7.0", "omit.js": "^1.0.0", "resolve-pathname": "^3.0.0", - "swiper": "6.7.5", + "swiper": "6.8.0", "weui": "^1.1.2" }, "devDependencies": { diff --git a/packages/taro-components/src/components/swiper/swiper.tsx b/packages/taro-components/src/components/swiper/swiper.tsx index b67f256f6f8b..fa40ee10838b 100644 --- a/packages/taro-components/src/components/swiper/swiper.tsx +++ b/packages/taro-components/src/components/swiper/swiper.tsx @@ -169,12 +169,24 @@ export class Swiper implements ComponentInterface { } } + @State() observer: MutationObserver + @State() observerFirst: MutationObserver + @State() observerLast: MutationObserver + componentWillLoad () { this.isWillLoadCalled = true } componentDidLoad () { this.handleInit() + if (!this.swiper || !this.circular) return + + const wrapper = this.swiper.$wrapperEl[0] + this.observer = new MutationObserver(this.handleSwiperLoopListen) + + this.observer.observe(wrapper, { + childList: true + }) } componentWillUpdate () { @@ -186,12 +198,42 @@ export class Swiper implements ComponentInterface { } componentDidRender () { - if (this.swiper && this.circular) { - ;(this.swiper as any).loopDestroy() - ;(this.swiper as any).loopCreate() + this.handleSwiperLoop() + } + + disconnectedCallback () { + this.observer.disconnect && this.observer.disconnect() + this.observerFirst.disconnect && this.observerFirst.disconnect() + this.observerLast.disconnect && this.observerLast.disconnect() + } + + handleSwiperLoopListen = () => { + this.observerFirst?.disconnect && this.observerFirst.disconnect() + this.observerLast?.disconnect && this.observerLast.disconnect() + this.observerFirst = new MutationObserver(this.handleSwiperLoop) + this.observerLast = new MutationObserver(this.handleSwiperLoop) + const wrapper = this.swiper.$wrapperEl[0] + const list = wrapper.querySelectorAll('taro-swiper-item-core:not(.swiper-slide-duplicate)') + if (list.length >= 1) { + this.observerFirst.observe(list[0], { + characterData: true + }) + } else if (list.length >= 2) { + this.observerLast.observe(list[list.length - 1], { + characterData: true + }) } } + handleSwiperLoop = debounce(() => { + if (this.swiper && this.circular) { + // @ts-ignore + this.swiper.loopDestroy() + // @ts-ignore + this.swiper.loopCreate() + } + }, 500) + handleInit () { const { autoplay, @@ -239,13 +281,6 @@ export class Swiper implements ComponentInterface { if (that.autoplay && target.contains(_swiper.$el[0])) { _swiper.slideTo(that.current) } - } else if (className.includes('swiper-wrapper')) { - if (e.addedNodes.length > 0 || e.removedNodes.length > 0) { - // @ts-ignore - _swiper.loopDestroy() - // @ts-ignore - _swiper.loopCreate() - } } } } @@ -313,3 +348,14 @@ export class Swiper implements ComponentInterface { ) } } + +function debounce (fn, delay: number) { + let timer: NodeJS.Timeout + + return function (...arrs) { + clearTimeout(timer) + timer = setTimeout(function () { + fn(...arrs) + }, delay) + } +}