前言
入职现在这家公司有几个月的时间了,前期主要做公司的业务,顺手给上一位前端老哥的代码做了一些优化,与其说是优化,其实这就是自己本身比较懒。写这篇文章的目的主要是记录一下自己根据项目的业务组成,对原有的重复代码(表单查询)进行封装,同时也为一些同学提供一下自己的封装思路。项目采用 Vue2 + element-ui + Jsx
安装JSX插件 Element-ui
install @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props babel-plugin-jsx-v-model element-ui -S
配置 .babelrc
{
"plugins": ["transform-vue-jsx", "transform-runtime", "jsx-v-model"]
}
首先看一下Jsx代码是啥样的
render() {
return (
//动态绑定样式
<div class={ 1 + 1 === 2 ? 'active' : ''}>
//循环生成多个元a素
{[1,2,3].map(elment=> <a> {element} </a> )}
</div>
)
}
关于 Jsx 的语法,可以自行去官网了解。
- 看看需要封装的页面长什么样,这种很常规的查询表格页面,也是后台管理类项目中用得最多的,非常建议进行封装,为接下来的开发节省时间,同时也让项目不那么臃肿。
页面中包含两个部分,表单+表格,我们先将表单查询抽离出来做成一个组件。
表单组件封装分析
- 一个表单可能会包含的input、select、time等各种输入组件,所以输入类型可配置。
- 根据不同的输入类型,传入不同的参数。
- 提交查询时,后台提供的键名valueKey可配置。综合我们的最基本的配置参数长这样:
{
type: 'input',
label: '消息标题:',
width: '200',
placeholder: '请输入标题',
valueKey: 'title'
}
表单组件内部具体实现
- 结合上面的配置参数,编写组件代码QueryComponent.vue:
<script>
export default {
name: "QueryComponent",
//接收option
props: {
option: {
type: Object,
required: true
}
},
data: () => ({
queryData: {} //定义queryData用来保存表单输入后的键值对
}),
//渲染函数
render() {
return <div>{this.renderHtml(this.option)}</div>;
},
methods: {
//接收参数,返回相应的Jsx
renderHtml(option) {
if (option.type === "input") {
return (
<el-form inline>
<el-form-item label={option.label} label-position="right">
<el-input
style={{ width: option.width + "px" }}
v-model={this.queryData[option.valueKey]}
placeholder={option.placeholder}
></el-input>
</el-form-item>
</el-form>
);
}
}
}
};
</script>
- 在页面引入组件
<template>
<div>
<QueryComponent :option="option" />
</div>
</template>
<script>
import QueryComponent from "@/components/QueryComponent.vue";
export default {
components: {
QueryComponent
},
data: () => ({
option: {
type: "input",
label: "消息标题:",
width: "260",
placeholder: "请输入标题",
valueKey: "title"
}
})
};
</script>
到这里我们实现了一个input框的创建,效果:
显然,这样子实现肯定时满足不了我们的需求的,要考虑到表单查询一定是多个的,所以 option 参数应该是一个数组才合理:
<template>
<div>
<QueryComponent :options="options" @submit="submit" :reset="reset" />
</div>
</template>
<script>
import QueryComponent from "@/components/QueryComponent.vue";
export default {
components: {
QueryComponent
},
data() {
return {
options: [
{
type: "input",
label: "消息标题:",
width: "260",
placeholder: "请输入标题",
valueKey: "title"
},
{
type: "select",
label: "消息类型:",
width: "260",
placeholder: "请选择类型",
valueKey: "messageType",
// select的options 一般是从后台获取的
selectOptions: [
{
label: "系统消息1",
value: "1"
},
{
label: "系统消息2",
value: "2"
}
]
}
]
};
},
methods: {
submit(queryData) {
console.log("submit", queryData);
//拿到queryData 进行查询
// await this.$http.get("/api/message/query", {
// params: this.queryData
// });
},
reset() {
console.log("reset", this.queryData);
}
}
};
</script>
接下来在组件内部处理传进来的数组
<script>
export default {
name: "QueryComponent",
//接收option
props: {
options: {
type: Array,
default: () => []
}
},
data: () => ({
queryData: {}, //定义queryData用来保存表单输入后的键值对
title: ""
}),
//渲染函数
render() {
return (
// 遍历options 根据option的type属性来渲染不同的组件 再加两个按钮 一个查询 一个重置
<div>
<el-form inline>
{this.options.map(option => this.renderHtml(option))}
<el-form-item>
<el-button type="primary" on-click={this.handleSubmit}>
查询
</el-button>
</el-form-item>
<el-form-item>
<el-button on-click={this.handleReset}>重置</el-button>
</el-form-item>
</el-form>
</div>
);
},
methods: {
//接收参数,返回相应的Jsx
renderHtml(option) {
// 对象配置(策略模式)实现不同输入框的渲染
const renderResult = {
input: () => (
<el-form-item label={option.label} label-position="right">
<el-input
style={{ width: option.width + "px" }}
v-model={this.queryData[option.valueKey]}
></el-input>
</el-form-item>
),
select: () => (
<el-form-item label={option.label} label-position="right">
<el-select
style={{ width: option.width + "px" }}
v-model={this.queryData[option.valueKey]}
>
{option.selectOptions.map(item => (
<el-option label={item.label} value={item.value}></el-option>
))}
</el-select>
</el-form-item>
)
};
return renderResult[option.type]();
},
// 点击查询按钮的时候触发父组件submit事件
handleSubmit() {
this.$emit("submit", this.queryData);
},
// 清空表单
handleReset() {
this.queryData = {};
this.$emit("reset");
}
}
};
</script>
于是有了以下的渲染结果:
结语
其实到这里也只是在涉及到了jsx在vue当中的一些简单使用,写这篇文章也只是记录一下自己一开始的思路,这也只是自己做封装的时的一个最基本的骨架,在项目中肯定还会有很多东西需要扩展,要考虑到的东西还有挺多的,不过都可以以此为基础做扩展。