Initial project

This commit is contained in:
Timi
2025-07-08 16:33:11 +08:00
parent 1a5a16be74
commit f862530142
80 changed files with 8301 additions and 129 deletions

View File

@ -0,0 +1,5 @@
import view from "./index.vue";
import Toolkit from "~/utils/Toolkit";
export const Loading = Toolkit.withInstall(view);
export default Loading;

View File

@ -0,0 +1,153 @@
<template>
<div v-if="visible" class="tui-loading" :class="{ 'filled': filled }" :style="style">
<div class="icon">
<div
class="line"
:class="lineClass(i)"
v-for="i in 4"
:key="i"
></div>
</div>
<div v-if="tips" class="text" v-text="tips"></div>
</div>
</template>
<script lang="ts" setup>
import { Toolkit } from "~/index";
defineOptions({
name: "Loading"
});
const props = withDefaults(defineProps<{
tips?: string | boolean;
delay?: number;
showOn?: boolean;
size?: number;
filled?: boolean;
}>(), {
tips: "加载中..",
delay: 260,
showOn: true,
size: 24,
filled: false
});
const { tips, delay, showOn, size, filled } = toRefs(props);
// ---------- 尺寸参数 ----------
const style = computed(() => {
const base = Math.max(8, size.value);
const height = Math.round(base);
const width = Math.round(base * (8 / 24));
const gap = Math.round(base * (3 / 24));
return {
"--loading-height": `${height}px`,
"--rect-width": `${width}px`,
"--rect-gap": `${gap}px`
};
});
// ---------- 显示控制 ----------
const visible = ref<boolean>(false);
watch(showOn, async () => await start());
// ---------- 动画 ----------
const activeI = ref<number>(0);
const timer = ref();
const lineClass = (i: number): string => {
let clazz = "i" + i;
if (activeI.value === i) {
clazz += " active";
}
return clazz;
};
const start = async () => {
if (timer.value) {
clearInterval(timer.value);
}
if (showOn.value) {
if (0 < delay.value) {
await Toolkit.sleep(delay.value);
}
if (!showOn.value) {
return;
}
visible.value = true;
// 动画
let direction = 1;
timer.value = setInterval(() => {
activeI.value = activeI.value + direction;
if (4 < activeI.value || activeI.value < 1) {
direction *= -1;
}
}, 120);
} else {
visible.value = false;
}
};
onMounted(start);
onUnmounted(() => {
if (timer.value) {
clearInterval(timer.value);
}
});
</script>
<style lang="less" scoped>
.tui-loading {
--h1: calc(var(--loading-height) * (9 / 24));
--h2: calc(var(--loading-height) * (14 / 24));
--h3: calc(var(--loading-height) * (19 / 24));
--h4: var(--loading-height);
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
&.filled {
color: #FFF;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, .3);
}
.icon {
display: flex;
align-items: flex-end;
.line {
width: var(--rect-width);
background: #BBB;
margin-right: var(--rect-gap);
&.i1 {
height: calc(var(--h1))
}
&.i2 {
height: calc(var(--h2))
}
&.i3 {
height: calc(var(--h3))
}
&.i4 {
height: var(--h4)
}
&.active {
background: #53BD93;
}
}
}
.text {
margin-top: .5rem;
}
}
</style>