整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

前端工具:常用的Web前端ui框架汇总

前端工具:常用的Web前端ui框架汇总

lementui应该是大家用的最多的和最常见最稳定的ui框架,那么除了elementui还有哪些好用的框架呢?

1.amazeui(妹子 UI) 中国首个开源 HTML5 跨屏前端框架

Amaze UI 以移动优先(Mobile first)为理念,从小屏逐步扩展到大屏,最终实现所有屏幕适配,适应移动互联潮流。
官网地址:
http://amazeui.shopxo.net/javascript/modal/

2.WeUI 适配于微信小程序的ui框架

WeUI 是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信内网页和微信小程序量身设计,令用户的使用感知更加统一。
官网地址:
https://weui.io/#button_default

3.MintUI 是基于Vue.js移动组件库

// 安装
# Vue 1.x
npm install mint-ui@1 -S
# Vue 2.0
npm install mint-ui -S


// 引入全部组件
import Vue from 'vue';
import Mint from 'mint-ui';
Vue.use(Mint);
// 按需引入部分组件
import { Cell, Checklist } from 'mint-ui';
Vue.component(Cell.name, Cell);
Vue.component(Checklist.name, Checklist);

官网地址:
http://mint-ui.github.io/docs/#/

4.LayUI 兼容人类正在使用的全部浏览器(IE6/7 除外),可作为 Web 界面速成开发方案。

基于浏览器端原生态模式,面向全层次的前后端开发者,易上手且开源免费的 Web 界面组件库
官网地址:
https://layuion.com/docs/

5.iviewUI

基于Vue.js的一个UI框架,主要用PC端,组件比ElementUI更丰富。View Design基于 Vue.js 3 的企业级 UI 组件库和前端解决方案,
为数万开发者服务。
官网地址:
https://www.iviewui.com/

6.Naive UI Vue3+TypeScript组件库

Naive UI 是一个 Vue3 的组件库。全量使用 TypeScript 编写,和你的 TypeScript 项目无缝衔接。有超过 80 个组件,希望能帮你少写点代码。顺便一提,它们全都可以 treeshaking。尽力让它不要太慢。至少 select、tree、transfer、table、cascader 都可以用虚拟列表,整体使用感受还是很好的,全局配置化,减少很多无用代码。
官网地址:
https://www.naiveui.com/zh-CN/os-theme/docs/introduction

7.Ant Design Pro

一个由蚂蚁金服开源出来的企业级后台前端UI框架,目前有Vue和React等版本。使用感受:react版本比vue版本好用稳定,vue版本可能是改造的原因,用起来有一些不方便,包括tree的虚拟加载都没有更新,react版本比较丰富,这个组件推荐配合react使用。
vue版本官网地址:
https://2x.antdv.com/components/form-cn/
react版本官网地址:
https://ant.design/components/button-cn/

8.Ionic Native 基于AngularJS框架的Javascript UI框架

用于移动端开发,学习成本较高,版本好多,选择的时候需要慎重,各种适配的版本,Ionic 是一个轻量的手机 UI 库,具有速度快,界面现代化、美观等特点。为了解决其他一些 UI 库在手机上运行缓慢的问题。
官网地址:
http://www.ionic.wang/native_doc-index.html

9.Uni-app

uni-app 是一个使用 Vue.js (opens new window)开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台,如果要做微信小程序uni-app配合微信开发者文档还是蛮香的,另一篇文章有具体入门进阶介绍。
官网地址:
https://uniapp.dcloud.net.cn/

以上就是今天的分享,希望对大家有帮助哦!

容摘要:

  • 需求分析
  • 定义 interface
  • 定义 json 文件
  • 定义列表控件的 props
  • 基于 el-table 封装,实现依赖 json 渲染
  • 实现内置功能:选择行(单选、多选),格式化、锁定等。
  • 使用 slot 实现自定义扩展
  • 做个工具维护 json 文件(下篇介绍)

管理后台里面,列表是一个常用的功能,UI库提供了列表组件和分页组件实现功能。虽然功能强大,也很灵活,只是还不能称为低代码,不过没关系,我们可以写点代码让UI库变为摸鱼神器!

本篇介绍列表的设计思路和封装方式。

需求分析

如果基于原生HTML来实现显示数据列表的功能的话,那么需考虑如何创建 table,如何设置css等。
如果直接使用UI库的话,那么可以简单很多,只需要设置各种属性,然后绑定数据即可。
以 el-table 为例:

  <el-table
    :data="tableData"
    border
    stripe
    style="width: 100%"
  >
    <el-table-column prop="date" label="Date" width="180" />
    <el-table-column prop="name" label="Name" width="180" />
    <el-table-column prop="address" label="Address" />
  </el-table>

