在vue文件中使用render函数封装实现动态组件
近期遇到一个vue项目中的table页面,数据和模板强耦合在一个页面中,看起来比较复杂,维护较不方便,而该页面又重复性较高,于是尝试在vue中用循环渲染dom元素,抽离公共部分配置化,很不幸的是v-for并不支持动态的dom元素插入,那么怎么用vue实现动态dom元素节点的动态渲染呢。联想到react的实现方式,想到vue的render函数,vue中的render号称可以像react一样写页面,有
近期遇到一个vue项目中的table页面,数据和模板强耦合在一个页面中,看起来比较复杂,维护较不方便,而该页面又重复性较高,于是尝试在vue中用循环渲染dom元素,抽离公共部分配置化,很不幸的是v-for并不支持动态的dom元素插入,那么怎么用vue实现动态dom元素节点的动态渲染呢。
联想到react的实现方式,想到vue的render函数,vue中的render号称可以像react一样写页面,有了想法就开始实施。render函数是比较好理解的,但是在render中如何实现 插槽,事件点击,Scope, 以及如何在render中使用 开源库呢?
经过对vue编译之后虚拟dom的调研,这些都是可以实现的。
插槽和scope:可以直接写成 (scope)=> {}的形式
事件点击:nativeOnClick
开源库:事件变为 'on-' + ' ' 比如: on-selection-change
下面是一个DynamicTablePage实例:
<script>
export default {
name: 'DynamicTablePage',
props: {
msg: String,
tableParams: Array,
tableData: Array,
selections: Array,
layout: String,
pageSizes: Array,
handleSizeChange: Function,
handleCurrentChange: Function,
total: Number,
currentPage: Number,
hasPagination: Boolean,
handleSelectionChange: {
type: Function,
default: () => { }
},
paginationFixed: Boolean
},
data () {
return {
}
},
mounted () {
console.log(this.hasPagination)
},
methods: {
},
render (h) {
return <div class="jsx-component">
<el-table
data={this.tableData}
style={{ width: '100%' }}
class="test"
on-selection-change={this.handleSelectionChange}
>
{
this.tableParams.map((item, index) => {
return <el-table-column
prop={item.param}
label={item.title}
width={item.width}
key={index}
type={item.type}
allow-expand={item.allowExpand}
filters={item.filters}
align={item.align ? item.align : 'left'}
selections={this.multipleSelection}
filter-method={item.filterHandler}
>
{
item.template ? scope => item.template(scope, this, h) : ''
}
</el-table-column>
})
}
</el-table>
{
this.hasPagination ? <el-pagination
class={this.paginationFixed ? "fixed" : ''}
on-size-change={this.handleSizeChange}
on-current-change={this.handleCurrentChange}
current-page={this.currentPage}
page-sizes={this.pageSizes}
layout={this.layout}
total={this.total}>
</el-pagination> : null
}
</div >
}
}
</script>
<style scoped>
.jsx-component {
background: red;
}
.fixed {
position: fixed;
bottom: 0;
}
</style>
对应的配置文件:
let tableParams = [
{
title: '',
param: "",
width: '30px',
type: 'selection'
},
{
width: '30px',
type: 'expand',
test: {
name: 1
},
allowExpand (_row, index) {
return index !== 2;
},
// eslint-disable-next-line no-unused-vars
template: (_scope, _self, h) => {
return <div>测试</div>
}
},
{
title: '日期',
param: "date",
filters: [
{ text: '2018/12/01', value: '2018/12/01' },
{ text: '2018/12/02', value: '2018/12/02' },
{ text: '2018/12/03', value: '2018/12/03' },
{ text: '2018/12/04', value: '2018/12/04' },
{ text: '2018/12/05', value: '2018/12/05' },
{ text: '2018/12/10', value: '2018/12/10' }
],
filterHandler (value, row, column) {
console.log(value, row, column)
const property = column['property'];
return row[property] === value;
}
},
{
title: '字段2',
param: "date2",
template: (scope) => {
return scope.row.date2.replace(/[1-9]+/g, '000')
}
},
{
title: '字段3',
param: "date3",
// eslint-disable-next-line no-unused-vars
template: (scope, self, h) => {
return <div>
<el-button
icon="h-icon-edit"
size="mini"
nativeOnClick={() => {
self.$router.push({ name: 'PageTwo' })
}}
/>
</div>
}
}
]
export const tableData = () => {
return [
{
date: '2018/12/01',
date2: 'dfkjdfjk',
date3: '测试',
id: 0
},
{
date: '1221121221',
date2: 'dfkjdfjk',
date3: '测试',
id: 1
},
{
date: '1221121221',
date2: '1373698562',
date3: '测试',
id: 2
},
{
date: '1221121221',
date2: 'dfkjdfjk',
date3: '测试',
id: 3
}
]
}
export default tableParams
使用组件DynamicTablePage
<template>
<div class="example">
<h4>页面一</h4>
<DynamicTablePage
:tableParams="tableParams"
:tableData="tableData"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
:currentPage="currentPage"
:handleSizeChange="handleSizeChange"
:handleCurrentChange="handleCurrentChange"
:pageSizes="[100, 200, 300, 400]"
hasPagination
:handleSelectionChange="handleSelectionChange"
paginationFixed
></DynamicTablePage>
</div>
</template>
<script>
import DynamicTablePage from '../../components/DynamicTablePage'
import tableParams, { tableData } from './pageOne.config'
export default {
name: 'PageOne',
components: {
DynamicTablePage
},
data () {
return {
tableData: tableData(),
total: 1000,
selections: [],
tableParams: tableParams,
currentPage: 1
}
},
methods: {
handleSelectionChange (val) {
console.log(val)
this.multipleSelection = val;
},
handleSizeChange () {
},
handleCurrentChange (val) {
console.log(val)
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.example {
width: 800px;
margin: 0 auto;
height: auto;
}
</style>
该组件是对table的抽象,封装过后表格的每一列和数据都可以抽离为配置化,代码结构清晰,且有利于后期维护。如果有相同的页面,可以通过配置快速生成页面。
对于其他的功能,比如表单页面,展示页面等,都可以做类似的封装,从而达到效率和性能及维护的提升。
对于较为复杂组件的封装,还可以结合vuex,插件抽离实现。
更多推荐
所有评论(0)