Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
zhouzhili opened this issue Nov 4, 2019 · 0 comments
Open

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

zhouzhili opened this issue Nov 4, 2019 · 0 comments
Labels

Comments

@zhouzhili
Copy link
Owner

Vue 组件扩展

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

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

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

no

本着少写一行就绝不多写一行,因此,我们可以把 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>
  }
}

在我们的组件中,我们引入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)
  }
}

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

import permissionDirective from './directives/permission'

Vue.directive('permission', permissionDirective)

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

<a-button v-permission="'DELETE./api/v1/users'">新建</a-button>
@zhouzhili zhouzhili added the vue label Aug 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant