Zhili's blog Zhili's blog
首页
关于
GitHub (opens new window)

Zhili

转型中的前端老兵
首页
关于
GitHub (opens new window)
  • webpack 区分环境使用CDN以及HtmlWebpackPlugin插件的编写
  • 使用 Mpvue 开发小程序总结
  • 前端知识汇总-持续更新
  • webGL知识汇总-持续更新
  • React思想要点
  • Mapbox 入门初试
  • 构建自己的 GLSL 绘图器 - 2d 版
  • webGL二维有向距离场(SDF)及布尔运算
  • webGL入门:绘制一个三角形
  • 使用 GLSL 绘图尝试:绘制正弦曲线
  • 简单解析虚拟 DOM
  • 自己动手开发一个 markdown 转微信文章工具
  • Vue组件扩展及权限管理的实现技巧
    • 使用 CSS 绘制三角形
    • Nginx 前端配置和使用
    • webpack按需加载配置和babel编译
    • 面试总结39题
    • 使用node反向代理接口改造旧项目
    • 可视化表单搭建系统的开发与思考
    • 前端
    zhili
    2019-11-04

    Vue组件扩展及权限管理的实现技巧

    Vue 组件扩展及权限管理的实现技巧

    # Vue 组件扩展

    最近使用 ant-design-vue 作为 UI 库进行开发,不得不说 ant-design 的外观的确比 ElementUI 要好看,ElementUI 呈现的一种灰蒙蒙的感觉,而 ant-design 就让人感觉很亮,细节动画也很多。

    另外,ant-design 的开发方式偏 React,很多示例也是使用 JSX 来编写的,在开发思路上得做一个切换。

    在新的项目中,有很多 table 列表以及增删改查工作,列表样式基本都统一,而且下方有分页,列表第一页为序号,如下图所示:

    本着少写一行就绝不多写一行,因此,我们可以把 table 封装起来,将一些属性设置为默认样式,但是有时候可能又会有所不同,因此,我们既要保持 table 的灵活性,同时又配置一些默认属性,因此,我们可以继承 table 原有的属性,同时进行一些扩展,并设置一些默认属性。这样使用 JSX 十分方便,我们可以如下进行开发一个 STable 进行扩展:

    import T from 'ant-design-vue/es/table/Table'
    
    export default {
      data() {
        return {
          selectedRowKeys: [],
          selectedRows: [],
          localPagination: Object.assign(
            {
              showTotal: total => `总共有${total}条数据`,
              showSizeChanger: true,
              pageSize: 10,
              current: 1
            },
            this.pagination
          )
        }
      },
      props: Object.assign({}, T.props, {
        // 是否分页
        showPagination: {
          type: Boolean,
          default: true
        },
        // 是否展示可选框
        showSelect: {
          type: Boolean,
          default: true
        },
        // 显示序号
        showSerialNo: {
          type: Boolean,
          default: true
        }
      }),
      methods: {
        handleTableChange(pagination, filters, sorter) {
          this.localPagination = Object.assign({}, this.pagination, {
            current: pagination.current,
            pageSize: pagination.pageSize
          })
          this.$emit('change', pagination, filters, sorter)
        },
        handleRowSelect(selectedRowKeys, selectedRows) {
          this.selectedRowKeys = selectedRowKeys
          this.$emit('rowSelection', selectedRowKeys, selectedRows)
        }
      },
    
      render() {
        const props = {}
        Object.keys(T.props).forEach(key => {
          // 分页
          if (key === 'showPagination') {
            if (!this.showPagination) {
              this.localPagination = false
            }
          } else if (key === 'pagination') {
            props[key] = Object.assign({}, this.localPagination, this[key])
          } else if (key === 'rowSelection') {
            // 是否显示第一行的选择框
            if (this.showSelect) {
              props.rowSelection = {
                selectedRows: this.selectedRows,
                selectedRowKeys: this.selectedRowKeys,
                onChange: (selectedRowKeys, selectedRows) => {
                  this.handleRowSelect(selectedRowKeys, selectedRows)
                }
              }
            }
          } else if (key === 'rowKey') {
            props[key] = record => record.id
          } else if (key === 'columns') {
            const columns = [].concat(this[key])
            // 添加序号
            if (this.showSerialNo) {
              const { pageSize, current } = this.localPagination
              columns.splice(0, 0, {
                title: '编号',
                dataIndex: 'serialNo',
                key: 'serialNo',
                align: 'center',
                customRender: (text, record, index) => (current - 1) * pageSize + index + 1
              })
            }
            columns.forEach(col => {
              col.align = col.align || 'center'
            })
            props[key] = columns
          } else {
            props[key] = this[key]
          }
        })
    
        const table = (
          <a-table {...{ props, scopedSlots: { ...this.$scopedSlots } }} onChange={this.handleTableChange}>
            {Object.keys(this.$slots).map(name => (
              <template slot={name}>{this.$slots[name]}</template>
            ))}
          </a-table>
        )
    
        return <div>{table}</div>
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105

    在我们的组件中,我们引入ant-design-vue/es/table/Table,并在组件的 Props 中继承 Table 的所有属性,Object.assign({}, T.props,{//扩展属性}),在渲染的时候,我们可以循环 Table 的 Props 属性,如果没有设置属性,我们自己给它设置一些默认属性,最终再把所有的属性绑定到 table 上,需要注意的是,在循环 Table 的 Props 属性时候,对于引用类型不可以直接进行修改,否则会陷入循环渲染。

    这样,我们既保留了ant-design-vue/es/table/Table所有可配置的属性,同时也添加了针对项目的默认属性,使用起来十分方便也易于扩展。

    # 增删改查权限的处理

    vue 权限管理很多人都说过,不过常见的都是路由权限,登录之后根据用户的权限动态生成路由。这是页面权限,现在系统的权限更变态,不止页面权限,还有页面里面的权限,也就是某些用户只能看不能编辑,某些用户只能新增不能删除等等,其实总结起来就是页面增删改查权限也得配置。

    好嘛,需求来了就得开干,首先,我们得知道用户有哪些权限,其次,我们要知道页面上的操作需要哪些权限,如果用户有这个权限,我们就显示这个模块,否则,我们不显示这个。例如如果用户没有修改权限,我们就可以不显示修改按钮。这种功能我们使用 Vue 指令就很好完成,代码如下:

    // config: ['GET./api/v1/cachet', 'PATCH./api/v1/users']
    import config from './config'
    // 判断按钮以及页面各个部分是否有权限,没有的话就会移除当前el
    export default {
      bind(el, binding) {
        setTimeout(() => {
          if (!config.includes(binding.value)) {
            el.parentNode.removeChild(el)
          }
        }, 0)
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    然后我们在 main.js 中注册该指令:

    import permissionDirective from './directives/permission'
    
    Vue.directive('permission', permissionDirective)
    
    1
    2
    3

    然后在页面中可以这样使用:

    <a-button v-permission="'DELETE./api/v1/users'">新建</a-button>
    
    1
    编辑 (opens new window)
    #Vue#JavaScript
    上次更新: 2022/03/14, 06:54:51
    自己动手开发一个 markdown 转微信文章工具
    使用 CSS 绘制三角形

    ← 自己动手开发一个 markdown 转微信文章工具 使用 CSS 绘制三角形→

    最近更新
    01
    可视化表单搭建系统的开发与思考
    03-09
    02
    使用node反向代理接口改造旧项目
    11-17
    03
    面试总结39题
    10-11
    更多文章>
    Theme by Vdoing | Copyright © 2022-2023 zhili | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式