头图

image.png

“老哥,听说你写的页面挺多的,我这儿有一个页面,你觉得你需要多少代码?”

“我看看,也还行吧,不就是个查询表格嘛,现在大家都用 ProComponent 了,用那个写一下很快的。我想想,差不多 200 行左右就可以了吧。”

“那个呀,我知道,官方的二次封装组件库,200 行就可以了吗?嗯,可以。等等,你说的代码是否包含了操作按钮?”

“操作按钮?是指你图上的 【新增】【详情】这些按钮吗?”

“是啊。”

“点了之后长啥样呀,你也没给我看呀!”

“哦,差不多长这个样。”

image.png

“哦~ 这样子啊,那这个简单,不就是个弹窗表单嘛,撑死再加个 100 行吧。”

“那【删除】呢?”

image.png

“就这。10 行就搞定了吧。”

“哈哈,你别着急嘛,还有批量删除呢!”

image.png

“哦哦,这也没多难啊,大部分都是表格自带的 Api,删除完刷新下表格请求就完事儿了。无非就是记录下选项嘛,再给个 10 行我觉得就差不多了。不过我看你这勾选之后,页面下面还有个条,把【批量删除】按钮放那里了,有点意思,不过也没多难,再加个 20 行左右我觉得差不多了。”

“哈哈,是的,我算算,这差不多已经 340 行了吧。”

“是啊,写这样一个页面的话,这点代码量很正常。”

“那如果翻页后,仍然保留上个页面的选项呢?”

“这个呀,现在哪有人做这个呀,这都是现成的组件,你不嫌麻烦我还嫌麻烦呢,而且又不是必须的,爱谁谁做。”

“你就说你会不会吧!”

“你是故意找茬是吧!再说了,这也不难,antd 表格不是有个 preserveSelectedRowKeys 属性吗,我觉得可以用那个实现,或者监听下表格的选择事件,存个变量就好了。实在不行,就点页面单个删除呗,也没多麻烦吧。”

“说是这么说,确实也没必要,但我觉得有更好,如果要删除多个的话,每次删除总是要多点几次,而且删除完之后,数据不是没了嘛,那第二页的数据就会跑到第一个页面来,就会担心自己会不会删错。”

“还行吧,只要你不嫌累,你就写吧。我觉得也没啥,如果真要做,用那个 api 就好了,顶多再加个 20 行吧。”

“哦!对了,我忘记说了,这个数字悬浮上去是能看到选项的。”

image.png

“...你玩的还挺花,数据都有,搞个 Popover 套一下,就可以了吧。”

“是的,这么样一算的话,差不多有 400 行代码了吧。”

“嗯,你需求多嘛,差不多差不多。”

“哈哈,这个页面我总共花了 134 行代码,你觉得可行

“???你怎么做到的,给我看看。“

查看表格示例代码

“我看了一下,有意思,这个组件用了一个大 json,把配置传进去了是吧,这种封装还挺常见的。”

“是的,你看这是其中一个片段,表格的顶部查询,只需要指定 search: true 就可以了。”

{
  title: '英文名',
  key: 'en'
  search: true
}

“这样子啊,那上面我看有 placeholder 呀,怎么没看你传进去。”

“哦,那个是自动生成的,像这里,会生成"请输入英文名"。”

“那如果要自定义呢?”

“当然也可以,需要这样子写。”

{
  title: '英文名',
  key: 'en'
  search: {
    placeholder: '请输入英文名'
  }
}

“哦~ 这还能是个对象是吧,那如果上面是个选择框呢?”

“也简单,添加 optionstype: 'select' 就可以了。”

{
  title: '职业',
  key: 'class',
  type: 'select',
  options: [
    { label: '近卫干员', value: '1' },
    { label: '狙击干员', value: '2' },
    { label: '术师重装', value: '3' },
    { label: '医疗干员', value: '4' },
    { label: '重装干员', value: '5' },
    { label: '辅助干员', value: '6' },
    { label: '特种干员', value: '7' },
    { label: '先锋干员', value: '8' }
  ],
  search: true
}

“你这 optionstype 为什么没有放在 search 对象里面的呀?”