设置好属性、记录集合,然后设置列(el-table-column)即可。
这样一个列表就搞定了,再加上 el-pagination 分页组件,编写一些代码即可实现分页的功能。

如果只是一个列表的话,这种方式没啥问题,但是管理后台项目,往往需要n个列表,而每个列表都大同小异,如果要一个一个手撸出来,那就有点麻烦了。

那么如何解决呢?我们可以参考低代码,基于 el-talbe 封装一个列表控件,
实现依赖 json 动态渲染列表,同时支持自定义扩展。

定义 interface

最近开始学习 Typescript,发现了一个现象,如果可以先定义好类型,那么代码就可以更清晰的展现出来。

另外 Vue3 的最新文档,也采用了通过 interface 来介绍API功能的方式,所以我们也可以借鉴一下。

依据 el-table 的属性,定义列表控件属性的 interface。

Vue3 的 props 有一套约束方式,这个似乎和TS的方式有点冲突,没想出了更好的方法(option API 和 script setup两种定义props的方式,都有不足 ),所以只好做两个 interface,一个用于定义组件的 props ,一个用于取值。

  • IGridPropsComp:定义组件的 props
/**
 * 列表控件的属性的描述,基于el-table
 */
export interface IGridPropsComp {
  /**
   * 模块ID,number | string
   */
  moduleId: IPropsValidation,
  /**
   * 主键字段的名称 String,对应 row-key
   */
  idName: IPropsValidation,
  /**
   * table的高度, Number
   */
  height: IPropsValidation,
  /**
   * 列(字段)显示的顺序 Array<number|string>
   */
  colOrder: IPropsValidation,
  /**
   * 斑马纹,Boolean
   */
  stripe: IPropsValidation,
  /**
   * 纵向边框,Boolean
   */
  border: IPropsValidation,
  /**
   * 列的宽度是否自撑开,Boolean
   */
  fit: IPropsValidation,
  /**
   * 要高亮当前行,Boolean
   */
  highlightCurrentRow: IPropsValidation,
  /**
   * 锁定的列数 Number,设置到 el-table-column 的 fixed
   */
  fixedIndex: IPropsValidation,
  /**
   * table的列的 IGridItem
   * * id: number | string,
   * * colName: string, 字段名称
   * * label: string, 列的标签、标题
   * * width: number, 列的宽度
   * * align: EAlign, 内容对齐方式
   * * headerAlign: EAlign 列标题对齐方式
   */
  itemMeta: IPropsValidation, // 
  /**
   * 记录选择的行:IGridSelection
   * * dataId: '', 单选ID number 、string
   * * row: {}, 单选的数据对象 {}
   * * dataIds: [], 多选ID []
   * * rows: [] 多选的数据对象 []
   */
  selection: IPropsValidation, 
    
  /**
   * 绑定的数据 Array, 对应 data
   */
  dataList: IPropsValidation

  // 其他扩展属性
  [propName: string]: IPropsValidation

}
  • moduleId:模块ID,一个模块菜单只能有一个列表,菜单可以嵌套。
  • itemMeta:列的属性集合,记录列表的列的属性。
  • selection:记录列表的单选、多选的 row。
  • dataList:显示的数据,对应 el-table 的 data
  • 其他:对应 el-table 的属性

IGridPropsComp 的作用是,约束列表控件需要设置哪些属性,属性的具体类型,就无法在这里约束了。

  • IPropsValidation (不知道vue内部有没有这样的 interface)
/**
 * vue 的 props 的验证的类型约束
 */
export interface IPropsValidation {
  /**
   * 属性的类型,比较灵活,可以是 String、Number 等,也可以是数组、class等
   */
  type: Array<any> | any,
  /**
   * 是否必须传递属性
   */
  required?: boolean,
  /**
   * 自定义类型校验函数(箭头函数),value:属性值
   */
  validator?: (value: any)=> boolean,
  /**
   * 默认值,可以是值,也可以是函数(箭头函数)
   */
  default?: any
}

取 props 用的 interface

IGridPropsComp 无法约束属性的具体类型,所以只好再做一个 interface。

  • IGridProps
