vue3+ts表格拖拽实现

<template>
    <div>
        <div class="table-box">
            <div class="table-header">
                <template v-for="columnItem in tableColumn" :key="columnItem.label">
                    <div>
                        <span>{{ columnItem.label }}</span>
                        <template v-if="columnItem.label === '标签序号'">
                            <el-tooltip class="box-item" effect="dark" :content="sortTip" placement="top">
                                <el-icon style="margin-left: 15px;">
                                    <QuestionFilled />
                                </el-icon>
                            </el-tooltip>
                        </template>
                    </div>
                </template>
            </div>
            <!-- 内容拖拽 -->
            <draggable v-model="data" group="items" @change="logEvent" v-if="data?.length > 0">
                <!-- 遍历表格数据-->
                <div class="table-item" v-for="item in data" :key="item.id">
                    <!-- 遍历header数据 -->
                    <template v-for="columnItem in tableColumn" :key="columnItem.label">
                        <!-- 遍历一行中的每一列 -->
                        <template v-for="(value, key) of item" :key="key">
                            <p v-if="String(key) === columnItem.prop" style="display: flex; align-items: center;">
                                <!-- 值 -->
                                <span>{{ value }}</span>
                                <!-- slot -->
                                <slot v-if="columnItem.slot" :name="columnItem.slot" />
                                <!-- p标签排序编辑弹窗 -->
                                <template v-if="String(key) === 'tagNum'">
                                    <el-popover :visible="popoverVisible === item.id" placement="bottom"
                                        :show-arrow="false" :offset="3"
                                        popper-style="padding:3px 5px; margin-left:18px;">
                                        <!-- 按钮 -->
                                        <template #reference>
                                            <el-icon style="color: #409EFF;cursor: pointer; margin-left: 45px;"
                                                @click="editSort(item)">
                                                <Edit />
                                            </el-icon>
                                        </template>
                                        <!-- 编辑 -->
                                        <div class="sort-edit-box">
                                            <el-input-number v-model="sortNumber" :min="0" :max="99" :controls="false"
                                                style="width: 70px;height: 24px;" />
                                            <span style="margin: 0 8px;color:#409EFF; "
                                                @click="sortEditSubmit">确定</span>
                                            <span style="color:#F56C6C;" @click="sortCancel">取消</span>
                                        </div>
                                    </el-popover>
                                </template>
                            </p>
                        </template>
                        <!--操作按钮  -->
                        <p class="btn-box" v-if="columnItem.prop === 'button'">
                            <el-button v-if="item?.appNumber <= 0" size="small" text @click="deleteBtn(item)"
                                type="danger">删除</el-button>
                            <el-tooltip v-else effect="dark" content="请先移除所有关联应用" placement="top">
                                <el-button :disabled="item?.appNumber > 0" size="small" text>删除</el-button>
                            </el-tooltip>
                        </p>
                    </template>
                </div>
            </draggable>
            <div v-else style="text-align: center; min-height: 200px;">暂无数据</div>
        </div>
        <!-- 分页 -->
        <div style="position: relative;padding-top: 15px;">
            <el-pagination class="app-pagination" :current-page="pagination.page" :page-size="pagination.size"
                :page-sizes="pageSizes" :total="total" @size-change="pageSizeChange" @current-change="pageNoChange"
                layout="total, sizes, prev, pager, next" />
        </div>
    </div>
</template>

<script setup lang="ts">
import { onMounted, reactive, ref, watch } from 'vue';
import { VueDraggableNext } from 'vue-draggable-next'
import { ElMessage, ElMessageBox } from 'element-plus'
const draggable = VueDraggableNext

const props = defineProps({
    tableColumn: {
        required: true,
        type: Array<{ label: string, prop: string, slot?: string }>,
        default: () => []
    },
    tableData: {
        type: Array<any>,
        default: () => []
    },
    pagination: {
        required: true,
        type: Object,
        default: () => { page: 1; size: 20 }
    },
    total: {
        required: true,
        type: Number,
        default: 0
    },
    pageSizes: {
        type: Array,
        default: () => [20, 50, 100]
    },
    hideOnSinglePage: { // 只有一页时是否隐藏
        type: Boolean,
        default: false
    },
})
const data = ref([]) // 表格数据变量
const sortTip = ref('应用中心标签过滤器中,标签按照标签序号由大到小从左向右排列,序号相等按照创建时间由近到远排列')
const popoverVisible = ref('')
const sortNumber = ref(null)

const emit = defineEmits(['size-change', 'current-change', 'sort-change'])

// 生命周期
onMounted(() => {
    data.value = props.tableData
})

// 监听
watch(data, (newValue, oldValue) => {
    console.log('newValue', newValue[0])
})

/*** 声明方法 ****/
const pageSizeChange = (val: any) => {
    emit('size-change', val)
}
const pageNoChange = (val: any) => {
    emit('current-change', val)
}

// 拖拽结束
const logEvent = (event) => {
    console.log('拖拽结束: ', event);
}

// 删除
const deleteBtn = (row) => {
    console.log('删除')
    ElMessageBox.confirm(
        `您正在进行删除标签操作,是否确定要删除“${row.name}”?`,
        '提示',
        {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
        }
    )
        .then(() => {
            ElMessage({
                type: 'success',
                message: '删除成功',
            })
        })
        .catch(() => {
        })
}
// 编辑排序
const editSort = (row) => {
    // emit('sort-change', row)
    console.log('编辑排序')
    popoverVisible.value = row.id
    sortNumber.value = row.num
}

const sortEditSubmit = () => {
    emit('sort-change', sortNumber.value)
    console.log('确定排序')
    sortNumber.value = null
    popoverVisible.value = ''
}
const sortCancel = () => {
    console.log('取消编辑排序')
    sortNumber.value = null
    popoverVisible.value = ''
}
</script>

<style lang="scss" scoped>
.table-box {
    width: 100%;

    .table-header {
        display: flex;
        justify-content: space-between;
        padding: 0 10px;
        background-color: #eff2ff;

        >div {
            flex: 1;
            text-align: left;
            height: 40px;
            line-height: 40px;
            display: flex;
            align-items: center;

        }
    }

    .table-item {
        height: 40px;
        line-height: 40px;
        display: flex;
        justify-content: space-between;
        border-top: 1px solid rgba($color: #ccc, $alpha: 0.4);
        padding: 0 10px;

        >p {
            flex: 1;
            text-align: left;
        }

        &:last-child {
            border-bottom: 1px solid rgba($color: #ccc, $alpha: 0.4);
        }
    }
}

// 标签排序编辑
.sort-edit-box {
    background-color: #fff;
    font-size: 12px;
    display: flex;
    align-items: center;

    >span {
        white-space: nowrap;
        cursor: pointer;
    }
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值