automated_uniapp/uni_modules/cool-ui/components/cl-noticebar/cl-noticebar.vue
2025-01-09 16:16:11 +08:00

221 lines
3.9 KiB
Vue

<template>
<view
class="cl-noticebar"
:class="[
{
'is-scrollable': scrollable,
},
]"
:style="{
color,
backgroundColor,
}"
v-if="visible"
>
<cl-icon
name="close-border"
:size="34"
:margin="[0, 10, 0, 0]"
@tap="close"
v-if="closeable"
/>
<slot name="icon">
<cl-icon :class-name="icon" :size="34" :margin="[0, 10, 0, 0]" v-if="icon" />
</slot>
<view class="cl-noticebar__box">
<view
class="cl-noticebar__scroller"
:class="[`is-${direction}`]"
:style="{
height: parseRpx(height),
top: scroll.top + 'px',
left: scroll.left + 'px',
transition,
transform: `translateX(-${scroll.translateX}px)`,
}"
>
<view class="cl-noticebar__item" v-for="(item, index) in list" :key="index">
<text class="cl-noticebar__text">{{ item }}</text>
</view>
</view>
</view>
</view>
</template>
<script lang="ts">
import {
defineComponent,
onMounted,
onUnmounted,
reactive,
ref,
computed,
getCurrentInstance,
type PropType,
} from "vue";
import { isArray } from "lodash-es";
import { parseRpx } from "/@/cool/utils";
export default defineComponent({
name: "cl-noticebar",
props: {
// 文本内容
text: {
type: [String, Array],
default: "",
required: true,
},
// 方向
direction: {
type: String as PropType<"horizontal" | "vertical">,
default: "horizontal",
},
// 字体颜色
color: String,
// 背景颜色
backgroundColor: String,
// 能否滚动
scrollable: Boolean,
// 滚动时长
duration: {
type: Number,
default: 10,
},
// 能否关闭
closeable: Boolean,
// 左侧图标
icon: String,
// 高度
height: {
type: [String, Number],
default: 40,
},
},
emits: ["close"],
setup(props, { emit }) {
const { proxy }: any = getCurrentInstance();
// 是否可见
const visible = ref(true);
// 滚动配置
const scroll = reactive({
left: 0,
top: 0,
translateX: 0,
duration: 0,
});
// 计时器
let timer: any = null;
// 文案列表
const list = computed(() => {
return isArray(props.text) ? props.text : [props.text];
});
// 动画过度
const transition = computed(() => {
if (props.direction == "horizontal") {
return `transform ${scroll.duration}s linear`;
} else {
return `top 0.3s`;
}
});
// 刷新
function refresh() {
if (props.scrollable) {
// 清除定时器
clear();
// 获取盒子大小
uni.createSelectorQuery()
.in(proxy)
.select(`.cl-noticebar__box`)
.boundingClientRect((box: any) => {
// 获取文本大小
uni.createSelectorQuery()
.in(proxy)
.select(`.cl-noticebar__text`)
.boundingClientRect((text: any) => {
const duration = props.duration * 1000;
// 水平滑动
if (props.direction == "horizontal") {
const fn = () => {
scroll.duration = props.duration;
scroll.left = box.width;
scroll.translateX = text.width + scroll.left;
timer = setTimeout(() => {
scroll.translateX = 0;
scroll.duration = 0;
setTimeout(fn, 500);
}, duration);
};
fn();
}
// 垂直滑动
else {
timer = setInterval(() => {
if (
Math.abs(scroll.top) >=
box.height * (list.value.length - 1)
) {
scroll.top = 0;
} else {
scroll.top -= box.height;
}
}, duration);
}
})
.exec();
})
.exec();
}
}
// 关闭
function close() {
clear();
visible.value = false;
emit("close");
}
// 清空
function clear() {
clearInterval(timer);
clearTimeout(timer);
timer = null;
}
onMounted(() => {
refresh();
});
onUnmounted(() => {
clear();
});
return {
visible,
scroll,
list,
transition,
refresh,
close,
clear,
parseRpx,
};
},
});
</script>