/**
 * 列表控件的属性的类型,基于el-table
 */
 export interface IGridProps {
  /**
   * 模块ID,number | string
   */
  moduleId: number | string,
  /**
   * 主键字段的名称 String,对应 row-key
   */
  idName: String,
  /**
   * table的高度, Number
   */
  height: number,
  /**
   * 列(字段)显示的顺序 Array<number|string>
   */
  colOrder: Array<number|string>,
  /**
   * 斑马纹,Boolean
   */
  stripe: boolean,
  /**
   * 纵向边框,Boolean
   */
  border: boolean,
  /**
   * 列的宽度是否自撑开,Boolean
   */
  fit: boolean,
  /**
   * 要高亮当前行,Boolean
   */
  highlightCurrentRow: boolean,
  /**
   * 锁定的列数 Number,设置到 el-table-column 的 fixed
   */
  fixedIndex: number,
  /**
   * table的列的 Object< IGridItem >
   * * id: number | string,
   * * colName: string, 字段名称
   * * label: string, 列的标签、标题
   * * width: number, 列的宽度
   * * align: EAlign, 内容对齐方式
   * * headerAlign: EAlign 列标题对齐方式
   */
  itemMeta: {
    [key:string | number]: IGridItem
  }, // 
  /**
   * 选择行的情况:IGridSelection
   * * dataId: '', 单选ID number 、string
   * * row: {}, 单选的数据对象 {}
   * * dataIds: [], 多选ID []
   * * rows: [] 多选的数据对象 []
   */
  selection: IGridSelection, 
    
  /**
   * 绑定的数据 Array, 对应 data
   */
  dataList: Array<any>

  // 其他扩展属性
  [propName: string]: any
}

对比一下就会发现,属性的类型不一样。因为定义 props 需要使用一套特定的对象格式,而使用 props 的时候需要的是属性自己的类型。

理想情况下,应该可以在 script setup 里面,引入外部文件 定义的 interface ,然后设置给组件的 props,但是到目前为止还不支持,只能在( script setup方式的)组件内部定义 props。希望早日支持,支持了就不会这么纠结和痛苦了。

依据 el-table-column 定义列属性的 interface。

  • IGridItem:列表里面列的属性
/**
 * 列的属性,基于 el-table-column
 */
export interface IGridItem {
  /**
   * 字段ID、列ID
   */
  id: number | string,
  /**
   * 字段名称
   */
  colName: string,
  /**
   * 列的标签、标题
   */
  label: string,
  /**
   * 列的宽度
   */
  width: number,
  /**
   * 内容对齐方式 EAlign
   */
  align: EAlign,
  /**
   * 列标题对齐方式
   */
  headerAlign: EAlign,

  // 其他扩展属性
  [propName: string]: any
}

还是需要扩展属性的,因为这里只是列出来目前需要的属性,el-table-column 的其他属性、方法还有很多,而且以后也可能会新增。

这个属性不是直接设置给组件的 props,所以不用定义两套了。

对齐方式的枚举

枚举可以理解为常量,定义之后可以避免低级错误,避免手滑。

  • EAlign
export const enum EAlign {
  left='left',
  center='center',
  right='right'
}

选择记录的 interface。

列表可以单选也可以多选,el-table 在默认情况下似乎是二选一,觉得有点不方便,为啥不能都要?

  • 单选:鼠标单一任意一行就是单选;(清空其他已选项)
  • 多选:单击第一列的(多个)复选框,就是多选;

这样用户就可以愉快的想单选就单选,想多选就多选了。

  • IGridSelection
/**
 * 列表里选择的数据
 */
export interface IGridSelection {
  /**
   * 单选ID number 、string
   */
  dataId: number | string,
  /**
   * 单选的数据对象 {}
   */
  row: any,
  /**
   * 多选ID []
   */
  dataIds: Array<number | string>,
  /**
   * 多选的数据对象 []
   */
  rows: Array<any>
}

其实我觉得只记录ID即可,不过既然 el-talble 提供的 row,那么还是都记录下来吧。

定义 json 文件

接口定义好之后,我们可以依据 interface 编写 json 文件:

{
  "moduleId": 142,
  "height": 400,
  "idName": "ID",
  "colOrder": [
    90,  100, 101 
  ],
  "stripe": true,
  "border": true,
  "fit": true,
  "highlightCurrentRow": true,
  "highlight-current-row": true,
  "itemMeta": {
    "90": {
      "id": 90,
      "colName": "kind",
      "label": "分类",
      "width": 140,
      "title": "分类",
      "align": "center",
      "header-align": "center"
    },
    "100": {
      "id": 100,
      "colName": "area",
      "label": "多行文本",
      "width": 140,
      "title": "多行文本",
      "align": "center",
      "header-align": "center"
    },
    "101": {
      "id": 101,
      "colName": "text",
      "label": "文本",
      "width": 140,
      "title": "文本",
      "align": "center",
      "header-align": "center"
    } 
  }
}

  • 为什么直接设置 json 文件而不是 js 对象呢?
    因为对象会比较长,如果是代码形式的话,那还不如直接使用UI库组件来的方便呢。
  • 你可能又会问了,既然直接用 json文件,为啥还要设计 interface 呢?
    当然是为了明确各种类型,interface 可以当做文档使用,另外封装UI库的组件的时候,也可以用到这些 interface。使用列表控件的时候也可以使用这些 interface。

