【React-admin】构建React应用(7)-Operator列的封装

前面提到,为了实现权限相关的需求而选择了React-admin框架,该框架已经对列做了封装,先看一下它封装的成果:

import { Operator } from 'src/library/components';

....
{
        title: '操作', dataIndex: 'operator',
        render: (value, record) => {
          const { id, name } = record;
          let items = []
          if (checkAuth("systemmanage_authmange_data_role_detail")) {
            items.push({
              label: '查看',
              icon: 'eye',
              onClick: (e) => {
                e.stopPropagation();
                this.getPropertyAuth(record)
              },
            })
          }
          if (checkAuth("systemmanage_authmange_data_role_modify")) {
            items.push({
              label: '修改',
              icon: 'form',
              onClick: (e) => {
                e.stopPropagation();
                this.setState({ visible: true, id, record, type: "edit", drawerTitle: "修改资产" });
              },
            })
          }
          if (checkAuth("systemmanage_authmange_data_role_delete")) {
            items.push({
              label: '删除',
              color: 'red',
              icon: 'delete',
              confirm: {
                title: `您确定删除"${name}"?`,
                onConfirm: (e) => {
                  e.stopPropagation();
                  this.handleDelete(id);
                },
              },
            })
          }
          return <Operator items={items} />;
        },
      },

上面是一个完整的Operator列,最后只要把我们需要的操作放到数据中就可以了。效果如下
在这里插入图片描述

用起来确实不错。但是试想一下,每个模块基本上都是这种,或者类似这种的,就需要每个模块都要定义那一坨,看起来很不舒服。所以打算在框架上再做一次封装。既然框架定义的Operator组件只需要一个参数,那么我就自己定义动态生成items,然后将items传递给组件就可以了。

所谓的封装组件就是共性的封装,看了看每个item的定义,几乎都是一样的,那么第一层封装应该是把这些共有的东西全拿出去。

从上面的代码可以看出对于查/改/删的操作,会需要不同的数据及不同的操作,那么在封装的时候,我们先提取第一层公有的属性。

  1. record:{}, 必须,
  2. keys:[], 必须,

无论是删改查哪个从操作似乎都需要record相关的属性,不管是删除时往后端发送的id还是用于删除提示的name,都离不开record,所以第一个要提取的属性就应该是record

因为这个框架主要是为了做权限操作的,所以对于任何操作都会设置一个key用来标识操作,比如create操作的key可能是这样的xxxx-create,只要根据这个key去登陆用户的权限列表中判断是否存在即可,所以key是必须的。但是还不满足,由于是程序去执行代码,他并不知道你的key对应的是什么操作,所以,你需要给key绑定额外的属性,那么可能就是这样的[{key:“xxx_create”,type:“create”}]。因为要作为所有模块的通用组件,所以不能单独根据_create这种东西去判断。这些其实还是不够,因为你会发现每个操作项都会有其独特函数去执行一些操作,比如点击查看显示一个抽屉去显示详情,点击删除会显示是否删除的提示框…。所以我们需要额外的属性callback去处理函数回调。

综上所述我们的定义的一个完整的keys应该是这样的:

{ key: "systemmanage_authmange_department_detail", type: "detail", callback:()=> this.onOperator(record, "detail") },
  • key:用于判断是否有该权限
  • type:操作类型,根据操作类型添加不同的操作
  • callback:回调函数

在模块下调用函数:

const items = getOperatorMenus([
            { key: "systemmanage_authmange_department_detail", type: "detail", callback:()=> this.onOperator(record, "detail") },
            { key: "systemmanage_authmange_department_modify", type: "modify", callback:()=> this.onOperator(record, "modify"), },
            { key: "systemmanage_authmange_department_delete", type: "delete", callback:()=> this.onOperator(record, "delete") },
          ], record)

那么在封装的组件或者函数中就可以这么去实现了:

import { checkAuth } from 'src/utils/auth'
/**
 * 根据路由的操作按钮对应的key生成operator列
 * @param {} keys 路由下的keys值
 */
export const getOperatorMenus = (keys, record) => {
  const { name } = record;
  let items = []
  keys && keys.map(({key, type, callback}) => {
    if (checkAuth(key)) {// 判断该key值是否在权限列表中,如果在则添加,不在则不添加
      switch (type) {
        case "detail":
          items.push({
            label: '查看',
            icon: 'eye',
            onClick: (e) => {
              e.stopPropagation();
              callback()//回调函数
            },
          })
          break;
        case "modify":
          items.push({
            label: '修改',
            icon: 'form',
            onClick: (e) => {
              e.stopPropagation();
              callback()
            },
            })
          break;
        case "delete":
          items.push({
            label: '删除',
            color: 'red',
            icon: 'delete',
            confirm: {
              title: `您确定删除"${name}"?`,
              onConfirm: (e) => {
              e.stopPropagation();
              callback()
              },
            },
            })
          break;
        default:
          break;
      }
    }
    return ""
  })
  return items
}

这样做的一层封装,只要在模块下调用这个函数就行了,不需要像刚开始的时候那样要在每个模块都需要写一大坨。这需要简化成这样就可以了:

{
  title: '操作', dataIndex: 'operator',
  render: (value, record) => {
    const items = getOperatorMenus([
      { key: "systemmanage_authmange_department_detail", type: "detail", callback:()=> this.onOperator(record, "detail") },
      { key: "systemmanage_authmange_department_modify", type: "modify", callback:()=> this.onOperator(record, "modify"), },
      { key: "systemmanage_authmange_department_delete", type: "delete", callback:()=> this.onOperator(record, "delete") },
    ], record)
    return <Operator items={items} />;
  },
},

是不是看起来清爽多了。

有人肯定认为还能再次封装,比如在每个操作中我们可以看出有很多共同的东西:

{
   label: '查看',
   icon: 'eye',
   onClick: (e) => {
     e.stopPropagation();
     callback()
   },
 }

比如上面这段代码,删改查几乎都一样,通用的属性:

  • label:显示的名称
  • icon:图标
  • onClick:操作事件
  • color:颜色

可以抽离出来一个组件,然后动态生成这些组件。

当然如果你感兴趣,需要再次封装,那我并不反对。只要是具有共性的我们都可以封装,只是根据需求,根据场景,根据时间选择自己的封装方式。

当然也并不是封装的越彻底越好,比如antd.pro的封装,已经算是很彻底了,机会我们不需要做任何的配置,比如webpack的配置,你只要专心做业务模块的开发就可以了。用起来是很爽,但是v4版本使用了dva的方式,给我们带来了大量的模板,在开发的时候尤其复杂,如果是新手接触会发现操作起来难度很高。但是v5版本就废弃了dva的方式管理数据流,改用了react自带的redux技术,让技术回归最初。

有人说榨汁机多方便,能帮我去掉果皮和一些不需要的部分,直接可以拿来喝。但是有调查表明,榨汁机在水果打碎的过程中,会破坏里面的营养成分,反而得不到我们需要的营养成分。我们吃水果有时是为了补充营养,结果发现用完榨汁机就跟和白开水一样。那我们投入了榨汁机的成本就反而得不偿失。

开发中没有所谓的最好,只有最合适

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值