vue3 elementPlus table skeleton 表格种 loading 状态的骨架屏
作者:互联网
之前用empty 插槽实现 不够简洁
全网搜索只有一个 elementui 的(vue2)
https://github.com/kangyonggan/vue-elementui-skeleton
扒下来改了下
原版是js的 这里换成ts了
1 import type { App, VNode } from 'vue' 2 /** 配置 */ 3 interface ISkeletonOption { 4 /** 指令名 */ 5 directiveName: string 6 /** 行数 */ 7 rows: number 8 /** 圆角 */ 9 radius: number 10 /** 背景颜色 */ 11 bg: string 12 } 13 export default { 14 install: (Vue: App, opts?: ISkeletonOption) => { 15 // #38BB8F 16 // #eaebed 17 // #74CFB1 18 opts ??= { directiveName: 'skeleton', rows: 5, radius: 5, bg: '#eaebed' } 19 Vue.directive(opts?.directiveName, { 20 updated(el: HTMLElement, binding, vnode) { 21 let { value } = binding 22 if (typeof value !== 'object') { 23 value = { loading: value } 24 } 25 // loading为true并且el的data-skeleton="0"或者空的时候画骨架 26 if (value.loading && (!el.dataset.skeleton || el.dataset.skeleton === '0')) { 27 el.dataset.skeleton = '1' 28 // el-table(自识别:宽度、列数、行高。可配置:行数、圆角、背景色) 29 if (el.classList.contains('el-table')) { 30 // 隐藏空数据提示 31 const totalWidth = el.clientWidth 32 const emptyText = el.querySelector('.el-table__empty-block') as HTMLElement 33 if (emptyText) { 34 emptyText.style.display = 'none' 35 } 36 37 // 计算每一列的宽度 38 const colsWidth = [] 39 let usedWidth = 0 40 let freeCount = 0 41 /** vnode.children[0].children[0].children[0] 这个路径.... */ 42 const [children] = (vnode.children as any)[0].children[0].children as VNode[] 43 /** 过滤出表头 */ 44 const Columns = (children.children as VNode[]).filter((e: any) => e.type.name == 'ElTableColumn') 45 for (let i = 0; i < Columns.length; i++) { 46 const item = Columns[i] as any 47 colsWidth.push(item.component.propsOptions.width * 1) 48 if (item.component.propsOptions.width) { 49 usedWidth += item.component.propsOptions.width * 1 50 } else { 51 freeCount++ 52 } 53 } 54 55 // 没指定宽度的列宽 = (总宽 - 已指定的列宽总和) / 未指定列宽的个数 56 const autoWidth = (totalWidth - usedWidth) / freeCount 57 for (let i = 0; i < colsWidth.length; i++) { 58 if (!colsWidth[i]) { 59 colsWidth[i] = autoWidth 60 } 61 } 62 63 // 在tbody中画骨架 64 const tbody = el.querySelector('.el-table__body tbody') 65 if (tbody) { 66 // 行数(缺省为5) 67 const rows = value.rows || opts?.rows 68 // 骨架屏背景色(缺省为#eaebed) 69 const bg = value.bg || opts?.bg 70 // 圆角(缺省为5) 71 const radius = value.radius || opts?.radius 72 for (let i = 0; i < rows; i++) { 73 const tr = document.createElement('tr') 74 tr.className = 'skeleton-tr el-table__row is-animated' 75 for (let j = 0; j < colsWidth.length; j++) { 76 const td = document.createElement('td') 77 td.className = 'cell' 78 const div = document.createElement('div') 79 div.style.lineHeight = '15px' 80 div.style.margin = '8px 0' 81 div.style.background = bg 82 div.style.borderRadius = `${radius}px` 83 div.style.textIndent = '-999px' 84 85 /** 随机宽度*/ 86 div.style.width = `${Math.random() * 60 + 30}%` 87 88 div.appendChild(document.createTextNode('.')) 89 td.appendChild(div) 90 tr.appendChild(td) 91 } 92 tbody.appendChild(tr) 93 } 94 } 95 } 96 } else if (!value.loading && el.dataset.skeleton === '1') { 97 // loading为false并且el的data-skeleton="1"的时候删除骨架 98 el.dataset.skeleton = '0' 99 100 // el-table 101 if (el.classList.contains('el-table')) { 102 const allSkeletons = el.querySelectorAll('.skeleton-tr') 103 const tbody = el.querySelector('.el-table__body tbody') as HTMLElement 104 for (let i = 0; i < allSkeletons.length; i++) { 105 tbody.removeChild(allSkeletons[i]) 106 } 107 const emptyText = el.querySelector('.el-table__empty-block') as HTMLElement 108 if (emptyText) { 109 emptyText.style.display = 'block' 110 } 111 } 112 } 113 } 114 }) 115 116 } 117 }
用法 全局导入
// main.ts import skeletonDirective from '/@/****/skeletonDirective' app.use(skeletonDirective)
vue模板中
1 <el-table v-skeleton="loading"> 2 <el-table-column label="xxx"/> 3 <el-table-column label="xxx"/> 4 </el-table> 5 6 7 <el-table v-skeleton="{loading:loading,rows:10}"> 8 <el-table-column label="xxx"/> 9 <el-table-column label="xxx"/> 10 </el-table>
效果如下
也可以用 empty插槽实现
<el-table class="my-table"> <el-table-column label="xxx"/> <el-table-column label="xxx"/> <template #empty> <el-row v-if="loading" :gutter="20"> <el-col v-for="item in 4" :key="item" :span="6"> <el-skeleton :rows="5" animated /> </el-col> </el-row> <div v-else style="text-align: center;">暂无数据</div> </template> </el-table>
<!--样式--> <style lang='scss' scoped> .my-table { :deep() .el-table__empty-text { margin-top: 1rem; line-height: 25px; text-align: left; width: calc(100% - 20px); } :deep() .el-empty { padding-top: 0; } } </style>
标签:el,loading,const,skeleton,elementPlus,table,div,children 来源: https://www.cnblogs.com/shouniu/p/16101261.html