最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • El-table优化&列表生成器|项目复盘

    正文概述 掘金(TRexK)   2021-03-19   764

    前言

    工作中难免遇到重复劳动。每次对着 element-ui 中 的 el-table 一顿乱撸。为了避免重复劳动,代码生成器一定是一个不错的选择。附图。

    El-table优化&列表生成器|项目复盘

    el-table 优化

    在日常开发中难免对后台返回的数据进行一些处理。然而在使用 el-table-colume 的时候,经常使用 el-table-column 的插槽会增加最少一行代码,同时也会降低代码的阅读理解能力。通过对文档的研究发现发现 formatter 参数可以对值对象进行格式化。使用该参数可以提高数据处理的复用能力,同时也将省略slot插槽,提高代码的阅读流畅度。

    优化前

    
    <el-table-column prop="startTime" label="开始时间">
        <template slot-scope="{ row }">
            {{ row.startTime | dayjs('YYYY-MM-DD HH:mm:ss') }}
        </template>
    </el-table-column>
    
    // 封装优化代码
    export class ElTableUtil {
        // 日期格式化
        static dateFormatter(format = 'YYYY-MM-DD HH:mm:ss') {
            return (row, column, cellValue, index) => {
                if (!cellValue) return ''
                const _cellValue = _.castArray(cellValue || '')
                return _cellValue.reduce((total, str, index) => {
                    const tailIndicator = index === _cellValue.length - 1 ? '' : ' - '
                    return total + dayjs(str).format(format) + tailIndicator
                }, '')
            }
        }
        // 除法
        static divide(num: number, indicator = 2) {
            if (num === 0) throw new Error('ElementUI table 除法不能除0')
            return (row, column, cellValue, index) => {
                return (cellValue / num).toFixed(indicator)
            }
        }
        // 除以另外一个字段
        static divideBy(key: string, indicator = 2) {
            return (row, column, cellValue, index) => {
                if (!row[key] || row[key] === 0) return NaN
                return (cellValue / row[key]).toFixed(indicator)
            }
        }
        // 秒或毫秒转 => xx天xx小时
        // 数值 => 数值/100 + '%'
        // 数值 => 解析对应中文
    }
    

    优化后

    <!-- 日期格式化 -->
    <el-table-column prop="startTime" label="时间" :formatter="ElTableUtil.dateFormatter()" />
    <!-- 除法并限制小数点 -->
    <el-table-column prop="rate" label="XX率(%)":formatter="ElTableUtil.divide(1, 0)" />
    

    代码生成器

    最初想到这个东西的时候,后台开始启用 Swagger,前端开始使用 TypeScript 来进行项目开发。既然后端已经有了类型为何我们不把后端的类型拿来用呢?

    灵感

    通过对调查,发现 swagger 返回的 json 中会带有一些固定类型,比如枚举,字符串,数字等。通过对此json和类型的解析。可以自动生成 TypeScript 中的 type 类型。 代码生成器:Swagger Codegen

    // Swagger api 会返回类似的 json
    // QRCodeDTO 的 description 可以解析成页面的 title
    // 对象的 key 可以解析成 column 的 prop
    // description 可以解析成 column 的 label
    const swaggerJson = {
        "QRCodeDTO": {
          "type": "object",
          "properties": {
            "xxId": { "type": "string", "description": "xxid" },
            "XXXId": { "type": "string", "description": "XXXid" },
            "XXXXId": {
              "type": "string",
              "description": "XXXXid",
              "required": true
            }
          },
          "title": "QRCodeDTO",
          "description": "生成QRCODE用的数据"
        }
    }
    // 通过 代码生成器 可转化为
    type Check = {
        'xxId' ? : string
        'XXXId' ? : boolean
        'XXXXId' : string
    };
    

    生成器

    建议先大致看一下模板引擎 [EJS](https://ejs.bootcss.com/) 的语法。不然应该不好看明白。
    

    既然可以生成 typescript 为什么不直接生成页面呢。自动写代码何乐而不为!采用 ejs 作为模板引擎。 首先做json转列表的解析,对特定字段进行正则匹配,然后解析成对应的组件。

    字段解析成组件模板

    <% if (/.*img.*/.test(_.lowerCase(item.id)) || /.*image.*/.test(_.lowerCase(item.id))) {%> 
        <el-table-column label="<%= item.description || item.id %>" prop="<%= item.id %>" show-overflow-tooltip align="center">
            <template slot-scope="scope">
                <el-img :value="scope.row.<%= item.id %>" />
            </template>
        </el-table-column>
    <% } else if (/.*id.*/.test(_.replace(_.lowerCase(item.id), ' ', '')) && item.id != 'id') { %> 
        <el-table-column label="<%= item.description || item.id %>" prop="<%= item.id %>" show-overflow-tooltip :formatter="ElTableUtil.get('<%= item.id %>_name')" align="center" />
    <% } else if (/.*status.*/.test(_.replace(_.lowerCase(item.id), ' ', ''))) { %> 
        <el-table-column label="<%= item.description || item.id %>" prop="<%= item.id %>" show-overflow-tooltip align="center">
            <template slot-scope="scope">
                <el-tag type="default|success|info|warning|danger">{{ scope.row.<%= item.id %> }}</el-tag>
            </template>
        </el-table-column>
    <% } else if (/.*time.*/.test(_.lowerCase(item.id))) {%> 
        <el-table-column label="<%= item.description || item.id %>" prop="<%= item.id %>" show-overflow-tooltip :formatter="ElTableUtil.dateFormatter()" align="center"/>
    <% } else if (item.type == 'number') {%> 
        <el-table-column label="<%= item.description || item.id %>" prop="<%= item.id %>" show-overflow-tooltip :formatter="ElTableUtil.divide(1)" align="center"/>
    <% } else if (item.type == 'boolean') {%> 
        <el-table-column label="<%= item.description || item.id %>" prop="<%= item.id %>" show-overflow-tooltip :formatter="ElTableUtil.boolean('是','否')" align="center"/>
    <% } else if (item.type == 'string' && item.enum) {%> 
        <el-table-column label="<%= item.description || item.id %>" prop="<%= item.id %>" show-overflow-tooltip :formatter="ElTableUtil.enum('')" align="center"/>
    <% } else { %>
        <el-table-column label="<%= item.description || item.id %>" prop="<%= item.id %>" show-overflow-tooltip align="center" />
    <% } %>
    
    

    字段解析查询框模板

    <%  if (/.*org.*/.test(_.replace(_.lowerCase(item.id), ' ', ''))) {%> 
       
    <% } else if (/.*time.*/.test(_.replace(_.lowerCase(item.id), ' ', '')) || /.*date.*/.test(_.replace(_.lowerCase(item.id), ' ', ''))) {%> 
        <el-date-picker v-model="condition.<%= item.id %>" value-format="timestamp" type="daterange" :default-time="['00:00:00', '23:59:59']"> </el-date-picker>
    <% } else if (item.type == 'boolean') {%> 
        <el-select v-model="condition.<%= item.id %>" clearable>
            <el-option label="是" :value="true" />
            <el-option label="否" :value="false" />
        </el-select>
    <% } else if (item.type == 'integer') {%> 
        <el-input-number v-model="condition.<%= item.id %>" :min="1" :max="10" label="<%= item.description %>"></el-input-number>
    <% } else if (item.type == 'string' || item.type == 'number') { %> 
        <el-input v-model.trim="condition.<%= item.id %>" clearable/>
    <% } else {%>
        <!-- 不知道是啥 -->
        <component v-model="condition.<%= item.id %>" />
    <% } %> 
    

    页面解析模板

    <template>
        <page-list>
             <!-- 查询条件 -->
            <template slot="search">
                <% conditions.forEach(condition => {  %>
                    <el-form-item label="<%= condition.description || condition.id %>">
                        <%= formatEdit({item: condition}) %>
                    </el-form-item>
                <% }) %> 
            </template>
             <!-- 列表部分 -->
            <template slot="list">
                <% list.children.forEach(item => {  %>
                    <%= formatlist({item: item}) %>
                <% }) %> 
                <el-table-column label="操作" width="130" fixed="right">
                    <template #default="{ row }">
                        <el-button icon="el-icon-s-check" type="text"   @click="handleEdit(row.id)" />
                    </template>
                </el-table-column>
            </template>
        </page-list>
    </template>
    

    解析

    import { saveAs } from 'file-saver'
    // condition 和 list 均为swagger 返回后的json
    const gendata = { conditions: this.selectNode?.children?.filter(e => e.search) || [], list: this.selectNode }
    // model, search, list, pagelist 均为 ejs 模板
    let fn = ejs.render(`<%- pagelist({conditions:conditions,list:list,formatlist:formatlist,formatEdit:formatEdit,formatModel:formatModel})%>`, {
                formatModel: model,
                formatEdit: search,
                formatlist: list,
                pagelist: pagelist,
                ...gendata
            })
    const file = new File([fn], 'hello world.txt', { type: 'text/plain;charset=utf-8' })
    // 页面解析模板,解析的结果
    saveAs(file, _.kebabCase(this.selectNode.label) + '.vue') 
    

    总结

    通过对 swagger 生成 json 的解析,我们可以利用模板引擎一键生成标准模板页面。通过 file-saver 一键下载到本地。不过缺点也是显而易见的,后端没有对应swagger对象的时候。我们还是无能为力的,需要后端先行确认数据结构。

    文章末尾请带上以下文字及链接:本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情


    起源地下载网 » El-table优化&列表生成器|项目复盘

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元