抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

vue是一个数据驱动视图的前端框架,通过slot可实现父组件传递dom给子组件渲染,但是灵活性并没有jsx/tsx那么高,因此本文通过vue的template结合jsx/tsx,使用elementPlus组件库,实现配置动态渲染视图

一、模拟使用场景

1.my-table组件封装

my-table.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<el-table>
<el-table-column v-for="item in option" :key="item.prop" prop="item.prop" label="item.name">
<template #default="{row}">
<slot :name="item.prop" :row="row">
{{row[item.prop]}}
</slot>
</template>
</el-table-column>
</el-table>
</template>
<script setup lang="ts">
const props = defineProps<{
option: any
data: any
}>()
</script>

2.简单使用组件

index.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<my-table :option="option" :data="data"></my-table>
</template>
<script setup>
const option=[{
name:"Date",prop:"date"
},{
name:"Name",prop:"name"
},{
name:"Address",prop:"address"
}]

const data = [{
date:"2016-05-03",name:"Tom",address:"No. 189, Grove St, Los Angeles"
},{
date:"2016-05-02",name:"Tom",address:"No. 189, Grove St, Los Angeles"
},{
date:"2016-05-04",name:"Tom",address:"No. 189, Grove St, Los Angeles"
},{
date:"2016-05-01",name:"Tom",address:"No. 189, Grove St, Los Angeles"
}]
</script>

3.自定义某一列渲染样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<my-table :option="option" :data="data">
<template #name="{row}">
<strong>{{row.name}}</strong>
</template>
</my-table>
</template>
<script setup>
const option=[{
name:"Date",prop:"date"
},{
name:"Name",prop:"name"
},{
name:"Address",prop:"address"
}]

const data = [{
date:"2016-05-03",name:"Tom",address:"No. 189, Grove St, Los Angeles"
},{
date:"2016-05-02",name:"Tom",address:"No. 189, Grove St, Los Angeles"
},{
date:"2016-05-04",name:"Tom",address:"No. 189, Grove St, Los Angeles"
},{
date:"2016-05-01",name:"Tom",address:"No. 189, Grove St, Los Angeles"
}]
</script>

二、技术选择

1.问题痛点

虽然通过slot的方式可以自定义某一列的数据展示,但是当项目中多处使用,且经常只需要更改数据的格式化,这样的话使用slot显得比较麻烦了。

2.技术选择

动态渲染dom可以通过v-html或者render实现,而render可以渲染自定义组件且灵活性更高,因此优化思路为将数据展示格式化通过option来传递给my-table。

但自定义的my-table组件是template方式(相信大多数vue项目都是采用该方式),而template是不能渲染render的(基于vue3.2.20),因此需要考虑如何让template和render相结合。

三、实现

1.定义render-function组件

render-function.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { defineComponent, PropType, VNodeTypes } from 'vue';

export default defineComponent({
name: 'RenderFunction',
props: {
render: {
required: true,
},
},
render() {
return this.render;
},
});

2.修改my-table组件

my-table.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<el-table>
<el-table-column v-for="item in option" :key="item.prop" prop="item.prop" label="item.name">
<template #default="{row}">
<slot :name="item.prop" :row="row">

<template v-if="isFunction(item.formatValue)">
<render-function :render="item.formatValue(row)"/>
</template>

<template v-else>
{{row[item.prop]}}
</template>

</slot>
</template>
</el-table-column>
</el-table>
</template>
<script setup lang="ts">
import renderFunction from './render-function'
const props = defineProps<{
option: any
data: any
}>()
</script>

3.option增加自定义render即可

index.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
<my-table :option="option" :data="data"/>
</template>
<script setup>
import {h} from 'vue'

const option=[{
name:"Date",prop:"date"
},{
name:"Name",prop:"name",
formatValue:(row)=>{
return h('strong',row.name)
}
},{
name:"Address",prop:"address"
}]

const data = [{
date:"2016-05-03",name:"Tom",address:"No. 189, Grove St, Los Angeles"
},{
date:"2016-05-02",name:"Tom",address:"No. 189, Grove St, Los Angeles"
},{
date:"2016-05-04",name:"Tom",address:"No. 189, Grove St, Los Angeles"
},{
date:"2016-05-01",name:"Tom",address:"No. 189, Grove St, Los Angeles"
}]
</script>

4.使用自定义组件,例如el-tag

index.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<my-table :option="option" :data="data"/>
</template>
<script setup>
import {h} from 'vue'
import {ElTag} from 'element-plus'

const option=[{
name:"Date",prop:"date"
},{
name:"Name",prop:"name",
formatValue:(row)=>{
return h(ElTag,row.name)
}
},{
name:"Address",prop:"address"
}]

const data = [{
date:"2016-05-03",name:"Tom",address:"No. 189, Grove St, Los Angeles"
},{
date:"2016-05-02",name:"Tom",address:"No. 189, Grove St, Los Angeles"
},{
date:"2016-05-04",name:"Tom",address:"No. 189, Grove St, Los Angeles"
},{
date:"2016-05-01",name:"Tom",address:"No. 189, Grove St, Los Angeles"
}]
</script>

评论