解放前端工程师——手把手教你开发自己的自定义列表和自定义表单系列之三表格

Posted webmote

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解放前端工程师——手把手教你开发自己的自定义列表和自定义表单系列之三表格相关的知识,希望对你有一定的参考价值。

前言

阅读前请按照顺序参看系列文章,效果更佳!
Vue中路由到一个公共组件,然后根据路径中是否存在文件动态加载组件
解放前端工程师——手把手教你开发自己的自定义列表和自定义表单系列之一缘起
解放前端工程师——手把手教你开发自己的自定义列表和自定义表单系列之二接口
据说系列文章很难火爆,因为知识点包袱不够多,所以大家看往后不太愿意收藏, 不过没关系了, 系列文章的好处是看着舒服,碎片化时间内很快就看完了,不是吗?

1. Common 公共页面

前面几个小节已经阐述过,如果需要完成我们的低代码列表设计,那么必然会涉及到公共组件的设计。

1.1灵活的动态组件

我们设计了 CommonLayout 组件以完成公共的功能,当然它的内容非常少,仅仅是引入了 Component组件而已。

下面是摘自Vue文档介绍:

有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里,上述内容可以通过 Vue 的 元素加一个特殊的 is attribute 来实现:。

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>

在上述示例中,currentTabComponent 可以包括已注册组件的名字,或一个组件的选项对象。

由于这一个组件会对应多个路由,由于vue的优化,导致其created方法仅被调用一次。因此我们需要完成路由切换时的加载工作。

1.2 难堪的异步api调用

前节的实现有些问题,因为涉及到api的调用,这个异步的方法会导致更新页面时状态刷新并不那么及时,因此对上节的组件需要进行优化,以便其能够顺利加载数据。

  • 先控制显示,这里引入initCom变量,在未准备好之前先不显示组件。这样做会有少许时间页面空白~~~ 暂时未找到合适的方案;
<template>
  <div class="app-container">
    <keep-alive v-if="initCom">
      <component :is="realCompoonent" v-if="realCompoonent" :guid="guid" />
      <common-layout v-else :guid="guid" />
    </keep-alive>

  </div>
</template>
  • 再控制api请求,在路由切换前,加载列表定义模型数据,一旦加载完毕,再刷新vuex数据,并加载实际的组件
beforeRouteEnter(to, from, next) {
    next(vm => {
      vm.guid = vm.getGuid(to)
      if (vm.hasExpire(vm.udf, vm.guid)) {
        const http = new Http()
        http.fetch({
          url: `/Tools/GetModelDefine/${vm.guid}`,
          method: 'get',
        }).then(data => {
          vm.$store.dispatch('udf/setUdfModelData', { guid: vm.guid, data })
          vm.init(to)
        })
      } else {
        vm.init(to)
      }
    })
  },

init(route) {
      const path = route.path
      try {
        this.realCompoonent = require(`@/views${path}`).default
        // this.$router.push(this.realCompoonent)
      } catch (ex) {
        console.log(`load sub com [${path}] failed. ${ex}`)
        this.realCompoonent = null
      }
      this.initCom = true
    },

按照这样的修改,终于在页面刷新、菜单来回切换时表现正常了。

2.CommonLayout 组件

在没有定义 realCompoonent 组件页面时,我们会自动的使用 CommonLayout组件显示。

2.1 这个表格有点丑

其主要按照列表形式展现我们定义的表单,做好的效果如下:
在这里插入图片描述

2.2 模型元数据

其主要按照模型定义,进行解析并展现。
在这里插入图片描述
通过Common页面组件,我们已经顺利的拿到模型定义数据,并放在vuex内,因此本组件只需要拿到guid参数,然后到vuex内查询数据即可。

2.3 那我们就定义一个guid属性先。

export default {
  name: 'CommonLayout',
  mixins: [mixClass],
  props: {
    guid: { type: String, default: '' },
  },
  data() {
    return {}
  },
 }

2.4 引入 mapGetters 获取vuex数据。

import { mapGetters } from 'vuex'
...
computed: {
    ...mapGetters(['udf']),
    templateModel() {
      // console.log(this.udf.get(this.guid))
      return this.udf.get(this.guid)
    },
    showSummary() {
      const index = this.templateModel.listTemplate.findIndex(
        item => item.isSum == 1,
      )
      return index != -1
    },
  },

2.5 为了获取后台列表数据,我们引用mixins扩展类。

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。 更多合并规则,可以参考vue文档

在混入类,我们会按照约定规则调用分页数据api。

