文章目錄
- 前言
- CustomTable
- 如何使用
- tableColumn 屬性
- h函數
- 創建原生元素
- 創建組件
- 動態生成
前言
elementui中的table組件,表格中想要自由地渲染內容,是一種比較麻煩的事情,比如你表格中想要某一列插入一個button按鈕,是不是要用插槽,那下一次某一列插入一個圖片,又得新開一種插槽或者類別。
那么,有沒有什么方法,能夠通過配置,直接配置一個組件的方式,讓表格的那一列直接渲染對應的組件。elementui table中并不提供這樣的配置。所以需要開發人員自己封裝。
CustomTable
在element UI 中Table組件的基礎上,封裝一個可以自定義渲染的table
<template><!-- 表格 --><el-table:data="tableData"v-loading="loading":empty-text="'暫無數據'"v-bind="$attrs"><!-- :border="true" --><template v-for="column in tableColumn" :key="column?.label"><el-table-column v-if="column.cols" v-bind="{ ...column }"><!-- 列名合并,存在cols的情況下 --><template v-for="col in column.cols" :key="column?.label + col?.label"><el-table-column v-bind="{ ...col }"><template #default="scope"><!-- 自定義render --><span v-if="col?.render" :class="col?.class" :style="col?.style ? col.style : {}">{{ col?.render(scope.row[col.prop], scope.row) }}</span><!-- 自定義render component 將當前列的數據和這一整行的數據都傳給component函數 --><div v-else-if="col?.component" v-html="renderVNode(col.component(scope.row[col.prop], scope.row))"> </div><spanv-else:style="col?.style ? col.style : {}":class="col?.class":title="scope.row[col.prop]":data-message="scope.row[col.prop]">{{ scope.row[col.prop] }}</span></template></el-table-column></template></el-table-column><el-table-column v-else v-bind="{ ...column }"><template #default="scope"><!-- 自定義render字符串 當前列的數據和這一整行的數據都傳給render函數--><span v-if="column?.render" :style="column?.style ? column.style : {}" :class="column?.class">{{ column?.render(scope.row[column.prop], scope.row) }}</span><!-- 自定義render component 將當前列的數據和這一整行的數據都傳給component函數 --><div v-else-if="column?.component" v-html="renderVNode(column.component(scope.row[column.prop], scope.row))"></div><spanv-else:style="column?.style ? column.style : {}":class="column?.class":title="scope.row[column.prop]":data-message="scope.row[column.prop]">{{ scope.row[column.prop] }}</span></template></el-table-column></template></el-table>
</template><script lang="ts" setup name="customTable">const props = defineProps({tableData: {type: Array,default: () => [],},tableColumn: {type: Array<any>,default: () => [],},loading: {type: Boolean,default: false,},});const generateRandomString = (length) => {const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';const charactersLength = characters.length;let result = '';for (let i = 0; i < length; i++) {const randomIndex = Math.floor(Math.random() * charactersLength);result += characters.charAt(randomIndex);}return result;};
// 通過renderVNode 接收一個vnode節點來渲染component
const renderVNode = (vnode: VNode) => {const tempDiv = document.createElement('div');const parentDiv = document.createElement('div');const id = generateRandomString(10);parentDiv.appendChild(tempDiv);tempDiv.id = id;// 利用createApp和render將vnode掛載成一個新的appconst Comp = createApp({render: () => vnode,});// 將這個新的vue app 掛載到對應的dom上nextTick(() => {// 但要放置到nextTick里面,以防止dom還沒放置到table的對應位置,就先掛在了Comp.mount('#' + id);});// 返回一個html dom ,利用v-html掛載到table中對應的位置return parentDiv.innerHTML;};
</script >
如何使用
<template><custom-table maxHeight="100vh" :tableColumn="tableColumn" :tableData="tableData" />
</template><script lang="ts" setup name="test">
import componentTest from '../componentTest.vue';
import customTable from '../components/customTable.vue';
const tableColumn = ref([{label: '名稱',prop: 'name',align: 'center',minWidth: 130,fixed: true,component: (value, row) => {return h('div', { onClick: () => handleClick(row?.name) }, [h('span', { style: { fontSize: '14px', display: 'inline-block' } }, value),h('p', { class: 'dealer-scale' }, row?.scale),]);},},{label: '訂單',prop: 'order',component: (value, row) => {return h(componentTest, {title: value})},style: { color: '#C00017' },},{ label: '本年', prop: 'open', style: { color: '#C00017' } },{ label: '費效比', prop: 'efficiency', style: { color: '#038810' },render: (value,rows) => {console.log(value, rows)return value + '%'}},{ label: '處罰', prop: 'punish', style: { color: '#0000aa' } },]);const tableData = ref([// name order open efficiency punish scale{name: 'xxxx有限公司',order: '23455 萬',open: '234 萬瓶',efficiency: '1.3 %',punish: '3 次',scale: '10億以上',},{name: '軟件有限公司',order: '23456 萬',open: '234 萬瓶',efficiency: '1.3 %',punish: '3 次',scale: '5千萬~1億',},]);
</script>
tableColumn 屬性
屬性名 | 類型 | 解釋 |
---|---|---|
style | string | 能夠單獨配置某一列的樣式 |
class | string | 能夠單獨配置某一列的class名稱 |
render | function | 接受兩個參數 (value, row) value是當前行當前列的數據,row是當前行的數據 返回的值會渲染在table對應的列中 |
component | function | 接受兩個參數 (value, row) value是當前行當前列的數據,row是當前行的數據,返回一個vnode,通過vue3自帶的h函數實現 |
fixed | boolean | 是否讓當且列固定 |
… | … | … |
剩下的屬性 | … | 查看element ui 中table 的Column配置 https://element.eleme.io/#/zh-CN/component/table#table-column-attributes |
h函數
function h(type: string | Component, // 元素/組件類型props?: object | null, // 屬性/Propschildren?: VNodeChildren // 子節點(字符串、數組、插槽等)
): VNode
創建原生元素
import { h } from 'vue'// 等價于 <div class="box" id="app">Hello</div>
h('div', { class: 'box', id: 'app' }, 'Hello')// 帶事件
h('button', { onClick: () => console.log('Clicked!') }, 'Click me')
創建組件
import MyComponent from './MyComponent.vue'// 傳遞 props 和插槽
h(MyComponent, { title: 'Demo',onClick: () => {} // 監聽自定義事件
}, {default: () => h('span', '默認插槽'),footer: () => h('div', 'Footer 內容')
})
動態生成
const items = ['A', 'B', 'C']
h('ul', items.map(item => h('li', item))
)