其实json文件不用手动编写,而是通过工具来编写和维护。

定义列表控件的 props

封装组件之前需要先定义一下组件需要的 props:

  • props-grid.ts
import type { PropType } from 'vue'

import type {
  IGridProps,
  IGridItem,
  IGridSelection
} from '../types/50-grid'

/**
 * 表单控件需要的属性propsForm
 */
export const gridProps: IGridProps={
  /**
   * 模块ID,number | string
   */
  moduleId: {
    type: Number,
    required: true
  },
  /**
   * 主键字段的名称
   */
  idName: {
    type: String,
    default: 'ID'
  },
  /**
   * 字段显示的顺序
   */
  colOrder: {
    type: Array as PropType<Array<number | string>>,
    default: ()=> []
  },
  /**
   * 锁定的列数
   */
  fixedIndex: {
    type: Number,
    default: 0
  },
  /**
   * table的列的 meta
   */
  itemMeta: {
    type: Object as PropType<{
      [key:string | number]: IGridItem
    }>
  },
  /**
   * 选择的情况 IGridSelection
   */
  selection: {
    type: Object as PropType<IGridSelection>,
    default: ()=> {
      return {
        dataId: '', // 单选ID number 、string
        row: {}, // 单选的数据对象 {}
        dataIds: [], // 多选ID []
        rows: [] // 多选的数据对象 []
      }
    }
  },
  /**
   * 绑定的数据
   */
  dataList: {
    type: Array as PropType<Array<any>>,
    default: ()=> []
  },
  其他略。。。
}

按照 Option API 的方式设置 props 的定义,这样便于共用属性的定义(好吧似乎也没有需要共用的地方,不过我还是喜欢把 props 的定义写在一个单独的文件里)。

封装列表控件

定义好 json 、props之后,我们基于 el-table 封装列表控件:

  • template 模板
  <el-table
    ref="gridRef"
    v-bind="$attrs"
    :data="dataList"
    :height="height"
    :stripe="stripe"
    :border="border"
    :fit="fit"
    :highlight-current-row="highlightCurrentRow"
    :row-key="idName"
    @selection-change="selectionChange"
    @current-change="currentChange"
  >
    <!--多选框,实现多选功能-->
    <el-table-column
      type="selection"
      width="55"
      align="center"
      header-align="center"
      @click="clickCheck"
    >
    </el-table-column>
    <!--依据 json 渲染的字段列表-->
    <el-table-column
      v-for="(id, index) in colOrder"
      :key="'grid_list_' + index + '_' + id"
      v-bind="itemMeta[id]"
      :column-key="'col_' + id"
      :fixed="index < fixedIndex"
      :prop="itemMeta[id].colName"
    >
    </el-table-column>
  </el-table>

设置 type="selection"列,实现多选的功能。
使用 v-for 的方式,遍历出动态列。
设置 :fixed="index < fixedIndex",实现锁定左面列的功能。

  • js 代码
  import { defineComponent, ref } from 'vue'
  // 列表控件的属性 
  import { gridProps } from '../map'

  /**
   * 普通列表控件
   */
  export default defineComponent({
    name: 'nf-elp-grid-list',
    inheritAttrs: false,
    props: {
      ...gridProps // 解构共用属性
    },
    setup (props, ctx) {
      // 获取 el-table 
      const gridRef=ref(null)
 
      return {
        gridRef
      }
    }
  })

把 props 的定义放在单独的 ts文件 里面,组件内部的代码就可以简洁很多。

实现内置功能

可以按照自己的喜好,设置一些内部功能,比如单选/多选的功能,格式化的功能等。

  • 定义控制函数 controller.ts
import type { ElTable } from 'element-plus'

// 列表控件的属性 
import type { IGridProps } from '../map'

export interface IRow {
 [key: string | number]: any
}

