Vue+element实现树状表格结构编辑+上下左右移动聚焦的input框+回车插入行+可编辑树形结构

备注的输入框按回车可以直接插入一行

直接上垃圾代码需要的自己改去吧

html部分

<template>
            <div class="right">
                <div style="width: 100%;margin: 0 auto;text-align: center; margin-bottom: 50px;">
          
                    <div style=" margin-top: 30px; text-align: left;padding: 20px;min-height: 600px;">
                        <div style="display: flex;display: flex;">
                            <div class="topinfo setBackgroundBlue" style="width: 150px;"> 序号</div>
                            <div class="topinfo setBackgroundBlue" style="width: 280px;">名称</div>
                            <div class="topinfo setBackgroundBlue" style="width: 200px;">
                                <div style="height: 25px;line-height: 25px;">
                                    时间
                                </div>
                                <div style="display: flex;">
                                    <div class="topinfo" style="height: 25px;line-height: 25px;flex: 1.5;">
                                        年
                                    </div>
                                    <div class="topinfo" style="height: 25px;line-height: 25px;flex: 1;">
                                        月
                                    </div>
                                    <div class="topinfo" style="height: 25px;line-height: 25px;flex: 1;">
                                        日
                                    </div>
                                </div>
                            </div>
                            <div class="topinfo setBackgroundBlue" style="width: 70px;"> 页数</div>
                            <!-- <div class="topinfo" style="width: 70px;"> 份数</div> -->
                            <div class="topinfo setBackgroundBlue" style="flex: auto;;">备注</div>
                        </div>
                        <div style="margin-bottom: 100px;" @keydown="handleKeydown" tabindex="0">
                            <el-table :data="treeData1" style="width: 100%;margin-bottom: 20px;" row-key="nodeId" border
                                :cell-class-name="setBackgroundBlue" class="exporttable" :show-header="false"
                                default-expand-all :tree-props="{ children: 'children' }"
                                :cell-style="{ borderColor: 'black' }" :header-cell-style="{ borderColor: 'black' }">
                                <el-table-column prop="nodeIndex" label="序号" width="150">
                                    <template slot-scope="scope">
                                        <div v-if="!scope.row.children || scope.row.children.length == 0">
                                            {{ getindex(scope.row) }}
                                            <!-- <el-input v-model="scope.row.nodeIndex" placeholder="请输入"></el-input> -->
                                        </div>
                                        <div v-else>
                                            {{ scope.row.nodeIndex }}
                                        </div>
                                    </template>
                                </el-table-column>
                                <el-table-column prop="nodeName" label="履历材料" width="280">
                                    <template slot-scope="scope">
                                        <div :style="{ width: '100%' }"
                                            v-if="!scope.row.children || scope.row.children.length == 0">
                                            <el-input v-model="scope.row.nodeName" placeholder="名称"
                                                @focus="handleFocus"></el-input>
                                        </div>
                                        <div v-else>
                                            {{ scope.row.nodeName }}
                                        </div>
                                    </template>
                                </el-table-column>
                                <el-table-column prop="nodeDate" label="时间" width="200">
                                    <template slot-scope="scope">
                                        <div v-if="!scope.row.children || scope.row.children.length == 0"
                                            style="display: flex;">
                                            <!-- <el-date-picker type="date" v-model="scope.row.nodeDate" format="yyyy-MM-dd"
                                                value-format="yyyy-MM-dd" :style="{ width: '100%' }" placeholder="请选择"
                                                clearable></el-date-picker> -->
                                            <el-input v-model="scope.row.year" placeholder="年" style="flex: 1.5;"
                                                @focus="handleFocus"></el-input>
                                            <el-input v-model="scope.row.month" placeholder="月" style="flex: 1;"
                                                @focus="handleFocus"></el-input>
                                            <el-input v-model="scope.row.day" placeholder="日" style="flex: 1;"
                                                @focus="handleFocus"></el-input>
                                        </div>
                                    </template>
                                </el-table-column>
                                <el-table-column prop="nodePages" label="页数" width="70">
                                    <template slot-scope="scope">
                                        <div v-if="!scope.row.children || scope.row.children.length == 0">
                                            <el-input v-model="scope.row.nodePages" placeholder="0"
                                                @focus="handleFocus"></el-input>
                                        </div>
                                        <div v-else>
                                            {{ scope.row.nodePages }}
                                        </div>
                                    </template>
                                </el-table-column>
                                <!-- <el-table-column prop="nodeCopies" label="份数" width="70">
                                    <template slot-scope="scope">
                                        <div v-if="!scope.row.children || scope.row.children.length == 0">
                                            <el-input v-model="scope.row.nodeCopies" placeholder="0"></el-input>
                                        </div>
                                        <div v-else>
                                            {{ scope.row.nodeCopies }}
                                        </div>
                                    </template>
                                </el-table-column> -->
                                <el-table-column prop="nodeNotes" label="备注" min-width="120">
                                    <template slot-scope="scope">
                                        <div v-if="!scope.row.children || scope.row.children.length == 0"
                                            :style="{ width: '100%' }"
                                            @keydown.enter="handleClickRow(scope.row, 'hang')">
                                            <el-input v-model="scope.row.nodeNotes" placeholder="备注"
                                                @focus="handleFocus"></el-input>
                                        </div>
                                        <div v-else>
                                            {{ scope.row.nodeNotes }}
                                        </div>
                                    </template>
                                </el-table-column>
                                <el-table-column label="操作" width="aotu" :align="'center'">
                                    <template slot-scope="scope">
                                        <div>
                                            <el-button @click="handleClickRow(scope.row, 'jiedian')" type="text"
                                                v-if="findNodeLevelAndPosition(treeData1, scope.row).length <= 1"
                                                size="small">+节点</el-button>
                                            <el-button @click="handleClickRow(scope.row, 'zjd')" type="text"
                                                v-if="!scope.row.nodeDate && findNodeLevelAndPosition(treeData1, scope.row).length < 2"
                                                size="small">+子节点</el-button>
                                            <el-button @click="handleClickRow(scope.row, 'zx')" type="text"
                                                v-if="scope.row.children && findNodeLevelAndPosition(treeData1, scope.row).length < 3"
                                                size="small">+子项</el-button>
                                            <el-button @click="handleClickRow(scope.row, 'del')" type="text"
                                                size="small">删除</el-button>
                                        </div>
                                    </template>
                                </el-table-column>
                            </el-table>
                </div>
            </div>
