vue3手写简易表格

因为项目需求,需要在表格中双击某一列的值时,那一列变成可编辑的状态,elementui里面表格满足不了需求,只能手写

<template>
    <div class="table_container">
        <div class="header">
            <div :style="{ 'width': getScaleByUI(40) + 'px' }" v-if="serialNumber">序号</div>
            <div v-for="(item, index) in header" :key="index" :style="{ 'width': getScaleByUI(item.width) + 'px' }">
                {{ item.label }}
            </div>
        </div>
        <div class="body">
            <div class="body_item" v-for="(items, indexs) in tableData" :key="indexs"
                :style="{ backgroundColor: indexs % 2 == 0 ? '' : '#303135' }">
                <div :style="{ 'width': getScaleByUI(40) + 'px' }" v-if="serialNumber">{{ indexs + 1 }}</div>
                <div v-for="(item, index) in header" :key="index" :style="{ 'width': getScaleByUI(item.width) + 'px' }">
                    <el-tooltip v-if="!item.isOperation" class="box-item" effect="light" :content="items[item.prop]"
                        placement="top-start">
                        <div class="ellipsis font" v-if="!item.canDouble">{{ items[item.prop]
                        }}</div>
                        <el-input style="width: 100%;height: 100%;" :readonly="readonly" @dblclick="change(item)"
                            v-model="items[item.prop]" class="w-50 m-2" size="large" @change="changeName(item, items)" @blur="blur(item)" />
                    </el-tooltip>
                    <div v-if="item.isOperation" style="width: 100%;display: flex;"
                        :style="{ 'justify-content': item.operation.length == 1 ? 'center' : 'space-between' }">
                        <div v-for="(i, n) in item.operation" :key="n" :style="{ 'color': i.color }" style="cursor: pointer"
                            @click="i.buttonClick(items, indexs)">{{ i.label }}</div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>
<script setup lang='ts'>
import { getScaleByUI } from "@/utils/tools.ts";
import { ref } from "vue";
interface props {
    header: any,
    tableData: any,
    serialNumber:boolean  //是否显示序号
}
defineProps<props>();
const emit = defineEmits(['onChange'])
const readonly = ref(true);
const change = (item: any) => {
    if (item.canDouble) {
        readonly.value = false
    }
}
const changeName = (item: any,items:any) => {
    if (item.canDouble) {
        readonly.value = true;
        emit('onChange',items);
    }
}
const blur = (item: any) => {
  if (item.canDouble) {
    readonly.value = true;
  }
};
</script>
<style scoped lang='scss'>
.table_container {
    width: 100%;

    .header {
        width: 100%;
        height: 30px;
        background: #303135;
        font-size: 12px;
        font-family: Alibaba PuHuiTi, Alibaba PuHuiTi;
        font-weight: 400;
        color: #E5E5E5;
        line-height: 30px;
        text-align: center;
        display: flex;
    }

    .body {
        width: 100%;
        .body_item {
            width: 100%;
            height: 30px;
            display: flex;
            text-align: center;
            font-size: 12px;
            font-family: Alibaba PuHuiTi, Alibaba PuHuiTi;
            font-weight: 400;
            color: #E5E5E5;
            line-height: 30px;

            .font {
                padding: 0 6px;
            }

            ::v-deep(.el-input__wrapper) {
                background-color: transparent !important;
                box-shadow:none;
            }

            ::v-deep(.el-input__inner) {
                width: 100%;
                height: 100%;
                color: #E5E5E5;
                text-align: center;
                font-size: 12px;
            }
        }
    }
}</style>

其中的getScaleByUI是用来做自适应的

  // 获取当前屏幕大小与1920的比列,计算大小
  export const getScaleByUI = (size:number) =>{
    const scale = document.documentElement.clientWidth / 1920;
      return size * scale;
  }

父组件使用方式

 <myTable :serialNumber="true" :header="watchhouseHeader" :tableData="watchhouseTableData" @onChange="change"></myTa
const change = (item: any) => {
    console.log(item, "item");
}
const detailsRow = (row: any, index: number) => {
    console.log(row, index);
}
const watchhouseHeader = ref([{
    label: "名称",
    prop: "name",
    width: 100,
    canDouble: true,  //该项是否可以双击编辑
}, {
    label: "编号",
    prop: "id",
    width: 80
}, {
    isOperation: true,  //是否是操作选项
    label: "操作",
    width: 60,
    operation: [{
        label: "查看",
        color: "#73AFFE",  //字体颜色
        buttonClick: detailsRow,  //点击后执行的函数
    }]
}]);
let watchhouseTableData = ref([{
    name: "哇哈哈",
    id: 13246
}, {
    name: "哇哈哈",
    id: 13246
},]);

正常情况的效果图片
在这里插入图片描述
双击后的效果图片
在这里插入图片描述
失去焦点后,会触发onChange,会返回当前行的数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值