getlistApi(params) {
  const model = this.templateModel.model.modelName
  return this.$http.fetch({
    url: `/${model}/Get${model}Page`,
    method: 'post',
    params: params,
  })
},

2.6 同样的,为了保证数据的加载,我们监视$route

监视$rout,以便在created方法不被调用时刷新数据。

 watch: {
    $route: function(to, from) {
      this.reset()
      this.fetchData()
    },
  },

2.7 按照模型定义,我们显示或隐藏表格的序号和多选框列。

<el-table-column
v-if="templateModel.model.listShowSelect == 1"
 type="selection"
 width="55"
/>
<el-table-column
 v-if="templateModel.model.listShowNo == 1"
 type="index"
 align="center"
 width="50"
 label="#"
 :index="table_index"
/>

2.8 增加列表的排序功能以及合并功能

<el-table
      v-loading="listLoading"
      :data="list"
      element-loading-text="Loading"
      border
      fit
      highlight-current-row
      :show-summary="showSummary"
      :summary-method="getSummaries"
      @current-change="handleCurrentChange"
      @sort-change="sortList"
    >

2.9 列表合计功能

合并功能需要按照列设置进行显示,因此需要自定义getSummaries方法。实现的方法如下:

getSummaries(param) {
      const list = this.templateModel.listTemplate
      const { columns, data } = param
      const sums = []
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = '合计'
          return
        }

        if (column.property) {
          const item = list.find(o => o.fieldName.toLowerCase() == column.property.toLowerCase())
          console.log(item)
          if (item && item.isSum == 1) {
            const values = data.map(item => Number(item[column.property]))
            sums[index] = values.reduce((prev, curr) => {
              const value = Number(curr)
              if (!isNaN(value)) {
                return prev + curr
              } else {
                return prev
              }
            }, 0)
          // sums[index]
          }
        }
      })
      return sums
    },

2.10 列定义

按照模型的列表定义,拉取列,并显示。这里定义了宽度、列名、对齐、属性、以及对日期数据进行格式化。当然还可以按照控件类型进行扩展。

<el-table-column
        v-for="(item, index) in templateModel.listTemplate"
        :key="index"
        :label="$t(templateModel.model.modelName + '.' + item.fieldName)"
        :width="item.width <= 0 ? 0 : item.width"
        :align="item.controlType == 'Number' ? 'right' : 'left'"
        :sortable="item.isSort == 1 ? 'custom' : false"
        :prop="firstLower(item.fieldName)"
      >
        <template slot-scope="scope">
          <template v-if="item.controlType == 'Text'">
            {{ scope.row[firstLower(item.fieldName)] }}
          </template>
          <template v-else-if="item.controlType == 'DateTime'">
            {{ scope.row[firstLower(item.fieldName)] | formatDate }}
          </template>
          <template v-else>
            {{ scope.row[firstLower(item.fieldName)] }}
          </template>
        </template>
      </el-table-column>

2.11 分页组件也可以按照配置进行显示。

<el-pagination
      v-if="templateModel.model.listShowPage == 1"
      background
      layout="total, sizes, prev, pager, next, jumper"
      :page-sizes="[10, 20, 50, 100, 500]"
      :page-size="listQuery.limit"
      :total="total"
      @size-change="changeSize"
      @current-change="fetchPage"
      @prev-click="fetchPrev"
      @next-click="fetchNext"
    />

2.12 遗留的问题之一列名资源化

列名资源化是个问题,因为如果让前端不介入的话,那资源化的工作需要完全放在后端,定义好资源文件后,前端通过接口获取资源并自动合并到资源化词典内。

2.13 遗留的问题之二,按钮自定义

增删改查可以按照通用的定义一套,如果需要扩展新的按钮,那么之前设计的模型需要增加按钮元数据,这块尚在设计中,有时间再分享。

3.小结

列表的自定义大致功能基本已经实现了,通过这几次的介绍,你有没有学会呢?

在低代码项目设计中,列表自定义设计和表单自定义设计一般是绕不过的槛,如果你有更好的想法,可以留言。

以上是关于解放前端工程师——手把手教你开发自己的自定义列表和自定义表单系列之三表格的主要内容,如果未能解决你的问题,请参考以下文章

前端工具Chrome 扩展程序的开发与发布 -- 手把手教你开发扩展程序

----转载----前端工具Chrome 扩展程序的开发与发布 -- 手把手教你开发扩展程序

手把手教你使用Jetpack Compose完成你的自定义Layout

手把手教你使用Jetpack Compose完成你的自定义Layout

手把手教你开发一款1024程序员节日历提醒服务

手把手教你如何用eclipse搭建前端开发环境