</template>

js部分

<script>
import { customAlphabet } from 'nanoid'//生成id用的
export default {
    data() {
        return {
            treeData1: [],
            selectedKey: '',
            defaultProps: {
                children: 'children',
                label: 'label'
            },
            currentRow: 0,//现在是第几列
            currentColumn: 0,//现在是第几行
            columns: 6,//每行有多少个输入框
        }
    },
    created() {

    },
    computed: {
        numberOfColumns() {
            return this.currentColumn * this.columns
        },
        numberOfRows() {
            return document.querySelectorAll('.exporttable input').length - 1
        }
    },
    mounted() {
//第一个输入框自动获焦 使键盘可控制焦点
        setTimeout(() => {
            let inputs = document.querySelectorAll('.exporttable input');
            inputs[0].focus();
        }, 500);
    },
    methods: {
//鼠标点击输入框后修正焦点位置
        handleFocus(event) {
            let selected = event.target
            let inputs = document.querySelectorAll('.exporttable input')
            let index = Array.from(inputs).indexOf(selected);
            this.currentRow = index % this.columns
            this.currentColumn = Math.floor(index / this.columns)
        },
//键盘上下左右移动input获焦
        handleKeydown(event) {
            switch (event.keyCode) {
                case 38: // 上
                    if (this.currentColumn > 0) {
                        console.log("上");
                        this.currentColumn--;
                        console.log("现在是第几行", this.currentColumn);
                    }
                    break;
                case 40: //下
                    if (this.currentColumn < this.numberOfRows / 6 - 1) {
                        console.log("下");
                        this.currentColumn++;
                        console.log("现在是第几行", this.currentColumn);
                    }
                    break;
                case 37: // 左
                    if (this.currentRow > 0) {
                        console.log("左");
                        this.currentRow--;
                        console.log("现在是第几列", this.currentRow);
                    }
                    break;
                case 39: // 右
                    if (this.currentRow < this.columns - 1) {
                        console.log("右");
                        this.currentRow++;
                        console.log("现在是第几列", this.currentRow);
                    }
                    break;
            }
            const inputs = document.querySelectorAll('.exporttable input');
            const index = this.numberOfColumns + this.currentRow; // Calculate input index based on row and column
            if (inputs.length > index) {
                inputs[index].focus();
            }
        },
        //计算序号
        getindex(clickedRow) {
            const positionInTree = this.findNodeLevelAndPosition(this.treeData1, clickedRow);
            if (positionInTree.length == 1) {
                return this.treeData1.indexOf(clickedRow) + 1;
            }
            if (positionInTree.length == 2) {
                return this.treeData1[positionInTree[0]].children.indexOf(clickedRow) + 1;
            }
            if (positionInTree.length == 3) {
                return this.treeData1[positionInTree[0]].children[positionInTree[1]].children.indexOf(clickedRow) + 1;
            }
        },
        setBackgroundBlue({ row }) {
            if (!row.children || row.children.length == 0) {

            } else {
                return 'setBackgroundBlue'
            }
        },
//还原在tree中的路径
        findNodeLevelAndPosition(data, clickedRow) {
            const path = [];
            const findPath = (node, targetId) => {
                for (let j = 0; j < node.length; j++) {
                    if (node[j].nodeId === targetId) {
                        path.push(j);
                        return true;
                    }
                    if (node[j].children) {
                        for (let i = 0; i < node[j].children.length; i++) {
                            const childs = node[j].children[i];
                            if (childs.nodeId == targetId) {
                                path.push(j);
                                path.push(i);
                                return true;
                            }
                            if (node[j].children[i].children) {
                                for (let k = 0; k < node[j].children[i].children.length; k++) {
                                    const child = node[j].children[i].children[k];
                                    if (child.nodeId == targetId) {
                                        path.push(j);
                                        path.push(i);
                                        path.push(k);
                                        return true;
                                    }
                                }
                            }
                        }
                    }
                }
            };
            findPath(data, clickedRow.nodeId);
            return path;
        },
        handleClickRow(clickedRow, type) {
            const positionInTree = this.findNodeLevelAndPosition(this.treeData1, clickedRow);
            console.log("此行在数据中的位置路径:", positionInTree);
            let nanoid = customAlphabet('1234567890', 4)
            // let id = nanoid()
            console.log("id:", positionInTree.length);
            if (type == 'del') {
                if (positionInTree.length == 1) {
                    this.treeData1.splice(positionInTree[0], 1,)
                }
                if (positionInTree.length == 2) {
                    this.treeData1[positionInTree[0]].children.splice(positionInTree[1], 1,)
                }
                if (positionInTree.length == 3) {
                    this.treeData1[positionInTree[0]].children[positionInTree[1]].children.splice(positionInTree[2], 1,)
                }
            }
            if (type == 'jiedian') {
                let data = {
                    nodeId: nanoid(),
                    nodeIndex: "",
                    nodeName: '',
                    nodeNotes: "",
                    children: []
                }
                if (positionInTree.length == 1) {
                    this.treeData1.splice(positionInTree[0] + 1, 0, data)
                }
                if (positionInTree.length == 2) {
                    this.treeData1[positionInTree[0]].children.splice(positionInTree[1] + 1, 0, data)
                }

            }
            if (type == 'zjd') {
                if (positionInTree.length == 1) {
                    this.treeData1[positionInTree[0]].children.push({
                        nodeId: nanoid(),
                        nodeIndex: "",
                        nodeName: '',
                        nodeNotes: "",
                        children: []
                    })
                }
                if (positionInTree.length == 2) {

                }
            }
            if (type == 'zx') {
                if (positionInTree.length == 1) {
                    this.treeData1[positionInTree[0]].children.push({
                        nodeId: nanoid(),
                        nodeIndex: "",
                        nodeName: '',
                        nodeDate: '',
                        nodePages: null,
                        nodeNotes: "",
                        nodeCopies: "",
                        children: [],
                    })
                }
                if (positionInTree.length == 2) {
                    this.treeData1[positionInTree[0]].children[positionInTree[1]].children.push({
                        nodeId: nanoid(),
                        nodeIndex: "",
                        nodeName: '',
                        nodeDate: '',
                        nodePages: null,
                        nodeNotes: "",
                        nodeCopies: "",
                    })
                }
            }
            if (type == 'hang') {
                if (positionInTree.length == 2) {
                    this.treeData1[positionInTree[0]].children.push({
                        nodeId: nanoid(),
                        nodeIndex: "",
                        nodeName: '',
                        nodeDate: '',
                        nodePages: null,
                        nodeNotes: "",
                        nodeCopies: "",
                        children: [],
                    })
                }
                if (positionInTree.length == 3) {
                    this.treeData1[positionInTree[0]].children[positionInTree[1]].children.push({
                        nodeId: nanoid(),
                        nodeIndex: "",
                        nodeName: '',
                        nodeDate: '',
                        nodePages: null,
                        nodeNotes: "",
                        nodeCopies: "",
                    })
                }
            }
        }
    }
}
</script>

样式

<style lang="scss" scoped>
.topinfo {
            height: 50px;
            line-height: 50px;
            text-align: center;
            border: 1px solid black;
        }

        .exporttable {
            border: solid 1px black;
        }
  ::v-deep .cell {
        display: flex;
        align-items: center;
    }

    ::v-deep .setBackgroundBlue {
        background-color: #DAE5F6;
    }
</style>

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值