首页 > 其他分享 >列表的批量操作组件封装 + 权限 ,如何更优雅的实现呢?Vue3

列表的批量操作组件封装 + 权限 ,如何更优雅的实现呢?Vue3

时间:2023-05-08 09:34:39浏览次数:50  
标签:const 按钮 actions return value Vue3 组件 封装 row

  1. 这个组件解决的问题?
    在以往的项目当中,我从未想过要对 批量/列表数据的操作按钮做什么变动,直到最近的一次开发,让我突然觉得可以将操作按钮也做成一个公共组件,在做前端开发时,更加专注于js代码逻辑。
  2. 如何使用?
    全局(main.js中)引用操作组件 BatchOperation.vue
    创建页面操作按钮 actions.js 文件
  3. BatchOperation.vue 全局操作按钮组件文件代码:
    <template>
       <div>
        <!-- 列表顶部的批量操作按钮组件  / 表格中的操作按钮-->
           <el-row :gutter="10" class="mb8 mt10" type="flex">
               <slot name="default"></slot>
               <el-col :span="1.5" v-for="action, index in visibleAction" :key="action.command" v-show="visibleAction.length > 0">
                   <el-button :link="inColumn" :type="getBtnType(index)" plain :disabled="action.disabled" v-hasPermi="action.permission" @click="commandAction(action.command)">{{action.name}}</el-button>
               </el-col>
               <el-col :span="1.5" v-if="moreActionsVisible">
                   <el-dropdown @command="commandAction" :size="inColumn ? 'default' : 'large'" style="line-height:inherit;vertical-align: bottom;">
                       <el-button type="primary" plain :link="inColumn">
                           更多操作<el-icon class="el-icon--right"><arrow-down /></el-icon>
                       </el-button>
                       <template #dropdown>
                           <el-dropdown-menu>
                               <div v-hasPermi="action.permission" v-for="action in moreActions" :key="action.command">
                                   <el-dropdown-item :disabled="action.disabled" :command="action.command" >
                                       {{action.name}}
                                   </el-dropdown-item>
                               </div>
                           </el-dropdown-menu>
                       </template>
                   </el-dropdown>
               </el-col>
               <slot name="rightToolbar"></slot>
           </el-row>
       </div>
    </template>
    <script setup>
     import take from 'lodash/take'
     import takeRight from 'lodash/takeRight'
     import mapValues from 'lodash/mapValues'
     import pickBy from 'lodash/pickBy'
     import values from 'lodash/values'
     import sortBy from 'lodash/sortBy'
     // button type
     const btnType = ['primary', 'success', 'warning', 'danger', 'info', 'default']
     // props
     const getBtnType =(index)=>{
         const indx = index % btnType.length
         return btnType[indx]
     }
     // actions command
     const emits = defineEmits()
     // props
     const props = defineProps(['actions','visibleCount','inColumn'])
     // 明显按钮 默认显示前五个按钮; 如果是在 数据行操作只显示 1 个
     const MAX = computed(()=>{
         const count = props.inColumn ? 1 : 5
         return props.visibleCount === undefined ? count : props.visibleCount
     })
     // 将 key 作为 command。 hiddenInColunm 在表中隐藏 onlyInColunm 只在表格列中显示 hidden 都不显示
     const operations = computed(()=>{
         let actions = pickBy(props.actions, a =>(props.inColumn ? (!a.hiddenInColunm) : !a.onlyInColunm) && !a.hidden)
         actions = mapValues(actions,(value,key)=>{
             value.command = key
             return value
         })
         // 将可用功能优先排序
        return sortBy(values(actions), (a)=>a.disabled)
     })
     // 明显按钮
     const visibleAction = computed(()=>{
         return take(operations.value, MAX.value)
     })
     // 更多操作下拉按钮
     const moreActions = computed(()=>{
         return takeRight(operations.value, operations.value.length - MAX.value)
     })
     // 是否显示更多按钮
     const moreActionsVisible = computed(()=>MAX.value == 0 || operations.value.length > visibleAction.value.length)
     // 点击更多操作里的按钮
     const commandAction =(command)=>{
         emits(command)
     }
    </script>
    
  4. actions.js 页面操作,举个例子:
    // single:批量勾选 false 单条数据,true 非单条数据
    // multiple:批量勾选 false 已勾选 true 未勾选
    // row:单行数据。当 single 为 false 时, row 也须有值 
    export default function (single, multiple, row) { 
         return {
             'create': {
                 name: "新增",// 按钮名称
                 permission: ['bless:product:permissionAdd'],// 权限字符
                 disabled: false, // 是否可点击
                 hiddenInColunm: true // 在表格列中隐藏
             },
             'edit': {
                 name: "修改",
                 permission: ['bless:product:permissionEdit'],
                 // 单行 或者 row 存在且符合( ... )中的条件时
                 disabled: single || ( row ? ( row.status !=0 && row.status !=3 ) : true),
                 onlyInColunm: true // 仅在列表中显示
             },
             'delete': {
                 name: "删除",
                 permission: ['bless:product:permissionRemove'],
                 disabled: multiple,
             },
             'search': {
                 name: "查询", 
                 permission: ['bless:product:permissionPage'],
                 disabled: false,
                 hidden: true // 隐藏
             }
         }
     }
    
  5. 页面使用操作按钮:UI 组件:element-plus
      <template>
         <!-- v-hasPermi 权限指令 详见 若依--自定义指令-->
         <div v-hasPermi="actions['search'].permission">
             <!-- 批量操作 -->
             <BatchOperation 
                :actions="actions" 
                @create="handleCreate"
                @delete="handleDelete"
                >
             </BatchOperation>
             <!-- 列表 -->
             <el-table :data="list" row-key="productId" @selection-change="handleSelectionChange">
                <!-- 勾选框 -->
                <el-table-column type="selection" width="55" align="center" fixed="left" />
                ...(这里就是列表展示的数据)
                <!-- 单行操作按钮 -->
                <el-table-column label="操作" fixed="right" header-align="center" width="150px">
                      <template #default="{row}">
                         <BatchOperation 
                         :inColumn="true"
                         :actions="initAction(false, false, row)"
                         @edit="handleEdit(row)"
                         @delete="handleDelete(row.productId)"
                         ></BatchOperation>
                      </template>
                </el-table-column>
             </el-table>
         </div>
      </template>
      <script setup name="ProductIndex">
         import { getPages, remove } from '@/api/product'
         import initAction from './components/actions'
         // 勾选
         const multipleSelection = ref([]) // ids
         // 非单个禁用
         const single = computed(() => multipleSelection.value.length != 1)
         // 非多个禁用
         const multiple = computed(() => !multipleSelection.value.length)
         // 当前选中
         const selectedRow = computed(() => {
            if (multipleSelection.value.length == 1) {
                  return list.value.find(z => z.productId == multipleSelection.value[0])
            }
            return null
         })
         // 批量操作按钮
         const actions = computed(()=>initAction(single.value, multiple.value, selectedRow.value))
         // 批量勾选触发
         const handleSelectionChange = (val) => {
            multipleSelection.value = val.map(z => z.productId)
         }
         // 点击 ��增
           const handleCreate =()=>{
               router.push('/product/create')
           }
         // 点击 修改
         const handleEdit =(row)=>{
            const current = row || selectedRow.value
            router.push('/product/edit/' + current.productId)
         }
         // 批量删除
         const handleDelete = (id) => {
            proxy.$modal.confirm('确定删除?')
               .then(() => {
                  const ids = id || multipleSelection.value
                  remove(ids).then(res => {
                     if (res.code == 200) {
                           proxy.$modal.msgSuccess("操作成功")
                           getList()
                     } else {
                           proxy.$modal.msgError(res.msg || "请求发生错误,请稍后重试")
                     }
                  })
               })
               .catch(() => {
                  proxy.$modal.msg("已取消")
               })
         }
         // 获取列表数据
         const getList = () => {
            proxy.$modal.loading("加载中...")
            // **这里 searchRef 咱们下篇随笔见!**
            const { dateRange, ...search } = searchRef.value.form
            const query = { ...pager.value, ...search }
            const data = dateRange ? proxy.addDateRange(query, dateRange) : query
            getPages(data).then(response => {
                  list.value = response.data.rows;
                  total.value = parseInt(response.data.total);
                  expandRowKeys.value = []
            }).finally(() => {
                  proxy.$modal.closeLoading();
            });
         }
      </script>

