vue3 + tsx 表格 Action 单独封装组件用法

前言

先上图看右侧列 action 的 UI 效果:

正常来说,如果一个表格的附带 action 操作,我们一般会放在最右侧的列里面实现,这个时候有些UI 框架支持在 SFC 模板里面定义额外的 solt,当然如果不支持,更通用的做法是通过 vue 的 h 函数来实现,纯粹用 js 或 ts 组装组件方式实现,这种方式很灵活,但有一个弊端,当定义的组件很多的时候,比如上图有4 个Button,还得定义按钮样式和点击事件,代码就显的非常乱。

更为优雅的做法是,把这一小块的功能给单独定义成一个 vue 组件,可以用 SFC 也可以用 JSX/TSX 实现,然后事件通过回调完成,代码就显得非常整洁了。

定义 Action 组件

这里用 tsx 实现:

import { defineComponent, PropType, toRefs } from 'vue'
import { NSpace, NTooltip, NButton, NIcon, NPopconfirm } from 'naive-ui'
import {AreaChartOutlined, DeleteOutlined, EditOutlined,
PlayCircleOutlined,PauseCircleOutlined,RedoOutlined,AlignCenterOutlined} from "@vicons/antd";
import {SolrListActionModel} from "@/service/middleware/types";

const props = {
    row: {
        type: SolrListActionModel as PropType<SolrListActionModel>
    }
}

export default defineComponent({
    name: 'SolrTableAction',
    props,
    emits: [
        'start',
        'stop',
        'restart',
        'showLog',
    ],
    setup(props, ctx) {

        const handleStartAction = () => {
            ctx.emit('start')
        }
        const handleStopAction = () => {
            ctx.emit('stop')
        }
        const handleRestartAction = () => {
            ctx.emit('restart')
        }
        const handleShowLogAction = () => {
            ctx.emit('showLog')
        }

        return {
            handleStartAction,
            handleStopAction,
            handleRestartAction,
            handleShowLogAction,
            ...toRefs(props)
        }
    },
    render() {
        return (
            <NSpace>
                {this.row?.start ? <NTooltip trigger={'hover'}>
                    {{
                        default: () => "启动",
                        trigger: () => (
                            <NButton
                                size='small'
                                type='info'
                                tag='div'
                                circle
                                onClick={this.handleStartAction}
                                class='btn-edit'
                            >
                                <NIcon>
                                    <PlayCircleOutlined></PlayCircleOutlined>
                                </NIcon>
                            </NButton>
                        )
                    }}
                </NTooltip>
                    :""
                }
                {
                   this.row?.stop?<NTooltip trigger={'hover'}>
                        {{
                            default: () => "停止",
                            trigger: () => (
                                <NButton
                                    size='small'
                                    type='info'
                                    tag='div'
                                    circle
                                    onClick={this.handleStopAction}
                                    class='btn-edit'
                                >
                                    <NIcon>
                                        <PauseCircleOutlined></PauseCircleOutlined>
                                    </NIcon>
                                </NButton>
                            )
                        }}
                    </NTooltip>:
                       ""
                }
                {
                    this.row?.restart?<NTooltip trigger={'hover'}>
                            {{
                                default: () => "重启",
                                trigger: () => (
                                    <NButton
                                        size='small'
                                        type='info'
                                        tag='div'
                                        circle
                                        onClick={this.handleRestartAction}
                                        class='btn-edit'
                                    >
                                        <NIcon>
                                            <RedoOutlined></RedoOutlined>
                                        </NIcon>
                                    </NButton>
                                )
                            }}
                        </NTooltip>:
                        ""
                }
                {
                    this.row?.showLog?<NTooltip trigger={'hover'}>
                            {{
                                default: () => "日志",
                                trigger: () => (
                                    <NButton
                                        size='small'
                                        type='info'
                                        tag='div'
                                        circle
                                        onClick={this.handleShowLogAction}
                                        class='btn-edit'
                                    >
                                        <NIcon>
                                            <AlignCenterOutlined></AlignCenterOutlined>
                                        </NIcon>
                                    </NButton>
                                )
                            }}
                        </NTooltip>:
                        ""
                }
                {this.$slots.extraAction?.()}
            </NSpace>
        )
    }
})
在 Table 列里面引用

定义好之后,在 table 里面引用就非常简单了,只需要把 props 属性传递一下,然后定义回调处理事件即可:

        const columns = [
            {
                title: '服务名',
                key: 'server_name',
                align: 'center'
            },
            {
                title: '运行状态',
                key: 'process_state',
                align: 'center'
            },
            {
                title: '主机IP',
                key: 'process_ip',
                align: 'center'
            },
            {
                title: '启动信息',
                key: 'process_description',
                align: 'center'
            },
            {
                title: '操作',
                key: 'operation',
              //列宽自适应
                ...COLUMN_WIDTH_CONFIG['operation'](4),
                align: 'center',
                render: (row: SolrList)=>{
                    let model=new SolrListActionModel(row)
                   return  h(SolrTableAction, {
                        row: model,
                        onStart: () => {

                        },
                        onStop:()=>{

                        },
                       onRestart:()=>{

                       },
                       onShowLog:()=>{

                       }
                    })


                }
            }
        ] as TableColumns<any>
列宽自适应工具类

这个是为了该列的宽度,根据实际情况重新分布:

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { isNumber, sumBy } from 'lodash'
import type {
  TableColumns,
  CommonColumnInfo
} from 'naive-ui/es/data-table/src/interface'

export const COLUMN_WIDTH_CONFIG = {
  selection: {
    width: 50
  },
  index: {
    width: 50
  },
  linkName: {
    width: 200
  },
  linkEllipsis: {
    style: 'max-width: 180px;line-height: 1.5'
  },
  name: {
    width: 200,
    ellipsis: {
      tooltip: true
    }
  },
  state: {
    width: 120
  },
  type: {
    width: 130
  },
  version: {
    width: 80
  },
  time: {
    width: 180
  },
  timeZone: {
    width: 220
  },
  operation: (number: number): CommonColumnInfo => ({
    fixed: 'right',
    width: Math.max(30 * number + 12 * (number - 1) + 24, 100)
  }),
  userName: {
    width: 120,
    ellipsis: {
      tooltip: true
    }
  },
  ruleType: {
    width: 120
  },
  note: {
    width: 180,
    ellipsis: {
      tooltip: true
    }
  },
  dryRun: {
    width: 140
  },
  times: {
    width: 120
  },
  duration: {
    width: 120
  },
  yesOrNo: {
    width: 100,
    ellipsis: {
      tooltip: true
    }
  },
  size: {
    width: 100
  },
  tag: {
    width: 160
  },
  copy: {
    width: 50
  }
}

export const calculateTableWidth = (columns: TableColumns) =>
  sumBy(columns, (column) => (isNumber(column.width) ? column.width : 0))

export const DefaultTableWidth = 1800
总结

通用这种单独定义组件的方式,大大提高了我们代码的可读性,并且后续这个组件可以单独扩展和改变样式而不影响主列表页的迭代,最后我们要注意给 h 组件的传递 props 的方式,直接使用 props name:value 的形式即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值