Files

212 lines
4.2 KiB
Vue
Raw Permalink Normal View History

2026-02-10 08:05:03 +08:00
<template>
<view>
<view
v-if="isShow"
:style="tools._style([customStyle])"
:class="[classPrefix + ' ', tClass]"
>
<view
v-if="parsedRowCols.length"
:class="classPrefix + '__content'"
>
<view
v-for="(row, index) in parsedRowCols"
:key="index"
:class="[
classPrefix + '__row ',
tClassRow
]"
>
<view
v-for="(col, index1) in row"
:key="index1"
:class="[col.class + ' ', tClassCol]"
:style="tools._style(col.style)"
/>
</view>
</view>
</view>
<view
v-else
:class="classPrefix + '__content'"
>
<slot />
</view>
</view>
</template>
<script>
import { uniComponent } from '../common/src/index';
import { prefix } from '../common/config';
import props from './props';
import { classNames } from '../common/utils';
import { isInteger, isNumeric } from '../common/validator';
import tools from '../common/utils.wxs';
const name = `${prefix}-skeleton`;
const ThemeMap = {
avatar: [{
type: 'circle',
size: '96rpx',
}],
image: [{
type: 'rect',
size: '144rpx',
}],
text: [[{
width: '24%',
height: '32rpx',
marginRight: '32rpx',
}, {
width: '76%',
height: '32rpx',
}], 1],
paragraph: [1, 1, 1, {
width: '55%',
}],
};
export default uniComponent({
name,
options: {
styleIsolation: 'shared',
},
externalClasses: [
`${prefix}-class`,
`${prefix}-class-col`,
`${prefix}-class-row`,
],
props: {
...props,
},
data() {
return {
prefix,
classPrefix: name,
parsedRowCols: [],
isShow: false,
tools,
timer: null,
};
},
watch: {
rowCol: {
handler() {
this.init();
},
immediate: true,
},
loading: 'isShowSkeleton',
delay: 'isShowSkeleton',
},
mounted() {
this.init();
this.isShowSkeleton();
},
beforeUnMount() {
this.clearTimer();
},
methods: {
init() {
const { theme, rowCol } = this;
const rowCols = [];
if (rowCol && rowCol.length) {
rowCols.push(...rowCol);
} else {
rowCols.push(...ThemeMap[theme || 'text']);
}
const parsedRowCols = rowCols.map((item) => {
if (isInteger(item) && item >= 0) {
return new Array(item).fill({
class: this.getColItemClass({ type: 'text' }),
style: {},
});
}
if (Array.isArray(item)) {
return item.map(col => ({
...col,
class: this.getColItemClass(col),
style: this.getColItemStyle(col),
}));
}
const nItem = item;
return [
{
...nItem,
class: this.getColItemClass(nItem),
style: this.getColItemStyle(nItem),
},
];
});
this.parsedRowCols = parsedRowCols;
},
getColItemClass(obj) {
return classNames([
`${name}__col`,
`${name}--type-${obj.type || 'text'}`,
`${name}--animation-${this.animation}`,
]);
},
getColItemStyle(obj) {
const styleName = [
'width',
'height',
'marginRight',
'marginLeft',
'margin',
'size',
'background',
'backgroundColor',
'borderRadius',
];
const style = {};
styleName.forEach((name) => {
if (name in obj) {
const px = isNumeric(obj[name]) ? `${obj[name]}px` : obj[name];
if (name === 'size') {
[style.width, style.height] = [px, px];
} else {
style[name] = px;
}
}
});
return style;
},
clearTimer() {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
},
isShowSkeleton() {
this.clearTimer();
const { loading, delay } = this;
if (!loading || delay === 0) {
this.isShow = loading;
return;
}
this.timer = setTimeout(() => {
this.isShow = this.loading;
}, delay);
},
},
});
</script>
<style scoped>
@import './skeleton.css';
</style>