/**
* 列表的单选和多选的事件
* @param props 列表组件的 props
* @param gridRef el-table 的 $ref
*/
export default function choiceManage<T extends IGridProps, V extends typeof ElTable>(props: T, gridRef: V) {
 // 是否单选触发
 let isCurrenting=false
 // 是否多选触发
 let isMoring=false

 // 单选
 const currentChange=(row: IRow)=> {
   if (isMoring) return // 多选代码触发
   if (!row) return // 清空

   if (gridRef.value) {
     isCurrenting=true
     gridRef.value.clearSelection() // 清空多选
     gridRef.value.toggleRowSelection(row) // 设置复选框
     gridRef.value.setCurrentRow(row) // 设置单选
     // 记录
     props.selection.dataId=row[props.idName]
     props.selection.dataIds=[ row[props.idName] ]
     props.selection.row=row
     props.selection.rows=[ row ]

     isCurrenting=false
   }
 }

 // 多选
 const selectionChange=(rows: Array<IRow>)=> {
   if (isCurrenting) return
   // 记录
   if (typeof props.selection.dataIds==='undefined') {
     props.selection.dataIds=[]
   }
   props.selection.dataIds.length=0 // 清空
   // 设置多选
   rows.forEach((item: IRow)=> {
     if (typeof item !=='undefined' && item !==null) {
       props.selection.dataIds.push(item[props.idName])
     }
   })
   props.selection.rows=rows
   // 设置单选
   switch (rows.length) {
     case 0:
       // 清掉单选
       gridRef.value.setCurrentRow()
       props.selection.dataId=''
       props.selection.row={}
       break
     case 1:
       isMoring=true
       // 设置新单选
       gridRef.value.setCurrentRow(rows[0])
       isMoring=false
       props.selection.row=rows[0]
       props.selection.dataId=rows[0][props.idName]
       break
     default:
       // 去掉单选
       gridRef.value.setCurrentRow()
       props.selection.row=rows[rows.length - 1]
       props.selection.dataId=props.selection.row[props.idName]
   }
 }

 return {
   currentChange, // 单选
   selectionChange // 多选
 }
}
  • 列表控件的 setup 里调用
setup (props, ctx) {
  // 获取 el-table 
  const gridRef=ref<InstanceType<typeof ElTable>>()

  // 列表选项的事件
  const {
    currentChange, // 单选
    selectionChange // 多选
  }=choiceManage(props, gridRef)

  return {
    selectionChange, // 多选
    currentChange, // 单选
    gridRef // table 的 dom
  }
}

这里有一个“度”的问题:

  • el-table 完全通过 slot 的方式实现各种功能,这种方法的特点是:非常灵活,可以各种组合;缺点是比较繁琐。
    而我们需要寻找到一个适合的“折中点”,显然这个折中点很难统一,这也是过渡封装带来的问题。
  • 不能遇到新的需求,就增加内部功能,这样就陷入了《人月神话》里说的“焦油坑”,进去了就很难出来。

这也是低代码被诟病的因素。

支持扩展

那么如何找到这个折中点呢?可以按照 “开闭原则”,按照不同的需求,设置多个不同功能的列表控件,使用 slot 实现扩展功能。或者干脆改为直接使用 el-table 的方式。(要灵活,不要一刀切)

比如简单需求,不需要扩展功能的情况,设置一个基础列表控件:nf-grid。
需要扩展列的情况,设置一个可以扩展的列表控件:nf-grid-slot。

如果需要多表头、树形数据等需求,可以设置一个新的列表控件,不过需要先想想,是不是直接用 el-table 更方便。

要不要新增一个控件,不要惯性思维,而要多方面全局考虑。

这里介绍一下支持 slot 扩展的列表控件的封装方式:

  <el-table
    ref="gridDom"
    v-bind="$attrs"
    size="mini"
    style="width: 100%"
    :data="dataList"
    :height="height"
    :stripe="stripe"
    :border="border"
    :fit="fit"
    :highlight-current-row="highlightCurrentRow"
    :current-row-key="idName"
    :row-key="idName"
    @selection-change="selectionChange"
    @current-change="currentChange"
  >
    <!--显示选择框-->
    <el-table-column
      type="selection"
      width="55">
    </el-table-column>
    <!--显示字段列表-->
    <template
      v-for="(id, index) in colOrder"
      :key="'grid_list_' + index + '_' + id"
    >
      <!--检查插槽里是否包含 字段名,作为判断依据-->
      <!--不带插槽的列-->
      <el-table-column
        v-if="!(slotsKey.includes(itemMeta[id].colName))"
        :fixed="index < fixedIndex"
        v-bind="itemMeta[id]"
        :prop="itemMeta[id].colName"
        :min-width="50"
      >
      </el-table-column>
      <!--带插槽的列-->
      <el-table-column  v-else
        v-bind="itemMeta[id]"
      >
        <template #default="scope">
          <!--读取外部插槽内容,并且传递 scope -->
          <slot :name="itemMeta[id].colName" v-bind="scope"></slot>
        </template>
      </el-table-column>
    </template>
  </el-table>

