@zhsz/cool-design-dv
Version:
258 lines (257 loc) • 6.97 kB
JavaScript
import { defineComponent, ref, computed, watch, nextTick, onMounted, onBeforeUnmount, openBlock, createElementBlock, normalizeClass, normalizeStyle, createElementVNode, renderSlot } from "vue";
import { cancelAnimationFrame, requestAnimationFrame } from "../../utils/util.mjs";
import "./style.css";
const _hoisted_1 = ["innerHTML"];
const __default__ = defineComponent({
name: "DvMarquee"
});
const _sfc_main = /* @__PURE__ */ defineComponent({
...__default__,
props: {
// 滚动数据
data: {
type: Array,
default() {
return [];
}
},
disabled: Boolean,
// 滚动方向
direction: {
type: String,
default: "up",
validator(val) {
return ["up", "down", "left", "right"].includes(val);
}
},
// 自动开始
auto: {
type: Boolean,
default: true
},
// 滚动速度,数值越大速度越快
speed: {
type: Number,
default: 1
},
// 间隔滚动停顿等待时间
waitTime: {
type: Number,
default: 3e3
},
// 间隔滚动,每次滚动的长度,单位px
scrollLength: {
type: Number,
deault: 0
},
customStyle: {
type: Object
}
},
emits: ["resize"],
setup(__props, { emit: __emit }) {
const props = __props;
const timerId = ref();
const copyHtml = ref("");
const contentWidth = ref(0);
const contentHeight = ref(0);
const scrollPosition = ref(0);
const isPause = ref(false);
const content = ref();
const resumeId = ref();
const $emit = __emit;
const isHorizontal = computed(() => {
return ["left", "right"].includes(props.direction);
});
const classes = computed(() => {
return {
"my-marquee--horizontal": isHorizontal.value,
"is-disabled": props.disabled
};
});
const scrollStyle = computed(() => {
return {
transform: isHorizontal.value ? `translate3d(-${scrollPosition.value}px, 0, 0)` : `translate3d(0, -${scrollPosition.value}px, 0)`,
width: isHorizontal.value ? `${2 * contentWidth.value}px` : "100%"
};
});
function renderCopyHtml() {
if (!content.value || props.disabled)
return;
copyHtml.value = content.value.innerHTML;
updateView();
}
function updateView() {
if (!content.value)
return;
const rect = content.value.getBoundingClientRect();
contentHeight.value = rect.height;
contentWidth.value = rect.width;
$emit("resize", rect);
}
function start() {
isPause.value = false;
switch (props.direction) {
case "up":
scrollPosition.value = scrollPosition.value || 0;
scrollUp();
break;
case "down":
scrollPosition.value = scrollPosition.value || contentHeight.value;
scrollDown();
break;
case "left":
scrollPosition.value = scrollPosition.value || 0;
scrollLeft();
break;
case "right":
scrollPosition.value = scrollPosition.value || contentWidth.value;
scrollRight();
break;
}
}
function stop() {
timerId.value && cancelAnimationFrame(timerId.value);
resumeId.value && clearTimeout(resumeId.value);
}
function scrollUp() {
timerId.value = requestAnimationFrame(() => {
if (isPause.value) {
return;
}
scrollPosition.value = scrollPosition.value + props.speed;
if (resume()) {
isPause.value = true;
return;
}
if (scrollPosition.value >= contentHeight.value) {
scrollPosition.value = 0;
}
scrollUp();
});
}
function scrollDown() {
timerId.value = requestAnimationFrame(() => {
if (isPause.value) {
return;
}
scrollPosition.value = scrollPosition.value - props.speed;
if (resume()) {
isPause.value = true;
return;
}
if (scrollPosition.value <= 0) {
scrollPosition.value = contentHeight.value;
}
scrollDown();
});
}
function scrollLeft() {
timerId.value = requestAnimationFrame(() => {
if (isPause.value) {
return;
}
scrollPosition.value = scrollPosition.value + props.speed;
if (resume()) {
isPause.value = true;
return;
}
if (scrollPosition.value >= contentWidth.value) {
scrollPosition.value = 0;
}
scrollLeft();
});
}
function scrollRight() {
timerId.value = requestAnimationFrame(() => {
if (isPause.value) {
return;
}
scrollPosition.value = scrollPosition.value - props.speed;
if (resume()) {
isPause.value = true;
return;
}
if (scrollPosition.value <= 0) {
scrollPosition.value = contentWidth.value;
}
scrollRight();
});
}
function resume() {
const value = Math.floor(scrollPosition.value) % ((props == null ? void 0 : props.scrollLength) ?? 0);
const match = value === 0;
if (match) {
resumeId.value && clearTimeout(resumeId.value);
resumeId.value = setTimeout(start, props.waitTime);
}
return match;
}
function handleMouseEnter() {
stop();
isPause.value = true;
}
function handleMouseLeave() {
start();
}
watch(
() => props.data,
() => {
nextTick(renderCopyHtml);
},
{
immediate: true
}
);
watch(
() => props.disabled,
(val) => {
stop();
if (val) {
copyHtml.value = "";
scrollPosition.value = 0;
} else {
nextTick(renderCopyHtml);
props.auto && start();
}
}
);
onMounted(() => {
if (props.auto && !props.disabled) {
start();
}
});
onBeforeUnmount(() => {
stop();
copyHtml.value = "";
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
class: normalizeClass(["my-marquee", classes.value]),
style: normalizeStyle(__props.customStyle),
onMouseenter: handleMouseEnter,
onMouseleave: handleMouseLeave
}, [
createElementVNode("div", {
class: "my-marquee__scroll",
style: normalizeStyle(scrollStyle.value)
}, [
createElementVNode("div", {
ref_key: "content",
ref: content,
class: "my-marquee__content"
}, [
renderSlot(_ctx.$slots, "default")
], 512),
createElementVNode("div", {
class: "my-marquee__copy-content",
innerHTML: copyHtml.value
}, null, 8, _hoisted_1)
], 4)
], 38);
};
}
});
export {
_sfc_main as default
};