简单及又舒服的前端低代码

低代码不只是少写代码而已:代码写得少,bug也就越少(正所谓“少做少错”),因此开发环节的两大支柱性工作“赶需求”和“修bug”就都少了;要测的代码少了,那么测试用例也可以少写不少

1.提高开发效率 2.减少开发成本 3.维护性更高

后台管理系统中频繁出现列表,普通开发代码重复且枯燥,而且可读性差密密麻麻的 一个列表页写上小千行
我们需要解决这个问题,达到方便便捷切代码统一 ,维护方便。

在这里插入图片描述

这是一个普通的列表页 在后台管理系统中这种页面数不胜数
这里以element为例 我想法是二次封装组件,将整个页面看成一个大组件,组件中分为三个模块,一个filterHeader、Xtabel(包含footer分页)、
附加代码

<template>
<div class="x-table">
    <el-table border ref="multipleTable" :data="tableData" tooltip-effect="dark" style="width: 100%" @select="handleSelectRow" @select-all="handleSelectAll" @selection-change="handleSelectionChange" @filter-change="handleFilterChange">
       
        <el-table-column type="selection" width="55" v-if="isSelection"></el-table-column>
        <el-table-column v-for="item in columns" :key="item.label" :label="item.label" :prop="item.prop" :width="item.width ? item.width : ''" :column-key="item.label" :filter-multiple='!item.fitersType' :filters="item.filters" filter-placement="" :fixed="item.fixed">
            <template slot-scope="scope">
                <template class="operate-btn" v-if="item.operates">
                    <el-button size="mini" v-for="btn in item.operates" :key="btn.event" :type="btn.type ? btn.type : ''" v-permission="btn.permission" v-show="showBtn(scope.row.isShow, btn.text)" @click="handleRowOperate(scope.$index, scope.row, btn.event,btn.text)">{{btn.text}}</el-button>
                </template>
                <template v-else>
                    <el-input class="edit-input" size="small" v-model="scope.row[item.prop]" v-if="item.cellEdit === 'input'" />
                    <el-cascader v-else-if="item.cellEdit==='cascader'" @change='changeel($event, scope.row, item.prop)' :options="scope.row.serverUserList" v-model='scope.row.echoUserList' :props="props" clearable></el-cascader>

                    <el-select placeholder="请选择" v-model="scope.row[item.prop]" @change="handleCellChange($event, scope.row, item.prop)" @focus="handleCellFocus($event, scope.row, item.prop)" v-else-if="item.cellEdit === 'select'">
                        <el-option v-for="(options,index) in item.options" :key="index" :label="options.label" :value="options.value">
                        </el-option>
                    </el-select>
                    <el-date-picker v-model="scope.row[item.prop]" type="date" value-format="yyyy-MM-dd" placeholder="请选择时间" v-else-if="item.cellEdit === 'date'" />
                    <img v-else-if="item.cellEdit === 'img'" :src="scope.row[item.prop]" alt="" style="width:80px;height:80px;" />
                    <span v-else>{{ scope.row[item.prop] }}</span>
                    <slot :name="scope.row['slot']" v-if="item.prop === scope.row['slot']"></slot>
                </template>
            </template>
        </el-table-column>
    </el-table>
</div>
</template>