模板部分,首先判断一下是否需要使用 slot,做一个分支。
需要使用 slot 的列,通过 <template #default="scope"> 设置 slot。

  • 代码部分
  import { defineComponent, ref } from 'vue'
  // 表单控件的属性 
  import { gridProps } from '../map'
  import choiceManage from './controller'

  export default defineComponent({
    name: 'nf-elp-grid-slot',
    inheritAttrs: false,
    props: {
      ...gridProps
    },
    setup (props, ctx) {
      // 记录插槽 的 名称
      const slots=ctx.slots
      const slotsKey=Object.keys(slots)
 
      // 列表选项的事件
      const {
        currentChange, // 单选
        selectionChange // 多选
      }=choiceManage(props, gridRef)

      return {
        slotsKey,
        selectionChange, // 多选
        currentChange // 单选
      }
    }
  })

一般列表的使用方法

封装之后,使用起来就很方便了,引入 json文件,设置属性即可。

  • template
  <nf-grid
    v-bind="gridMeta"
    :dataList="dataList"
    :selection="selection"
    size="small"
  />

是不是简单多了。

  • 代码部分
  import { defineComponent, reactive } from 'vue'
  import { nfGrid, createDataList } from '../../../../lib-elp/main'
  import _gridMeta from '../../grid/grid.json'
  import _formMeta from '../../form/form.json'
 
  export default defineComponent({
    name: 'nf-elp-grid-page',
    components: {  nfGrid  },
    setup(props) {
      // 不需要动态改变的话,可以不使用 reactive。
      const gridMeta=reactive(_gridMeta)
      // 设置选择的行
      const selection=reactive({
        dataId: '', // 单选ID number 、string
        row: {}, // 单选的数据对象 {}
        dataIds: [], // 多选ID []
        rows: [] // 多选的数据对象 []
      })
      // 设置记录集。
      const dataList=reactive(_dataList)

      return {
        dataList,
        selection,
        gridMeta
      }
    }
  })

控件可以做成全局组件的形式。

  • 看看效果

扩展列表的使用方法

首先还是依据 json 渲染列表,然后根据需要设置插槽即可,设置插槽后会替换默认的列。

  • template
  可以使用 slot 自定义扩展列 <br>
  <!--表单控件-->
  <nf-grid
    v-grid-drag="gridMeta"
    v-bind="gridMeta"
    :dataList="dataList"
    :selection="selection"
    size="small"
  >
    <!--普通字段,用字段名作为插槽的名称-->
    <template #text="scope">
      <div style="display: flex; align-items: center">
        <el-icon><timer /></el-icon>
        <span style="margin-left: 10px">扩展:{{ scope.row.text }}</span>
      </div>
    </template>
    <!--普通字段-->
    <template #week="scope">
      <span style="margin-left: 10px">{{ scope.row.week.replace('-w','年 第') + '周' }}</span>
    </template>
    <!--操作按钮-->
    <template #option="scope">
      <el-button size="small" @click="handleEdit(scope.$index, scope.row)">修改</el-button>
      <el-button
        size="small"
        type="danger"
        @click="handleDelete(scope.$index, scope.row)">删除</el-button>
    </template>
  </nf-grid>

通过 slot 扩展列,可以按照 Table-column 的匿名插槽的方式进行设置。
列的先后顺序还是由 colOrder 控制,和插槽的先后顺序无关。

  • 代码部分
  import { defineComponent, reactive } from 'vue'
  // 使用 图标
  import { Timer } from '@element-plus/icons-vue'
  import { nfGridSlot, createDataList } from '../../../../lib-elp/main'
  import _gridMeta from '../../grid/grid.json'
  import _formMeta from '../../form/form.json'

  import { EAlign } from '../../../../lib/types/enum'
  import type { IGridSelection, IGridItem } from '../../../../lib/types/50-grid'
 
  export default defineComponent({
    name: 'nf-elp-grid-slot-page',
    components: {
      Timer,
      nfGrid: nfGridSlot
    },
    props: {
      moduleID: { // 模块ID
        type: [Number, String],
        default: 1 
      }
    },
    setup(props) {
      const gridMeta=reactive(_gridMeta)

      // 设置列的先后顺序和是否显示
      gridMeta.colOrder=[90, 100, 101, 102, 105, 113, 115, 116, 120,121,150, 2000]

      // 设置一个操作按钮列
      const optionCol: IGridItem={
        id: 2000,
        colName: "option",
        label: "操作",
        width: 180,
        fixed: EAlign.right,
        align: EAlign.center, // 使用枚举
        headerAlign: EAlign.center
      }

      gridMeta.itemMeta['2000']=optionCol // 设置操作列,也可以直接在json文件里设置。
      const dataList=reactive(_dataList)

      const handleEdit=(index: number, row: any)=> {
        console.log(index, row)
      }
      const handleDelete=(index: number, row: any)=> {
        console.log(index, row)
      }

      return {
        handleEdit,
        handleDelete,
        dataList,
        gridMeta
      }
    }
  })

