UNPKG

@opensig/opendesign

Version:

413 lines (412 loc) 12.5 kB
import { defineComponent, ref, computed, watch, onMounted, onUnmounted, nextTick, provide, createElementBlock, openBlock, normalizeStyle, normalizeClass, createElementVNode, createCommentVNode, renderSlot, Fragment, renderList, createVNode, unref } from "vue"; import { IconChevronLeft, IconChevronRight } from "../_utils/icons.mjs"; import Gallery from "./effects/gallery.mjs"; import Toggle from "./effects/toggle.mjs"; import { carouselInjectKey } from "./provide.mjs"; import { carouselProps } from "./types.mjs"; const _hoisted_1 = { class: "o-carousel-wrap" }; const _hoisted_2 = ["onClick"]; const _hoisted_3 = { class: "o-carousel-arrow-prev" }; const _hoisted_4 = { class: "o-carousel-arrow-icon" }; const _hoisted_5 = { class: "o-carousel-arrow-next" }; const _hoisted_6 = { class: "o-carousel-arrow-icon" }; const _sfc_main = /* @__PURE__ */ defineComponent({ __name: "OCarousel", props: carouselProps, emits: ["before-change", "change", "update:activeIndex", "pause"], setup(__props, { expose: __expose, emit: __emit }) { const props = __props; const emits = __emit; const containerRef = ref(null); const childrenLength = ref(0); const registerItem = () => { childrenLength.value++; }; const unregisterItem = () => { childrenLength.value++; }; const total = computed(() => { var _a; childrenLength.value; return ((_a = containerRef.value) == null ? void 0 : _a.children.length) ?? 0; }); const isAutoPlay = ref(props.autoPlay); watch( () => props.autoPlay, (a) => { isAutoPlay.value = a; } ); const fixIndex = (idx) => { if (!total.value) { return idx; } const i = idx % total.value; return i >= 0 ? i : i + total.value; }; const activeIndex = ref(props.activeIndex ? fixIndex(props.activeIndex) : 0); watch( () => props.activeIndex, (v) => { activeIndex.value = v ?? 0; } ); const initialized = ref(false); const slidesRef = ref(null); const slideElList = computed(() => { var _a; childrenLength.value; const c = (_a = containerRef.value) == null ? void 0 : _a.children; return c ? Array.from(c).map((el) => el) : null; }); let slidesInstance = null; let isChanging = false; const activeSlideByIndex = (index) => { return new Promise((resolve) => { const to = fixIndex(index); const from = activeIndex.value; if (isChanging || !slideElList.value) { resolve(false); return; } if (to === from) { resolve(true); return; } isChanging = true; if (slidesInstance) { activeIndex.value = to; emits("update:activeIndex", to); slidesInstance.active(to).then(() => { isChanging = false; resolve(true); }); } else { isChanging = false; resolve(false); } }); }; let timer = null; const isPlaying = ref(isAutoPlay.value); const pausePlay = () => { if (timer) { clearInterval(timer); timer = null; isPlaying.value = false; emits("pause", activeIndex.value); } }; const startPlay = () => { pausePlay(); isPlaying.value = true; timer = window.setInterval(() => { activeSlideByIndex(activeIndex.value + 1); }, props.interval); }; const resumePlay = () => { if (isAutoPlay.value) { setTimeout(() => { startPlay(); }, 0); } }; const activeSlide = (index, resumeAutoPlay = true) => { pausePlay(); return activeSlideByIndex(index).then((success) => { if (!success) { return; } if (!props.pauseOnHover || resumeAutoPlay) { resumePlay(); } }); }; const clickListenerCleanups = []; const cleanupClickListeners = () => { clickListenerCleanups.forEach((fn) => fn()); clickListenerCleanups.length = 0; }; const buildEffectOptions = () => ({ activeClass: props.activeClass, onTouchstart: () => { pausePlay(); }, onTouchend: () => { resumePlay(); }, onBeforeChange: (to, from) => { emits("before-change", to, from); }, onChanged: (to, from) => { activeIndex.value = to; emits("update:activeIndex", to); emits("change", to, from); } }); const bindClickListeners = (els) => { els.forEach((el, idx) => { const handler = () => { if (idx !== activeIndex.value) { activeSlide(idx); } }; el.addEventListener("click", handler); clickListenerCleanups.push(() => el.removeEventListener("click", handler)); }); }; const initSlides = () => { if (!slideElList.value || !containerRef.value) { return; } slidesInstance == null ? void 0 : slidesInstance.destroyed(); slidesInstance = null; cleanupClickListeners(); if (activeIndex.value >= slideElList.value.length) { activeIndex.value = fixIndex(activeIndex.value); emits("update:activeIndex", activeIndex.value); } let EffectType = null; switch (props.effect) { case "gallery": { EffectType = Gallery; break; } case "toggle": { EffectType = Toggle; break; } default: { EffectType = Gallery; break; } } if (EffectType) { slidesInstance = new EffectType(slideElList.value, containerRef.value, activeIndex.value, buildEffectOptions()); } if (props.clickToSwitch) { bindClickListeners(slideElList.value); } initialized.value = true; }; watch( () => props.autoPlay, (v) => { if (v) { startPlay(); } else { pausePlay(); } } ); const init = () => { initSlides(); if (isAutoPlay.value) { startPlay(); } }; onMounted(() => { if (!props.manualInit) { init(); } }); onUnmounted(() => { if (timer) { clearInterval(timer); timer = null; } slidesInstance == null ? void 0 : slidesInstance.destroyed(); cleanupClickListeners(); }); watch( () => { var _a; return ((_a = slideElList.value) == null ? void 0 : _a.length) ?? 0; }, async (now, prev) => { if (!initialized.value || now === prev) { return; } await nextTick(); initSlides(); } ); provide(carouselInjectKey, { effect: props.effect, register: registerItem, unregister: unregisterItem }); const play = () => { isAutoPlay.value = true; startPlay(); }; const pause = () => { isAutoPlay.value = false; pausePlay(); }; const onHoverIn = () => { if (props.pauseOnHover) { pausePlay(); } }; const onHoverOut = () => { if (props.pauseOnHover) { resumePlay(); } }; __expose({ /** * @zh-CN 初始化轮播组件 * @en-US Initialize the carousel component */ init, /** * @zh-CN 开始自动播放 * @en-US Start auto play */ play, /** * @zh-CN 暂停自动播放 * @en-US Pause auto play */ pause, /** * @zh-CN 切换到指定幻灯片 * @en-US Switch to the specified slide */ active: activeSlide }); return (_ctx, _cache) => { return openBlock(), createElementBlock( "div", { ref_key: "slidesRef", ref: slidesRef, class: normalizeClass(["o-carousel", [ { "o-carousel-visible": initialized.value, "o-carousel-click-to-switch": props.clickToSwitch, "o-carousel-hover-arrow": props.arrow === "hover", "o-carousel-autoplay": isAutoPlay.value, "is-playing": isPlaying.value }, `o-carousel-effect-${props.effect}` ]]), style: normalizeStyle({ "--carousel-interval": props.interval + "ms" }), onMouseenter: onHoverIn, onMouseleave: onHoverOut }, [ createElementVNode("div", _hoisted_1, [ createElementVNode( "div", { ref_key: "containerRef", ref: containerRef, class: normalizeClass([`o-carousel-container-${props.effect}`]) }, [ renderSlot(_ctx.$slots, "default") ], 2 /* CLASS */ ) ]), !props.hideIndicator ? (openBlock(), createElementBlock( "div", { key: 0, class: normalizeClass(["o-carousel-indicator-wrap", props.indicatorWrapClass]) }, [ (openBlock(true), createElementBlock( Fragment, null, renderList(total.value, (item, idx) => { return openBlock(), createElementBlock("div", { key: item, class: "o-carousel-indicator-item", onClick: ($event) => props.indicatorClick && activeSlide(idx) }, [ renderSlot(_ctx.$slots, "indicator", { active: item - 1 === activeIndex.value, index: idx }, () => [ createElementVNode( "div", { class: normalizeClass(["o-carousel-indicator-bar", { "o-carousel-indicator-bar-selected": item - 1 === activeIndex.value }]) }, [..._cache[2] || (_cache[2] = [ createElementVNode( "div", { class: "o-carousel-indicator-line" }, null, -1 /* CACHED */ ) ])], 2 /* CLASS */ ) ]) ], 8, _hoisted_2); }), 128 /* KEYED_FRAGMENT */ )) ], 2 /* CLASS */ )) : createCommentVNode("v-if", true), props.arrow !== "never" ? (openBlock(), createElementBlock( "div", { key: 1, class: normalizeClass(["o-carousel-arrow-wrap", props.arrowWrapClass]) }, [ createElementVNode("div", { onClick: _cache[0] || (_cache[0] = ($event) => activeSlide(activeIndex.value - 1, false)) }, [ renderSlot(_ctx.$slots, "arrow-prev", {}, () => [ createElementVNode("div", _hoisted_3, [ createElementVNode("div", _hoisted_4, [ renderSlot(_ctx.$slots, "arrow-prev-icon", {}, () => [ createVNode(unref(IconChevronLeft)) ]) ]) ]) ]) ]), createElementVNode("div", { onClick: _cache[1] || (_cache[1] = ($event) => activeSlide(activeIndex.value + 1, false)) }, [ renderSlot(_ctx.$slots, "arrow-next", {}, () => [ createElementVNode("div", _hoisted_5, [ createElementVNode("div", _hoisted_6, [ renderSlot(_ctx.$slots, "arrow-next-icon", {}, () => [ createVNode(unref(IconChevronRight)) ]) ]) ]) ]) ]) ], 2 /* CLASS */ )) : createCommentVNode("v-if", true) ], 38 /* CLASS, STYLE, NEED_HYDRATION */ ); }; } }); export { _sfc_main as default };