“哈哈,这你就不知道了吧,因为这样子写的话,表格也可以用这个配置,写在 search 对象里面的话,就只能查询区域自己用了。”

“表格也可以用这个配置?表格要这俩有啥用。”

“表格这一列,可以通过 options 翻译,假如数据是个 1,那么这一列就会根据 options 去寻找这个 label,这时候对应的 label近卫干员,所以页面上显示的就是 近卫干员。另外如果表格有筛选,添加 filter: true 就会出现筛选了。”

image.png

“可以,还挺方便的,那 type 呢?这东西表格用不到吧。”

“是的,这个的话,其实是给 dialog 弹窗编辑用的。这样子的话可以让弹窗里面也展示一个选择框了。”

{
  title: '职业',
  key: 'class',
  type: 'select',
  options: [
    { label: '近卫干员', value: '1' },
    { label: '狙击干员', value: '2' },
    { label: '术师重装', value: '3' },
    { label: '医疗干员', value: '4' },
    { label: '重装干员', value: '5' },
    { label: '辅助干员', value: '6' },
    { label: '特种干员', value: '7' },
    { label: '先锋干员', value: '8' }
  ],
  search: true,
+ dialog: true
}

“哦哦!明白了,指定了 dialog: true 后,就会在弹窗里面显示了是吧。”

“是的,那如果只在弹窗里展示,而表格不展示呢?”

“那可以这样子做。指定 table: false 就可以了。”

{
  title: '职业',
  key: 'class',
  type: 'select',
  options: [
    { label: '近卫干员', value: '1' },
    { label: '狙击干员', value: '2' },
    { label: '术师重装', value: '3' },
    { label: '医疗干员', value: '4' },
    { label: '重装干员', value: '5' },
    { label: '辅助干员', value: '6' },
    { label: '特种干员', value: '7' },
    { label: '先锋干员', value: '8' }
  ],
  dialog: true,
+ table: false
}

“明白了。这是把弹窗、表格、查询揉在一起了是吧,对了,我怎么没有看到新增打开弹窗的代码呢?”

“那个呀,那个需要再加点代码。把 addApi 作为请求接口传进去,再指定 action="add" 就好了?”

<AySearchTable
  title="Amiya 增删改查"
  dialogFormExtend={{
    fields: fields,
    addApi
  }}
>
  <AyAction action="add">新增</AyAction>
</AySearchTable>

“这也可以?为什么?难到不需要监听按钮点击事件,然后控制弹窗显示,再请求接口,之后关闭弹窗刷新页面吗?”

“是的,这里默认认为弹窗和表格共用一个配置,且弹窗新增大多都是千篇一律的,所以把所有的操作封装了一下,就只剩下这么点了。当然如果太过复杂,或者跟表格都没有什么可以共用的列,就再定义一个 'fields: dialogFields',和表格完全分开用俩 fields,各用各的。”

“哦哦,可以可以,那我理解了,修改也是同理吧。”

“是的,编辑的时候,不是会有默认值吗?此时我们把 record 传进去,当作表单的默认值就可以了。”

const ctrl: AyTableCtrlField = {
  render: (value: string, record: Record) => {
    return (
      <AyCtrl>
        <AyAction record={record} action="update">
          编辑
        </AyAction>
      </AyCtrl>
    )
  }
}

<AySearchTable
  title="Amiya 增删改查"
  dialogFormExtend={{
    fields: fields,
    addApi
  }}
/>

“可以,可以!这个组件把常用的操作都变成指令了啊。”

“是的呀,如果你的详情是需要请求接口的,那就不需要 record 了,删掉之后改成 detailApidetailParams, 分别是请求的接口和请求的参数,action="view" 指令会自动的把请求返回的数据,作为打开弹窗后表单的默认值的。”

<AyAction detailParams={record.sort_id} detailApi={detailApi} action="view">详情</AyAction>

“明白了,非常的棒!对了你刚刚还说到分页删除了,用这个组件是不是也很简单啊?”