使用字段名称作为插槽的名称,可以把任意字段变成插槽的形式。

如果要添加操作按钮这类的列,可以给 itemMeta 添加对应的列属性。

  • 看看效果:

管理 json

其实,前面介绍的那些大家可能都会想到,也许早就实践过了,然后发现虽然看着挺好,但是其实没有解决根本问题!只是把 template 里的问题转移到 json 里面。

虽然不需要设置模板,但是需要设置 json,还不是一样,有啥本质区别吗?

其实不一样的,管理 json 的难度明显比管理模板要简单得多。

比如我们可以做一个维护 json 的小工具:

  • 首先从数据库文档生成基础的 json(毛坯房);
  • 然后使用可视化+拖拽的方式设置格子细节(精装修)。

这样就可以很方便的维护 json 了。具体实现方式,将在下一篇再介绍。

源码

nf-ui-controller-UI库的二次封装的共用 JavaScript 函数: 对UI库做二次封装的纯JavaScript函数,支持更多的UI库的时候便于复用。

nf-ui-elementPlus-基于 element-plus 的二次开发: 封装UI库(elementPlus),实现更简洁的使用方式。

动端web开发框架、类库和UI组件简介,有需要的收藏一波。

react-native

一个基于React的创建原生APP的框架

html5-boilerplate

一个用来构建快速、强大、可适配的webapp的前端模板

ionic

领先的HTML5移动开发框架和SDK,利用你所熟知的web技术构建难以置信的移动应用,是AngularJS最好的朋友。

weui

由微信官方设计团队为微信Web开发量身打造的框架,包含移动web应用开发中有用的组件和模块

hammer.js

实现多点触控的javascript库

weex

阿里推出的跨平台的移动端开发框架,具有轻量级、可扩展和高性能的特点

fastclick

一个消除移动端浏览器上的点击事件的300ms的延迟

zepto

Zepto.jsisaminimalistJavaScriptlibraryformodernbrowsers,withajQuery-compatibleAPI

vux

基于Vue和Weui的移动端框架

wepy

腾讯团队推出的小程序组件化开发框架

NativeScript

NativeScript是一个利用JavaScript等WEB技术创建原生APP的框架

Framework7

功能强大的创建iOS&AndroidAPP的HTML框架

mui

最接近原生APP体验的高性能框架

ratchet

用简单的HTML,CSS,和JavaScript组件创建移动应用

react-native-elements

ReactNativeUI组件库

mint-ui

基于vue.js的移动端UI框架

amazeui

移动端优先的开源HTML5跨屏前端框架,俗称妹子UI

jquery-mobile

jQuery移动开发框架

Mars

腾讯移动Web前端知识库

interact.js

JavaScriptdraganddrop,resizingandmulti-touchgestureswithinertiaandsnappingformodernbrowsers(andalsoIE8+)

vant

有赞开发的基于Vue.js2.0的UI组件库

OnsenUI

用来构建混合移动端APP的HTML5UI框架

muse-ui

基于Vue2.0和MaterialDesigin的UI组件库

SUI-Mobile

SUIMobile(MSUI)是由阿里巴巴国际UED前端出品的一个手机端的UI库,轻量精美。更多信息请参考官网

ant-design-mobile

一个可配置的移动端UI框架

TouchSwipe-Jquery-Plugin

TouchSwipeisajqueryplugintobeusedwithjQueryontouchinputdevicessuchasiPad,iPhoneetc.

jquery-weui

创建微信混合app的UI库

jquery-ui-touch-punch

AduckpunchforaddingtoucheventstojQueryUI

device.js

Device.jsmakesiteasytowriteconditionalCSS_and/or_JavaScriptbasedondeviceoperatingsystem(iOS,Android,Blackberry,Windows,FirefoxOS,MeeGo),orientation(Portraitvs.Landscape),andtype(Tabletvs.Mobile).

