UNPKG

@tarojs/components

Version:
755 lines (754 loc) 26.9 kB
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var _Swiper_id, _Swiper_source, _Swiper_swiperResetting, _Swiper_domChangeByOutSide, _Swiper_lastSwiperActiveIndex; import { h, Host } from '@stencil/core'; import SwiperJS from 'swiper/bundle'; import { debounce } from '../../utils'; let INSTANCE_ID = 0; const ONE_ADDITIONAL_SLIDES_THRESHOLD = 5; const TWO_ADDITIONAL_SLIDES_THRESHOLD = 7; export class Swiper { constructor() { _Swiper_id.set(this, INSTANCE_ID++); _Swiper_source.set(this, 'autoplay'); _Swiper_swiperResetting.set(this, false // dom 变化是否由外部引起,因为 swiper 的循环模式也会引起 dom 的变化。如果不是由外部引起的 dom 变化,就不需要重新初始化 swiper ); // dom 变化是否由外部引起,因为 swiper 的循环模式也会引起 dom 的变化。如果不是由外部引起的 dom 变化,就不需要重新初始化 swiper _Swiper_domChangeByOutSide.set(this, false); _Swiper_lastSwiperActiveIndex.set(this, 0); this.handleSwiperSizeDebounce = debounce(() => { if (!this.swiper || !this.isWillLoadCalled) return; if (this.circular) { if (__classPrivateFieldGet(this, _Swiper_domChangeByOutSide, "f")) { this.reset(); __classPrivateFieldSet(this, _Swiper_domChangeByOutSide, false, "f"); __classPrivateFieldSet(this, _Swiper_swiperResetting, false, "f"); } } else { this.swiper.update(); __classPrivateFieldSet(this, _Swiper_swiperResetting, false, "f"); } }, 50); this.reset = () => { __classPrivateFieldSet(this, _Swiper_swiperResetting, true, "f"); __classPrivateFieldSet(this, _Swiper_lastSwiperActiveIndex, this.swiper.realIndex, "f"); this.swiper.destroy(); this.handleInit(true); __classPrivateFieldSet(this, _Swiper_swiperResetting, false, "f"); }; // 下面为方法函数 this.getSlidersList = () => this.el.querySelectorAll('taro-swiper-item-core:not(.swiper-slide-duplicate)') || []; // 获取是否需要手动修复 loop 的条件 this.getNeedFixLoop = () => { const margins = this.parseMargin(); const hasMargin = margins.filter(Boolean).length > 0; return this.circular && hasMargin; }; this.parseMargin = () => { const [, previousMargin] = /^(\d+)px/.exec(this.previousMargin) || []; const [, nextMargin] = /^(\d+)px/.exec(this.nextMargin) || []; return [parseInt(previousMargin) || 0, parseInt(nextMargin) || 0]; }; this.swiperWrapper = undefined; this.swiper = undefined; this.isWillLoadCalled = false; this.indicatorDots = false; this.indicatorColor = 'rgba(0, 0, 0, .3)'; this.indicatorActiveColor = '#000000'; this.autoplay = false; this.current = 0; this.currentItemId = ''; this.interval = 5000; this.duration = 500; this.circular = false; this.vertical = false; this.previousMargin = '0px'; this.nextMargin = '0px'; this.displayMultipleItems = 1; this.full = false; this.zoom = false; this.effectsProps = {}; this.observer = undefined; } watchCurrent(newVal) { if (this.currentItemId || !this.isWillLoadCalled || !this.swiper) return; const n = parseInt(newVal, 10); if (isNaN(n) || n === this.swiper.realIndex) return; __classPrivateFieldSet(this, _Swiper_source, '', "f"); if (this.circular) { this.swiper.slideToLoop(n); // 更新下标 this.autoplay && this.swiper.autoplay.pause(); // @ts-ignore this.swiper.loopFix(); this.autoplay && this.swiper.autoplay.start(); } else { this.swiper.slideTo(n); // 更新下标 } } watchCurrentItemId(newVal) { if (!this.swiperWrapper || !this.isWillLoadCalled) return; let itemIdIndex = 0; this.getSlidersList().forEach((swiperItem, index) => { const itemId = swiperItem.getAttribute('item-id'); if (itemId === newVal) { if (this.circular) { itemIdIndex = Number(swiperItem.getAttribute('data-swiper-slide-index')); } else { itemIdIndex = index; } } }); if (itemIdIndex === this.swiper.realIndex) return; // 无需更新 __classPrivateFieldSet(this, _Swiper_source, '', "f"); if (this.circular) { this.swiper.slideToLoop(itemIdIndex); // 更新下标 // @ts-ignore this.swiper.loopFix(); this.autoplay && this.swiper.autoplay.start(); } else { this.swiper.slideTo(itemIdIndex); // 更新下标 } } watchAutoplay(newVal) { if (!this.isWillLoadCalled || !this.swiper) return; const swiperAutoplay = this.swiper.autoplay; if (swiperAutoplay) { if (swiperAutoplay.running === newVal) return; if (newVal) { if (this.swiper.params && typeof this.swiper.params.autoplay === 'object') { if (this.swiper.params.autoplay.disableOnInteraction === true) { this.swiper.params.autoplay.disableOnInteraction = false; } this.swiper.params.autoplay.delay = this.interval; } swiperAutoplay.start(); } else { swiperAutoplay.stop(); } } } watchDuration(newVal) { if (!this.swiper || !this.isWillLoadCalled) return; this.swiper.params.speed = newVal; } watchInterval(newVal) { if (!this.swiper || !this.isWillLoadCalled) return; if (typeof this.swiper.params.autoplay === 'object') { this.swiper.params.autoplay.delay = newVal; } } watchSwiperWrapper(newVal) { if (!this.isWillLoadCalled || !this.swiper) return; if (!newVal) return; const beforeDomOperation = () => { __classPrivateFieldSet(this, _Swiper_domChangeByOutSide, true, "f"); // 如果是由于外部子节点的变化引起的 dom 变化,需要重新初始化 swiper。 // 在初dom操作之前,需要调用 loopDestroy,把子节点的顺序恢复 this.swiper.loopDestroy(); this.swiper.params.loop = false; }; this.el.appendChild = (newChild) => { __classPrivateFieldSet(this, _Swiper_swiperResetting, true, "f"); if (!__classPrivateFieldGet(this, _Swiper_domChangeByOutSide, "f") && this.circular) { beforeDomOperation(); } return newVal.appendChild(newChild); }; this.el.insertBefore = (newChild, refChild) => { __classPrivateFieldSet(this, _Swiper_swiperResetting, true, "f"); if (!__classPrivateFieldGet(this, _Swiper_domChangeByOutSide, "f") && this.circular) { beforeDomOperation(); } return newVal.insertBefore(newChild, refChild); }; this.el.replaceChild = (newChild, oldChild) => { __classPrivateFieldSet(this, _Swiper_swiperResetting, true, "f"); if (!__classPrivateFieldGet(this, _Swiper_domChangeByOutSide, "f") && this.circular) { beforeDomOperation(); } return newVal.replaceChild(newChild, oldChild); }; this.el.removeChild = (oldChild) => { __classPrivateFieldSet(this, _Swiper_swiperResetting, true, "f"); if (!__classPrivateFieldGet(this, _Swiper_domChangeByOutSide, "f") && this.circular) { beforeDomOperation(); } return newVal.removeChild(oldChild); }; } watchCircular() { if (!this.swiper || !this.isWillLoadCalled) return; this.reset(); } watchDisplayMultipleItems() { if (!this.swiper || !this.isWillLoadCalled) return; this.reset(); } componentWillLoad() { this.isWillLoadCalled = true; } componentDidLoad() { this.handleInit(); if (!this.swiper || !this.swiperWrapper) return; this.observer = new MutationObserver(this.handleSwiperSizeDebounce); this.observer.observe(this.swiperWrapper, { childList: true }); } disconnectedCallback() { var _a; (_a = this.observer) === null || _a === void 0 ? void 0 : _a.disconnect(); } handleInit(reset = false) { const { autoplay, circular, current, currentItemId, displayMultipleItems, duration, interval, effectsProps, vertical } = this; let initialSlide = current; if (reset) { initialSlide = __classPrivateFieldGet(this, _Swiper_lastSwiperActiveIndex, "f"); } else { if (currentItemId) { let itemIdIndex = 0; this.getSlidersList().forEach((swiperItem, index) => { // @ts-ignore if (swiperItem.itemId && swiperItem.itemId === currentItemId) { itemIdIndex = index; } }); initialSlide = itemIdIndex; } } const loopAdditionalSlides = this.getLoopAdditionalSlides(); const centeredSlides = displayMultipleItems === 1 && this.getNeedFixLoop(); const slidesPerView = displayMultipleItems; // eslint-disable-next-line @typescript-eslint/no-this-alias const that = this; const options = Object.assign(Object.assign({ pagination: { el: `.taro-swiper-${__classPrivateFieldGet(this, _Swiper_id, "f")} > .swiper-container > .swiper-pagination` }, direction: vertical ? 'vertical' : 'horizontal', loop: circular, slidesPerView: slidesPerView, initialSlide: initialSlide, loopAdditionalSlides: loopAdditionalSlides, speed: duration, observeParents: true, observer: true, centeredSlides: centeredSlides, zoom: this.zoom, nested: true, touchReleaseOnEdges: true, threshold: 0 }, effectsProps), { on: { transitionEnd(e) { if (__classPrivateFieldGet(that, _Swiper_swiperResetting, "f") || __classPrivateFieldGet(that, _Swiper_lastSwiperActiveIndex, "f") === this.realIndex) return; __classPrivateFieldSet(that, _Swiper_lastSwiperActiveIndex, this.realIndex, "f"); that.getNeedFixLoop() && e.loopFix(); that.autoplay && e.autoplay.start(); const currentItemId = that.getCurrentItemId(e); that.onAnimationFinish.emit({ current: this.realIndex, source: __classPrivateFieldGet(that, _Swiper_source, "f"), currentItemId, }); __classPrivateFieldSet(that, _Swiper_source, 'autoplay', "f"); }, touchMove() { __classPrivateFieldSet(that, _Swiper_source, 'touch', "f"); }, slideChange(e) { if (__classPrivateFieldGet(that, _Swiper_swiperResetting, "f") || __classPrivateFieldGet(that, _Swiper_lastSwiperActiveIndex, "f") === this.realIndex) return; const currentItemId = that.getCurrentItemId(e); that.onChange.emit({ current: this.realIndex, source: __classPrivateFieldGet(that, _Swiper_source, "f"), currentItemId, }); }, init: (e) => { that.getNeedFixLoop() && e.loopFix(); that.autoplay && e.autoplay.start(); }, touchEnd: (e) => { __classPrivateFieldSet(that, _Swiper_source, 'touch', "f"); that.autoplay && e.autoplay.start(); }, touchStart: (e) => { __classPrivateFieldSet(that, _Swiper_source, 'touch', "f"); that.autoplay && e.autoplay.pause(); }, autoplay(e) { // Note: 修复 autoplay 时,切换到其他页面再切回来,autoplay 会停止的问题 // autoplay 会调用 slideTo 方法,里面会判断是否 animating,如果 animating 为 true,就会被 return // 参考源码:https://github.com/nolimits4web/swiper/blob/v11.1.0/src/core/slide/slideTo.mjs#27 27行 // https://github.com/nolimits4web/swiper/blob/v11.1.0/src/modules/autoplay/autoplay.mjs e.animating = false; __classPrivateFieldSet(that, _Swiper_source, 'autoplay', "f"); } } }); // 自动播放 if (autoplay) { options.autoplay = { delay: interval, disableOnInteraction: false }; } this.swiper = new SwiperJS(`.taro-swiper-${__classPrivateFieldGet(this, _Swiper_id, "f")} > .swiper-container`, options); // Note: 这里是拦截了 swiper 的 minTranslate 和 maxTranslate 方法,手动修复了 loop 模式下的 margin 问题 // 因为这两个属性会影响滑动到哪个位置进行 fixloop // 可参考源码:https://github.com/nolimits4web/swiper/blob/v11.1.0/src/core/events/onTouchMove.mjs // https://github.com/nolimits4web/swiper/blob/v11.1.0/src/core/loop/loopFix.mjs if (this.getNeedFixLoop()) { // @ts-ignore const minTranslate = this.swiper.minTranslate.bind(this.swiper); //@ts-ignore const maxTranslate = this.swiper.maxTranslate.bind(this.swiper); if (centeredSlides && this.getSlidersList().length < 4) { //@ts-ignore this.swiper.minTranslate = () => minTranslate() + this.parseMargin()[1]; //@ts-ignore this.swiper.maxTranslate = () => maxTranslate() - this.parseMargin()[0]; } else { //@ts-ignore this.swiper.minTranslate = () => minTranslate() - this.parseMargin()[0]; //@ts-ignore this.swiper.maxTranslate = () => maxTranslate() + this.parseMargin()[1]; } } this.swiperWrapper = this.swiper.wrapperEl; } // Note: loop 的时候添加 additionalSlides 可以避免循环的时候由于 loopFix 不及时,出现空白的问题。但是并不是 additionalSlides 越多越好,因为 additionalSlides 越多,如果 swiper-item 的数量不够,会导致出现 bug。 // 目前的策略是 swiper-item 的数量小于等于 5 时,不添加 additionalSlides,大于 5 小于等于 7 时,添加 1 个 additionalSlides,大于 7 时,添加 2 个 additionalSlides。 getLoopAdditionalSlides() { const slidersLength = (this.getSlidersList()).length; if (!this.el || !this.getNeedFixLoop() || slidersLength < ONE_ADDITIONAL_SLIDES_THRESHOLD) return 0; if (slidersLength <= TWO_ADDITIONAL_SLIDES_THRESHOLD) return 1; return 2; } getCurrentItemId(swiper) { const slides = swiper.slides; const activeIndex = swiper.activeIndex; const currentSlide = slides[activeIndex]; return currentSlide.getAttribute('item-id'); } render() { const { vertical, indicatorDots, indicatorColor, indicatorActiveColor } = this; const [pM, nM] = this.parseMargin(); const swiperContainerStyleList = [ 'overflow: visible;', vertical ? `margin-top: ${pM}px; margin-bottom: ${nM}px;` : `margin-right: ${nM}px; margin-left: ${pM}px;`, this.full ? 'height: 100%;' : '', ]; const swiperPaginationStyleList = [ indicatorDots ? 'opacity: 1;' : 'display: none;', 'font-size: 0;' ]; const hostStyle = { overflow: 'hidden' }; if (this.full) { hostStyle.height = '100%'; } return (h(Host, { class: `taro-swiper-${__classPrivateFieldGet(this, _Swiper_id, "f")}`, style: hostStyle }, h("div", { class: 'swiper-container' }, h("style", { type: 'text/css' }, ` .taro-swiper-${__classPrivateFieldGet(this, _Swiper_id, "f")} > .swiper-container > .swiper-pagination > .swiper-pagination-bullet { background: ${indicatorColor} } .taro-swiper-${__classPrivateFieldGet(this, _Swiper_id, "f")} > .swiper-container > .swiper-pagination > .swiper-pagination-bullet-active { background: ${indicatorActiveColor} } .taro-swiper-${__classPrivateFieldGet(this, _Swiper_id, "f")} > .swiper-container { ${swiperContainerStyleList.join('')} } .taro-swiper-${__classPrivateFieldGet(this, _Swiper_id, "f")} > .swiper-container > .swiper-pagination { ${swiperPaginationStyleList.join('')} } `), h("div", { class: 'swiper-wrapper' }, h("slot", null)), h("div", { class: 'swiper-pagination' })))); } static get is() { return "taro-swiper-core"; } static get originalStyleUrls() { return { "$": ["./style/index.scss"] }; } static get styleUrls() { return { "$": ["./style/index.css"] }; } static get properties() { return { "indicatorDots": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u662F\u5426\u663E\u793A\u9762\u677F\u6307\u793A\u70B9" }, "attribute": "indicator-dots", "reflect": false, "defaultValue": "false" }, "indicatorColor": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u6307\u793A\u70B9\u989C\u8272" }, "attribute": "indicator-color", "reflect": false, "defaultValue": "'rgba(0, 0, 0, .3)'" }, "indicatorActiveColor": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u5F53\u524D\u9009\u4E2D\u7684\u6307\u793A\u70B9\u989C\u8272" }, "attribute": "indicator-active-color", "reflect": false, "defaultValue": "'#000000'" }, "autoplay": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u662F\u5426\u81EA\u52A8\u5207\u6362" }, "attribute": "autoplay", "reflect": false, "defaultValue": "false" }, "current": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u5F53\u524D\u6240\u5728\u6ED1\u5757\u7684 index" }, "attribute": "current", "reflect": false, "defaultValue": "0" }, "currentItemId": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u5F53\u524D\u6240\u5728\u6ED1\u5757\u7684 item-id" }, "attribute": "current-item-id", "reflect": false, "defaultValue": "''" }, "interval": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u81EA\u52A8\u5207\u6362\u65F6\u95F4\u95F4\u9694" }, "attribute": "interval", "reflect": false, "defaultValue": "5000" }, "duration": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u6ED1\u52A8\u52A8\u753B\u65F6\u957F" }, "attribute": "duration", "reflect": false, "defaultValue": "500" }, "circular": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u662F\u5426\u91C7\u7528\u8854\u63A5\u6ED1\u52A8" }, "attribute": "circular", "reflect": false, "defaultValue": "false" }, "vertical": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u6ED1\u52A8\u65B9\u5411\u662F\u5426\u4E3A\u7EB5\u5411" }, "attribute": "vertical", "reflect": false, "defaultValue": "false" }, "previousMargin": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u524D\u8FB9\u8DDD\uFF0C\u53EF\u7528\u4E8E\u9732\u51FA\u524D\u4E00\u9879\u7684\u4E00\u5C0F\u90E8\u5206\uFF0C\u63A5\u53D7 px \u503C" }, "attribute": "previous-margin", "reflect": false, "defaultValue": "'0px'" }, "nextMargin": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u540E\u8FB9\u8DDD\uFF0C\u53EF\u7528\u4E8E\u9732\u51FA\u540E\u4E00\u9879\u7684\u4E00\u5C0F\u90E8\u5206\uFF0C\u63A5\u53D7 px \u503C" }, "attribute": "next-margin", "reflect": false, "defaultValue": "'0px'" }, "displayMultipleItems": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u540C\u65F6\u663E\u793A\u7684\u6ED1\u5757\u6570\u91CF" }, "attribute": "display-multiple-items", "reflect": false, "defaultValue": "1" }, "full": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u7ED9 previewImage API \u4F7F\u7528\uFF0C\u5168\u5C4F\u663E\u793A swiper" }, "attribute": "full", "reflect": false, "defaultValue": "false" }, "zoom": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "\u7ED9 previewImage API \u4F7F\u7528\uFF0C\u7F29\u653E\u652F\u6301" }, "attribute": "zoom", "reflect": false, "defaultValue": "false" }, "effectsProps": { "type": "unknown", "mutable": false, "complexType": { "original": "Record<string, any>", "resolved": "{ [x: string]: any; }", "references": { "Record": { "location": "global" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "swiper11 \u76F8\u5173\u7684\u52A8\u6548\u53C2\u6570\uFF0C\u5177\u4F53\u89C1\u6587\u6863 https://swiperjs.com/swiper-api#parameters" }, "defaultValue": "{}" } }; } static get states() { return { "swiperWrapper": {}, "swiper": {}, "isWillLoadCalled": {}, "observer": {} }; } static get events() { return [{ "method": "onChange", "name": "change", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "onAnimationFinish", "name": "animationfinish", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }]; } static get elementRef() { return "el"; } static get watchers() { return [{ "propName": "current", "methodName": "watchCurrent" }, { "propName": "currentItemId", "methodName": "watchCurrentItemId" }, { "propName": "autoplay", "methodName": "watchAutoplay" }, { "propName": "duration", "methodName": "watchDuration" }, { "propName": "interval", "methodName": "watchInterval" }, { "propName": "swiperWrapper", "methodName": "watchSwiperWrapper" }, { "propName": "circular", "methodName": "watchCircular" }, { "propName": "displayMultipleItems", "methodName": "watchDisplayMultipleItems" }]; } } _Swiper_id = new WeakMap(), _Swiper_source = new WeakMap(), _Swiper_swiperResetting = new WeakMap(), _Swiper_domChangeByOutSide = new WeakMap(), _Swiper_lastSwiperActiveIndex = new WeakMap();