@farris/ui-vue
Version:
Farris Vue, a Farris Design based Vue3 component library.
348 lines (347 loc) • 10 kB
JavaScript
import { withInstall as J } from "../common/index.esm.js";
import { defineComponent as V, ref as x, computed as A, watch as H, onMounted as X, onUnmounted as Y, createVNode as u, Fragment as D, createTextVNode as N } from "vue";
const G = {
// 初始激活的内容项索引
initialIndex: {
type: Number,
default: 0
},
// 走马灯容器高度
height: {
type: String,
default: "400px"
},
// 是否自动轮播
autoplay: {
type: Boolean,
default: !0
},
// 自动轮播的时间间隔(毫秒)
interval: {
type: Number,
default: 3e3
},
// 是否循环展示
loop: {
type: Boolean,
default: !0
},
// 展示方向
direction: {
type: String,
default: "horizontal",
validator: (e) => ["horizontal", "vertical"].includes(e)
},
// 切换按钮显示时机
arrow: {
type: String,
default: "hover",
validator: (e) => ["always", "hover", "never"].includes(e)
},
// 指示器位置
indicatorPosition: {
type: String,
default: "inside",
validator: (e) => ["inside", "outside", "none"].includes(e)
},
// 指示器切换触发方式
trigger: {
type: String,
default: "click",
validator: (e) => ["click", "hover"].includes(e)
},
// 悬停时是否暂停自动轮播
pauseOnHover: {
type: Boolean,
default: !0
},
// 展示风格类型
type: {
type: String,
default: "",
validator: (e) => ["card", ""].includes(e)
},
// 是否显示标题区域
showTitle: {
type: Boolean,
default: !1
},
// 标题对齐方式
titleAlign: {
type: String,
default: "left",
validator: (e) => ["left", "center", "right"].includes(e)
}
};
function U(e, { emit: m, slots: s }, n, d, h, c) {
const f = (l) => e.loop ? l - 1 : l, w = () => {
if (!e.loop)
return;
let l = !1, v = n.value;
n.value === 0 ? (v = d.value, l = !0) : n.value === h.value - 1 && (v = 1, l = !0), l && (c.value = !1, n.value = v);
}, g = (l, v = !1) => {
if (c.value && !v)
return;
let o;
if (typeof l == "string") {
if (!s.default || (o = s.default().findIndex((I) => {
var S;
return ((S = I.props) == null ? void 0 : S.name) === l;
}), o === -1))
return;
e.loop && (o += 1);
} else
o = l;
if (o < 0 || o >= h.value) {
if (!e.loop)
return;
o < 0 ? o = h.value - 2 : o = 1;
}
if (o === n.value && !v)
return;
const k = f(n.value);
n.value = o, c.value = !v, v || setTimeout(() => {
c.value = !1, w();
}, 500), m("change", f(o), k);
};
return {
setActiveItem: g,
next: () => {
if (d.value <= 1)
return;
let l = n.value + 1;
if (l >= h.value) {
if (!e.loop)
return;
l = h.value - 1;
}
g(l);
},
prev: () => {
if (d.value <= 1)
return;
let l = n.value - 1;
if (l < 0) {
if (!e.loop)
return;
l = 0;
}
g(l);
},
handleIndicatorEvent: (l) => {
e.trigger === "hover" && g(l);
},
handleIndicatorClick: (l) => {
e.trigger === "click" && g(l);
},
getRealIndex: f
};
}
function W(e, m, s) {
let n = null;
const d = () => {
n && (clearInterval(n), n = null);
}, h = () => {
e.autoplay && (d(), n = setInterval(() => {
(!m.value || !e.pauseOnHover) && s();
}, e.interval));
};
return { startAutoPlay: h, stopAutoPlay: d, handleMouseEnter: () => {
m.value = !0, e.pauseOnHover && d();
}, handleMouseLeave: () => {
m.value = !1, e.autoplay && h();
} };
}
const j = /* @__PURE__ */ V({
name: "Carousel",
props: G,
emits: ["change"],
setup(e, {
emit: m,
slots: s
}) {
const n = x(!1), d = x(!1), h = x(null), c = A(() => {
if (!s.default)
return 0;
const t = s.default();
return !t || t.length === 0 ? 0 : t.length === 1 && t[0].children && Array.isArray(t[0].children) ? t[0].children.length : t.length;
}), f = x(e.loop ? Math.min(e.initialIndex + 1, c.value) : e.initialIndex), w = A(() => e.loop ? c.value + 2 : c.value), {
next: g,
prev: $,
setActiveItem: b,
handleIndicatorEvent: P,
handleIndicatorClick: z,
getRealIndex: l
} = U(e, {
emit: m,
slots: s
}, f, c, w, n), {
startAutoPlay: v,
stopAutoPlay: o,
handleMouseEnter: k,
handleMouseLeave: C
} = W(e, d, g), I = A(() => -(f.value * 100) / w.value), S = A(() => ({
overflow: "hidden",
position: "relative",
height: e.height,
width: "100%"
})), B = A(() => {
const t = e.direction === "horizontal";
return {
display: "flex",
// 循环模式需要额外的克隆项空间
height: t ? "100%" : `${w.value * 100}%`,
width: t ? `${w.value * 100}%` : "100%",
flexDirection: t ? "row" : "column",
transition: n.value ? "transform 0.5s ease-in-out" : "none",
transform: t ? `translateX(${I.value}%)` : `translateY(${I.value}%)`
};
}), M = (t) => {
const i = t === f.value, r = e.direction === "horizontal", a = 100 / w.value;
return {
// flex-basis 是相对于父容器(轨道)的主轴方向
// 水平模式:flex-basis 控制宽度,每个项目占轨道宽度的 (100/totalItemCount)%
// 垂直模式:flex-basis 控制高度,每个项目占轨道高度的 (100/totalItemCount)%
flex: `0 0 ${a}%`,
// 确保另一个方向也占满
width: "100%",
height: "100%",
minWidth: r ? `${a}%` : "100%",
minHeight: r ? "100%" : `${a}%`,
position: "relative",
overflow: "hidden",
// 卡片模式的特殊样式
opacity: e.type === "card" ? i ? 1 : 0.5 : 1,
transform: e.type === "card" ? i ? "scale(1)" : "scale(0.8)" : "scale(1)",
transition: "all 0.5s ease-in-out",
cursor: e.type === "card" ? "pointer" : "default"
};
}, O = A(() => e.arrow === "never" ? !1 : e.arrow === "always" ? !0 : d.value), R = A(() => e.indicatorPosition !== "none" && c.value > 1);
H(() => e.autoplay, (t) => {
t && !d.value ? v() : o();
}), H(() => e.interval, () => {
e.autoplay && !d.value && v();
}), X(() => {
e.autoplay && v();
}), Y(() => {
o();
});
const F = () => {
if (!O.value || c.value <= 1)
return null;
const t = (r) => ({
position: "absolute",
[e.direction === "horizontal" ? r === "prev" ? "left" : "right" : r === "prev" ? "top" : "bottom"]: "16px",
[e.direction === "horizontal" ? "top" : "left"]: "50%",
transform: e.direction === "horizontal" ? "translateY(-50%)" : "translateX(-50%)"
}), i = e.direction === "horizontal" ? "horizontal" : "vertical";
return u(D, null, [u("button", {
class: `carousel-arrow carousel-arrow-prev ${i}`,
onClick: $,
type: "button",
style: t("prev")
}, [u("span", {
class: "icon"
}, [N("‹")])]), u("button", {
class: `carousel-arrow carousel-arrow-next ${i}`,
onClick: g,
type: "button",
style: t("next")
}, [u("span", {
class: "icon"
}, [N("›")])])]);
}, E = () => {
if (!R.value)
return null;
const t = e.indicatorPosition === "outside", i = c.value;
return u("div", {
class: `carousel-indicators ${t ? "outside" : ""}`
}, [Array.from({
length: i
}).map((r, a) => {
const y = e.loop ? a + 1 : a, _ = f.value === y;
return u("button", {
key: a,
type: "button",
class: `carousel-indicator ${_ ? "active" : ""}`,
onMouseenter: () => P(y),
onClick: () => z(y),
"aria-label": `Go to slide ${a + 1}`
}, null);
})]);
}, L = () => {
if (!e.showTitle || !s.default)
return null;
let t = s.default();
if (!t || t.length === 0)
return null;
t.length === 1 && t[0].children && Array.isArray(t[0].children) && (t = t[0].children);
const i = l(f.value), r = t[i];
if (!r || !r.props)
return null;
const {
label: a
} = r.props;
return a ? u("div", {
class: "carousel-title-area",
style: {
textAlign: {
left: "left",
center: "center",
right: "right"
}[e.titleAlign]
}
}, [u("h3", null, [a])]) : null;
}, T = () => {
if (!s.default)
return null;
let t = s.default();
if (!t || t.length === 0)
return null;
t.length === 1 && t[0].children && Array.isArray(t[0].children) && (t = t[0].children);
const i = [];
if (e.loop && t.length > 1) {
const r = t[t.length - 1];
i.push(u("div", {
key: "clone-last",
class: "carousel-item",
style: M(0)
}, [r]));
}
if (t.forEach((r, a) => {
const y = e.loop ? a + 1 : a;
i.push(u("div", {
key: a,
class: `carousel-item ${y === f.value ? "active" : ""}`,
style: M(y),
onClick: () => {
e.type === "card" && y !== f.value && b(y);
}
}, [r]));
}), e.loop && t.length > 1) {
const r = t[0], a = t.length + 1;
i.push(u("div", {
key: "clone-first",
class: "carousel-item",
style: M(a)
}, [r]));
}
return i;
};
return () => u("div", {
ref: h,
class: "el-carousel",
style: S.value,
onMouseenter: k,
onMouseleave: C
}, [u("div", {
class: "el-carousel__track",
style: B.value
}, [T()]), F(), e.indicatorPosition === "inside" && E(), e.indicatorPosition === "outside" && E(), L()]);
}
}), Q = J(j);
export {
j as FCarouselComponent,
G as carouselProps,
Q as default
};