<script>
// import Sortable from 'sortablejs'
export default {
    name: "x-table",
    data() {
        return {
            props: {
                multiple: true
            },
        };
    },
    props: {
        showSelect: {
            type: Boolean,
            default: false
        },
        isSelection: {
            type: Boolean,
            default: false
        },
        tableData: {
            type: Array,
            default: function () {
                return [
                    // {
                    //   id: "1",
                    //   userName: '12345',
                    // },
                    // {
                    //   id: "2",
                    //   userName: '12345',
                    // },
                    // {
                    //   id: "3",
                    //   userName: '12345',
                    // }
                ]
            }
        },
        columns: {
        	type:Array,
        	 default: function () {
                return [
                     {
                    label: '用户名',//表格头
                    prop: 'userName'//绑定的字段
                },
                {
                    label: '用户id',
                    prop: 'id'
                },
                ]
            }
        }
    },
    created() {},
  
    components: {},
    mounted() {},
    methods: {
        // 除权限外的特殊显示隐藏需求
        showBtn(show, text) {
            if (show === 0) {
                return text !== '审批' && text !== '收款'
            } else {
                return true
            }
        },
        // 列筛选条件
        handleFilterChange(filterObj) {
            this.$emit('filter', filterObj)
        },
        // 选择行
        handleSelectionChange(val) {
            this.$emit('select', val)
            // console.log(val)
        },
        handleSelectRow(selection, row) {
            this.$emit('row-select', selection, row)
        },
        handleSelectAll(val) {
            this.$emit('all-select', val)
        },
        // 操作行
        handleRowOperate(index, row, event, text) {
            // console.log(text);
            // console.log(text);
            // console.log(text);

            this.$emit('edit', event, row, index, text)
            // this.$router.push('/order-detail/index')
        },
        // 操作格子
        handleCellFocus(val, row, prop) {
            this.$emit('handleCellFocus', val, row, prop)
        },
        handleCellChange(val, row, prop) {
            // console.log(val, row)
            this.$emit('cellChange', val, row, prop)
        },
        changeel(val, row, prop) {
            // console.log(val, row)
            this.$emit('changeel', val, row, prop)
        },
        toggleRowSelection(row) {
            console.log('测试', row)
            this.$refs.multipleTable.clearSelection();
            this.tableData.forEach(row => {
                if (row.select == 1) {
                    this.$refs.multipleTable.toggleRowSelection(row);
                }
            })
        },
        rowDrop() {
            const tbody = document.querySelector('.el-table__body-wrapper tbody')
            const _this = this
            Sortable.create(tbody, {
                onEnd({
                    newIndex,
                    oldIndex
                }) {
                    const currRow = _this.tableData.splice(oldIndex, 1)[0]
                    _this.tableData.splice(newIndex, 0, currRow)
                }
            })
        },
        // columnDrop() {
        //   const _this = this
        //   const wrapperTr = document.querySelector('.el-table__header-wrapper tr')
        //   this.sortable = Sortable.create(wrapperTr, {
        //     animation: 180,
        //     delay: 0,
        //     onEnd: evt => {
        //       console.log(evt)
        //       const oldItem = this.columns[evt.oldIndex]
        //       this.columns.splice(evt.oldIndex, 1)
        //       this.columns.splice(evt.newIndex, 0, oldItem)
        //     }
        //   })      
        // }
    }
};
</script>

<style scoped>
.x-table {
    /* max-width: 70%; */
}

.demo-table-expand {
    font-size: 0;
}

.demo-table-expand label {
    width: 90px;
    color: #99a9bf;
}

.demo-table-expand .el-form-item {
    margin-right: 0;
    margin-bottom: 0;
    width: 35%;
}
</style>
<template>

<!-- filterHeader 组件 -->
  <el-form :inline="true" class="demo-form-inline">
    <el-form-item :label="item.label" 
      v-for="item in filterOptions" 
      :key="item.label"
      >
      <el-input 
        v-model="item.value" 
        :placeholder="item.placeholder" 
        v-if="item.type === 'input'" />
      <el-select 
        v-model="item.value" 
        :placeholder="item.placeholder" 
        :filterable="item.filterable"
        @change="onItemChange($event, item.label)"
        v-if="item.type === 'select'">
        <el-option 
          v-for="options in item.options" 
          :key="options.label"
          :label="options.label" 
          :value="options.value" />    
      </el-select>
      <el-date-picker
        v-model="item.value"
        type="date"
        value-format="yyyy-MM-dd"
        :placeholder="item.placeholder"
        v-if="item.type === 'date'" />
      <el-date-picker
        v-model="item.value"
        type="month"
        value-format="yyyy-MM"
        :placeholder="item.placeholder"
        v-if="item.type === 'month'" />
      <el-date-picker
        v-model="item.value"
        type="daterange"
        range-separator="—"
        value-format="yyyy-MM-dd"
        start-placeholder="开始时间"
        end-placeholder="结束时间"
        v-if="item.type === 'daterange'" />  
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="onFilter">查询</el-button>
      <el-button @click="onReset">重置</el-button>
    </el-form-item>
  </el-form>