“是的,我给你看一下,这个多个几步,第一步,先添加 selectionType="checkbox" 开启勾选;第二步,添加 selectShowKey="cn",让气泡悬浮时用它来决定展示选中的名称,并用 tag 标签裹住,因为 tag 标签可以删除的,这样子翻页之后也可以点击 tag 标签上面的 X,来取消选项,不用再翻到上一页取消选择了;第三步,在删除按钮上添加 action="delete" 属性,批量删除上添加 action="batch-delete" 属性,标签上添加 deleteApi={deleteApi} 接口,就可以完成删除和批量删除的动作了。”

const ctrl: AyTableCtrlField = {
  render: (value: string, record: Record) => {
    return (
      <AyCtrl>
        <AyAction record={record} action="delete">
          删除
        </AyAction>
      </AyCtrl>
    )
  }
}

<AySearchTable
  title="Amiya 增删改查"
  selectionType="checkbox"
  rowKey="sort_id"
  ctrl={ctrl}
  selectShowKey="cn"
  deleteApi={deleteApi}
>
  <AyAction action="batch-delete">批量删除</AyAction>
</AySearchTable>

“哦哦,这样子就可以了吗?那还挺方便的,毕竟不需要自己写一堆代码来写。对了,我刚才看了下代码,上面有个 renderType: 'html',这是什么作用。”

{
  title: '描述',
  key: 'feature',
  width: 200,
  renderType: 'html'
}

“你猜猜?”

“把这一列渲染成 html 之类的?”

“是呀,除此之外,还有 unit datetime state 等等类型,你可以看看这个。”

查看自定义类型

“可以,那如果我要的这里面没有呢?”

“就等着你问这个呢,看来你用过其它的二次封装呀,这个组件提供两种方式,第一种可以指定 render 方法。”

{
  title: '姓名',
  key: 'cn',
  search: true,
  dialog: {
    required: true
  },
  table: {
    // 渲染自定义内容
    render: (text: string, record: Record) => {
      return (
        <div>
          <div>{record.cn}</div>
          <div>{record.en}</div>
          <div>{record.jp}</div>
        </div>
      )
    }
  }
},

“第二种,可以全局注册,注册完之后,可以像 renderType: 'star' 这样子使用。”

import { registerTableRender, RenderProps } from 'amiya'

/**
 * @decs 注册 renderType
 * @param renderTypeName string 注册类型名字
 * @param text string 当前 col 的数据
 * @param record object 当前 row 的数据
 * @param field 当前配置配置项
 *
 * @returns ReactNode
 */
registerTableRender('renderTypeName', ({ text, record, field }: RenderProps) => {
  return <span>{text}</span>
})

// 实际使用
const fields = [
  {
    renderType: 'renderTypeName' // 已经注册过后的名字
  }
]

注册自定义表单类型

“好家伙,这跟我直接 render 也没什么区别嘛,不过用注册的方法,把 render 写在其它公共的地方的话,确实会让当前页面干净一点。”

“是的,两种方式自由选择。你看这样子一套下来,你看,是不是省了很多代码,如果你用 jsx 语法糖的话会更省,那样子只需要 90 行代码了。”

“对哦,我见到的其它二次封装就是少了这个,都用 json,用起来编辑器右边空白一大片,代码又拉的老长,挺不爽的,你这样子写法我挺喜欢的,我跟他们提建议,他们都不听的,还云云这样容易控制什么的。”

 <AyFields>
   <AyField
     title="头像"
     key="icon"
     width={80}
     align="center"
     renderType="image"
   />
   <AyField title="姓名" key="cn" search />
   <AyField title="英文名" key="en" search dialog table={false} />
   {// ...}
 </AyFields>

“真能省,还没见过这么能省的,不过,这个组件封装的这么多,别人会用吗?用的明白吗?”

“确实,如果不介绍介绍的话,没人用的明白。所以这个组件支持完整的 TypeScript 提示,也准备了文档,详细地介绍了表格的使用方式,你看左侧那一堆菜单,都是在介绍表格 api 的。”

image.png

“而且,也有完整的页面级别的示例,也可以做参考。”

表格其它示例

“我看到了,这是个二次封装的组件库吧,我看还有其它组件,等我回头用用看体验一下。”

“好的,等你消息。”

Amiya 二次封装文档地址


viewweiwu
660 声望104 粉丝

咸鱼也是有梦想的!