You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
2.8 KiB
Vue
106 lines
2.8 KiB
Vue
<template>
|
|
<view class="wd-skeleton" :class="[props.customClass]" :style="props.customStyle">
|
|
<view class="wd-skeleton__content" v-if="parsedRowCols.length">
|
|
<view class="wd-skeleton__row" v-for="(row, index) of parsedRowCols" :key="`row-${index}`">
|
|
<view v-for="(col, idx) of row" :key="`col-${idx}`" :class="col.class" :style="col.style" />
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
<script lang="ts">
|
|
export default {
|
|
// #ifdef H5
|
|
name: 'wd-skeleton',
|
|
// #endif
|
|
options: { virtualHost: true, addGlobalClass: true, styleIsolation: 'shared' }
|
|
}
|
|
</script>
|
|
|
|
<script lang="ts" setup>
|
|
import type { CSSProperties } from 'vue'
|
|
import { ref, computed, watch } from 'vue'
|
|
import type { SkeletonRowCol, SkeletonRowColObj } from './types'
|
|
import { skeletonProps } from './types'
|
|
import { isNumber, addUnit } from '../common/util'
|
|
|
|
const themeMap = {
|
|
avatar: [{ type: 'circle', height: '64px', width: '64px' }],
|
|
image: [{ type: 'rect', height: '64px', width: '64px' }],
|
|
text: [
|
|
1,
|
|
[
|
|
{ width: '24%', height: '16px', marginRight: '16px' },
|
|
{ width: '76%', height: '16px' }
|
|
]
|
|
],
|
|
paragraph: [1, 1, 1, { width: '55%' }]
|
|
}
|
|
const props = defineProps(skeletonProps)
|
|
const rowCols = ref<SkeletonRowCol>([])
|
|
|
|
const parsedRowCols = computed(() => {
|
|
return rowCols.value.map((item) => {
|
|
if (isNumber(item)) {
|
|
return [
|
|
{
|
|
class: getColItemClass({ type: 'text' }),
|
|
style: {}
|
|
}
|
|
]
|
|
}
|
|
if (Array.isArray(item)) {
|
|
return item.map((col) => {
|
|
return {
|
|
...col,
|
|
class: getColItemClass(col),
|
|
style: getColItemStyle(col)
|
|
}
|
|
})
|
|
}
|
|
const nItem = item as SkeletonRowColObj
|
|
|
|
return [
|
|
{
|
|
...nItem,
|
|
class: getColItemClass(nItem),
|
|
style: getColItemStyle(nItem)
|
|
}
|
|
]
|
|
})
|
|
})
|
|
|
|
function getColItemClass(rowCol: SkeletonRowColObj) {
|
|
return ['wd-skeleton__col', `wd-skeleton--type-${rowCol.type || 'text'}`, { [`wd-skeleton--animation-${props.animation}`]: props.animation }]
|
|
}
|
|
function getColItemStyle(rowCol: SkeletonRowColObj) {
|
|
const style: CSSProperties = {}
|
|
const styleName = ['size', 'width', 'height', 'margin', 'background', 'marginLeft', 'marginRight', 'borderRadius', 'backgroundColor']
|
|
|
|
for (const name of styleName) {
|
|
if (Object.prototype.hasOwnProperty.call(rowCol, name)) {
|
|
const px = addUnit(rowCol[name])
|
|
|
|
if (name === 'size') {
|
|
style.width = px
|
|
style.height = px
|
|
} else {
|
|
style[name] = px
|
|
}
|
|
}
|
|
}
|
|
return style
|
|
}
|
|
|
|
watch(
|
|
() => props.rowCol,
|
|
(rowCol) => {
|
|
rowCols.value = [...(Array.isArray(rowCol) && rowCol.length ? props.rowCol : themeMap[props.theme])]
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
@import './index.scss';
|
|
</style>
|