react-native-ui-kitten

可定制和可重用的react-native组件包

iview-weapp

一套高质量的微信小程序UI组件库

vonic

基于Vue.js和ionic组件的SPAUI框架

brick

UIWebComponentsforModernWebApps

app

App.js是一个用来创建移动webapp的轻量级JavaScriptUI框架,可以表现得像原生APP而又不牺牲性能和优雅

Lungo.js

一个给开发者提供的设计、构建、分享跨设备应用的框架

AlloyFinger

腾讯Web前端团队推出的轻量级的多点触控手势库

FooTable

jQueryplugintomakeHTMLtablesresponsive

vue-ydui

一个基于Vue2.x的移动端组件库

wechat-h5-boilerplate

为腾讯微信优化的H5动效模板,帮助你快速构建全屏滚动型H5页面

slip

通过滑动和拖动手势操作列表的UI库

mobi.css

一个关注于移动端的轻量级的、灵活的css框架,

vue-touch

Vue.js的Hammer.js包装器

QuoJS

针对移动设备的微型JavaScript库

pressure

:point_down::boom:JavaScriptlibraryforhandlingbothForceTouchand3DTouchontheweb

junior

一个创建类似原生APP的html5应用的前端框架

vum

为手机webapp打造的基于Vue.js构建的UI框架

mobiscroll

ThecustomizablemobileUIlibraryfortouchdeviceslikesmartphonesandtablets

zingtouch

一个JavaScript触摸手势检测库

montage

montagejs是一个优雅的、开源的HTML5框架。它提供了模块化组件,双向数据绑定,以及更多功能

pushy

Pushyisaresponsiveoff-canvasnavigationmenuusingCSStransforms&transitions

GMU

基于zepto的ui组件库,适用于移动端

flex.css

flex.cssis是一个声明式的布局框架,能够兼容多个MVVM框架和浏览器

mobilebone

单页切换骨架。适用于移动webAPP,Hybrid混合APP,Phonegap开发,无兼容要求单页PC应用等

jquery.pep.js

Pep,alightweightpluginforkineticdragonmobile/desktop

Cloudajs

CloudaFramework-一个针对移动WebApp的实时JavaScriptRIA框架

jo

Jo(0.5.0)是一个轻量级的(~16K)创建HTML5应用的外壳。可以和PhoneGap,Chrome,Safari,Opera,FireFox,iOS,Android,BlackBerry10,Tizen,&WindowsPhone8+一起工作

touchui

高质量移动端UI框架

iosselect

一个简洁好看的模仿ios的webapp下拉菜单

mand-mobile

面向金融场景的Vue移动端UI组件库,丰富、灵活、实用,快速搭建优质的金融类产品

tabris-js

tabris.js-用JavaScript开发原生应用

aui

移动端UI快速布局解决方案(APICloudUI框架)

vue-carbon

基于vue开发的materialdesignui库

cordova-plugin-ibeacon

AniBeaconpluginforPhonegap/Cordova3.xandupwards.SupportsbothiOSandAndroid(contributionsarewelcome)

touch.code.baidu.com

TouchOfficalSite

bindingx

阿里团队推出的weex和ReactNative上富交互问题的一种解决方案

jQuery-Touch-Events

AcollectionofmobileeventpluginsforjQuery.

TinyNav.js

Responsivenavigationpluginthatweighsjust443bytes

Jingle

JingleUI是一个基于html5、css3开发轻量级的移动webapp框架,提供一些基本交互方式,帮助您更方便的开发移动应用。

light7

一个轻量级的易用的移动端UI框架

framework7-vue

基于Framework7和Vue构建iOS和Android应用

ydui

一只注重审美,且性能高效的移动端&微信UI

slip.js

移动端跟随手指滑动组件,零依赖。

wepayui

微信支付场景化组件,wepayui源码

BlendUI

BlendUI是Clouda+中的重要组成部分,他能让webapp的用户界面体验和交互能和Native媲美

toucher

面向移动端的手势类库

touchjs

一个移动端手势检测库

thumbs.js

Addtouchsupporttoyourbrowserwiththumbs.js-asmall,transparent,andsyntax-lesslibrary.

JMUI

移动Web开发UI组件库

JM

面向Mobile的极致JavaScript库

react-ui

为React打造的一套ionic风格的可复用UI组件库

Zoomage.js

Zoomage.js-一个通过手势缩放图片的库

touchSlider

TouchSliderjQueryPlugin