标签:const,按钮,actions,return,value,Vue3,组件,封装,row
From: https://www.cnblogs.com/kitty-blog/p/17380714.html

相关文章

  • 封装
    引入面向对象编程有三大特性:封装、继承、多态隐藏属性Python的Class机制采用双下划线开头的方式将属性隐藏起来(设置成私有的),但其实这仅仅只是一种变形操作,类中所有双下滑线开头的属性都会在类定义阶段、检测语法时自动变成“_类名__属性名”的形式:classFoo:__N=0#变形......
  • k8s集群组件
    k8s集群有以下组件:Master:Kubernetes集群的控制中心,包括:APIServer:在Kubernetes集群中,APIserver扮演一个接口,使用户和管理员可以通过kubectl或其他工具与集群进行交互,而不必直接与底层组件打交道。同时,所有其他Kubernetes组件,包括kubelet、kube-proxy、controllerman......
  • 第10章:10W QPS真刀实操__以及基于ZK+Netty手写分布式测试工具 177手机路人甲账号 主目
    10WQPS真刀实操__以及基于ZK+Netty手写分布式测试工具参考链接系统架构知识图谱(一张价值10w的系统架构知识图谱)https://www.processon.com/view/link/60fb9421637689719d246739秒杀系统的架构https://www.processon.com/view/link/61148c2b1e08536191d8f92f10WQPS真刀实......
  • VueUse 是怎么封装Vue3 Provide/Inject 的?
    Provide/InjectProvide和Inject可以解决Prop逐级透传问题。注入值类型不会使注入保持响应性,但注入一个响应式对象,仍然有响应式的效果。Provide的问题是无法追踪数据的来源,在任意层级都能访问导致数据追踪比较困难,不知道是哪一个层级声明了这个或者不知道哪一层级或若干个......
  • 在vue3中使用elementPlus的el-select时样式穿透问题
    下拉框的option样式只能在全局样式里改,千万不能用scope,否则不生效<el-selectclass="select":popper-append-to-body="false"v-model="selectValue"placeholder="请选择"popper-class="select-option"><......
  • 使用 NutUI 搭建「自定义业务风格」的组件库 | 京东云技术团队
    本文介绍,如何使用NutUI组件库,搭建一套为专属业务风格的业务组件库。NutUI是一款京东风格的移动端组件库。NutUI目前支持Vue和React技术栈,支持Taro多端适配。当下的实现方式一般组件库,都会给用户提供修改主题的方式。比如在NutUI组件库中,给用户提供了两种方式:修改CSS变量,Nu......
  • 【WPF】-MVVM-封装窗口管理器解耦在ViewModel中弹出窗口
    一.在ViewModel层直接调用View弹出窗体如下图所示,这样做就发生了在ViewModel层直接使用了View,两者产生了耦合,ViewModel里是不应该包含View的,这不是我们期望的。 二.封装窗口管理器解耦在ViewModel中调用View2.1.封装窗口管理器延迟了对象的创建,先把类型(对象的模板)注册进来,......
  • Vite-WeGPT聊天AI实例|vue3+pinia仿ChatGPT聊天界面
    基于vue3.x+vite4+pinia2仿chatgpt聊天模拟实例Vue3-WeGPT。基于Vite4.x+Vue3+Pinia2+VEPlus+Vue3-Markdown等技术实现仿ChatGPT聊天AI界面实例。整体界面简洁清新、支持2种界面布局、暗黑+亮色模式、全屏+半屏展示、Markdown语法解析、侧边栏收缩等功能。使用技术编辑器:cur......
  • vue3源码-三、ref和toRefs的实现
    实现Refref的本质就是通过类属性访问器来实现,可以将一个普通值类型进行包装import{hasChanged,isObject}from"@vue/shared";import{track,trigger}from"./effect";import{TrackOpTypes,TriggerOpTypes}from"./operations";import{reactive}from&q......
  • 前端配置化表单组件设计方法
    一、背景前端开发中涉及表单的页面非常多,看似功能简单,开发快速,实则占去了很大一部分时间。当某个表单包含元素过多时还会导致html代码过多,vue文件过大。从而不容易查找、修改和维护。为了提高开发效率及降低维护成本,下面介绍表单配置化组件的封装原理与封装方法。二、技术方案......