</template>

<script>
export default {
  name: 'filter-header',
  data () {
    return {
    }
  },
  props: {
    filterOptions: Array
  },
  components: {},
  mounted () { 
  },
  methods: {
    onFilter() {
      this.$emit('filter')
    },
    onReset() {
      this.$emit('reset')
    },
    onItemChange(val, prop) {
      this.$emit('item-change', val, prop)
    }
  },
}
</script>

<style scoped>
</style>
<template>
<div class="order">
    <filter-header v-if="filterOptions && filterOptions.length" :filterOptions="filterOptions" @item-change="onFilterItemChange" @filter="onConditionalQuery" @reset="onConditionalReset" />
    <el-row type="flex" justify="end" class="order-operate">
        <!-- <el-button type="primary" @click="onDownload" >下载</el-button>
      <el-button type="primary" @click="onPrint">打印</el-button>-->
        <el-button :loading="isExporting" type="primary" @click="onExport">导出</el-button>
        <el-button type="primary" @click="onAdd" >添加</el-button>
    </el-row>
    <x-table :showSelect="showSelect2" :columns="columns" :tableData="tableData" @changeel='changel' @edit="onItemEdit" @filter="onColumnsFilter" @cellChange="onCellChange" @handleCellFocus="handleCellFocus" />
    <el-row type="flex" justify="end" class="pagination-wrap">
       
        <el-pagination background layout="prev, pager, next" :current-page.sync="currentPage" :total="totalSize" @current-change="onPageChange" />
    </el-row>
</div>
</template>

<script>
import FilterHeader from "@/components/FilterHeader";
import XTable from "@/components/XTable";
export default {
    data() {
        return {
            currentPage: 1,
            isSelection: true,
            radio: null
        };
    },
    props: {
        showSelect2: {
            type: Boolean,
            default: false
        },
      
       
        isExport: {
            type: Boolean,
            default: true,
        },
        isRadio: {
            type: Boolean,
            default: false,
        },
     
        isExporting: {
            type: Boolean,
            default: false,
        },
        totalSize: Number,
        filterOptions: Array,
        columns: Array,
        tableData: Array,
        tableOperate: Array,
    },
    components: {
        FilterHeader,
        XTable,
    },
    created() {},
    methods: {
       
        tohelp() {
            this.$emit('toHelp', '')
        },
        radioChange(val) {
            console.log(val)
            this.$emit("radioChange", val);
        },
        handleCellFocus(val, row) {
            this.$emit("handleCellFocus", val, row);
        },
        onCellChange(val, row, prop) {
            console.log(row);
            this.$emit("cell-change", val, row, prop);
        },
        changel(val, row, prop) {
            this.$emit("changel", val, row, prop);
        },
        onFilterItemChange(val, prop) {
            this.$emit("filter-item-change", val, prop);
        },
        onConditionalQuery() {
            this.$emit("conditional-query");
        },
        onConditionalReset() {
            this.$emit("conditional-reset");
        },
        onColumnsFilter(val) {
            this.$emit("columns-filter", val);
            console.log("列筛选", val);
        },
        onItemEdit(event, row, index, text) {
            // console.log(text);
            this.$emit(event, row, index, text);
        },
        onPageChange(page) {
            this.$emit("page-change", page);
        },
        onDownload() {
            console.log("download");
        },
        onPrint() {
            console.log("print");
        },
        onExport() {
            this.$emit("export");
        },
        onSetting() {
            this.$router.push({
                name: "table-setting",
                query: {
                    formType: this.formType
                },
            });
        },
        onAdd() {
            this.$emit("add");
            console.log("add");
        },
    },
};
</script>

<style scoped>
.order-operate {
    margin-bottom: 30px;
}

.pagination-wrap {
    margin-top: 30px;
}
</style>

最后是完整的tabelPage的代码
一套操作下来以后每个列表页只需要两分钟搞定 方便快捷
再配合 mixin混入下复用新高的函数(比如:分页 查询 重置 getlist 直接就想起来了)


版权声明:本文为weixin_46744852原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。