
最近又遇到类似表格的界面,在很久以前我就做过了,其中的自定义内容,是使用render函数实现的。使用时的代码如下,总归看起来不够优雅。
column.render = (h, {value: {row}}) => { // 使用render函数自定义单元格内容
let vNode = [h("span", {}, row.mobile)];
if (!row.isShowMobile) {
vNode.push(h("i",
{
class: {
'iconfont-md': true,
'icon-xianshiyanjing-01': true
},
style: {
"margin-left": '8px'
},
on: {
click: () => { // 实现绑定数据
this.showPassword(1, row)
}
},
},
),)
}
return vNode;
}
结合JSX之后,直接写一个JSX即可。
// 这个代码片段是在computed里的
[{
label: "纳税人识别号",
key: "socialCreditCode",
jsxRight: { // 本来想传更多的参数进去,所以采用对象的形式
// 使用匿名函数保证this指向问题
jsx: () => {
return <f-button vOn:click={this.click}>{this.message}</f-button>
},
},
}]
那么现在我们看一下是怎么实现的。
配置环境
1.安装 JSX-babel
npm install @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props
2.增加配置babel.config.js
module.exports = {
presets: ['@vue/babel-preset-jsx'],
}
那么我们其他学习参考jsx-vue2(响应式,指令,事件等)
JSX转换器
在这里使用了render函数对JSX进行处理
<script>
export default {
name: "render-jsx",
props: {
jsx:{
type: Function
}
},
render(h) {
// 获取props里的jsx执行
return this.$props.jsx();
}
}
</script>
<style lang="less" scoped>
</style>
需要注意的是,我们在这里使用函数传递jsx,为什么这样做呢?因为可以使用匿名函数,控制变量的作用域。
使用一下
render-jsx.vue
<script>
export default {
name: "render-jsx",
props: {
jsx:{
type: Function
}
},
render(h) {
// 获取props里的jsx执行
return this.$props.jsx();
}
}
</script>
<style lang="less" scoped>
</style>
FButton.vue 用来模拟点击事件和判断是否可以使用单文件组件(SFC)
<template>
<div class="f-button" @click="click">
<slot></slot>
</div>
</template>
<script>
export default {
name: "FButton",
methods:{
click(){
this.$emit('click')
}
}
}
</script>
<style lang="less" scoped>
.f-button{
display: flex;
align-items: center;
color: skyblue;
border: 1px solid skyblue;
padding: 0 8px;
border-radius: 2px;
}
</style>
infoTable.vue
<template>
<div class="info-table" :class="{'in-table-border':isBorder}">
<div class="item__row" v-for="(item,index) in options" :key="index">
<div class="item__col" v-for="item2 in item" :key="item2.key">
<template v-if="item2">
<div class="item__col__init item__col__left">
<template v-if="item.jsxLeft">
<render-jsx :render="item.jsxLeft.jsx"></render-jsx>
</template>
<template v-else>
{{ item2.label }}
</template>
</div>
<div class="item__col__init item__col__right">
<template v-if="item2.jsxRight">
<render-jsx :jsx="item2.jsxRight.jsx"></render-jsx>
</template>
<template v-else>
{{ data[item2.key] }}
</template>
</div>
</template>
</div>
</div>
</div>
</template>
<script>
import RenderJsx from "./render-jsx";
export default {
name: "info-table",
components: {RenderJsx},
props: {
options: {
type: Array,
default: () => {
return []
}
},
isBorder: {
type: Boolean,
default: true
},
data: {
type: Object,
default() {
return {}
},
}
},
methods: {
click() {
console.log(this.options, this.data);
}
}
}
</script>
<style lang="less" scoped>
.item__row {
display: flex;
min-height: 36px;
box-sizing: border-box;
border-bottom: 1px var(--blue) solid;
flex-shrink: 0;
.item__col {
display: flex;
width: 100%;
word-wrap: break-word;
border: 1px solid darkslategray;
.item__col__init {
display: flex;
align-items: center;
padding: 12px;
overflow: hidden;
}
.item__col__left {
width: 125px;
flex-shrink: 0;
.item__col__left__label {
font-weight: bold;
}
}
.item__col__right {
flex-grow: 1;
flex-shrink: 1;
}
}
.item__col:last-child {
flex-grow: 1;
.item__col__right {
border-right: 0;
}
}
}
.item__row:nth-child(2n) {
background: var(--blue-3);
}
.item__row:last-child {
border-bottom: 0;
}
</style>
App.Vue
<script>
import infoTable from "./components/info-table";
import FButton from "../FButton";
export default {
components: {
infoTable,
FButton
},
data() {
return {
message: 'hello',
data: {
socialCreditCode: '1233',
companyName: '陈**',
taxTypes: '有',
registrationType: '个人',
registerTime: '2022-10',
businessScope: '个人经营',
industry: '计算机',
creditLevel: '1级',
legalPersonName: '陈'
},
};
},
render() {
return <info-table data={this.data} options={this.options}></info-table>;
},
methods: {
click() {
return console.log('hello');
}
},
computed: {
options() {
return [
[{
label: "纳税人识别号",
key: "socialCreditCode",
jsxRight: {
jsx: () => {
return <f-button vOn:click={this.click}>
<div>{this.message}</div>
</f-button>
},
},
}, {
label: "纳税人名称",
key: "companyName",
},
{}
],
[{
label: "纳税人资格",
key: "taxTypes",
}, {
label: "登记注册类型",
key: "registrationType",
}, {
label: "法人名称",
key: "legalPersonName",
}],
[{
label: "税务登记日期",
key: "registerTime",
}, {
label: "纳税信用等级",
key: "creditLevel",
}, {
label: "税务行业归属",
key: "industry",
}],
[{
label: "工商经营范围",
key: "businessScope",
}]
]
}
}
};
</script>