这个面试题是一个微信团队的面试官给的技术题,当然也不算太难,思路正确的话,挺快就能完成(当然最后没能打入tc内部,在最后一轮技术主管面试的时候没能通过,大概是因为项目的实战经验问题吧)。对于这个动态表格的内容,本该在10几天前就发出来的。但是由于要出门找工作,就一直耽搁下来了。虽然还没找到工作,但还是先发出来,要不然之后就更没时间,忘得更彻底了~~~~
先来一波效果图
题目要求
使用vue做一个表格编辑的组件,功能包括:1.修改单元格内容 2.动态增删行、列 3.发送数据给后台(模拟即可)
1.解题思路
拿到这个题,肯定是先百度一波,在各类论坛、博客上查找看有没有类似的人做过这类题。答案显而易见,无。那没办法,只能自己操作一波了。分析了一下题目,因为之前有做过vue的todoMvc案例,所以呢,这里的编辑单元格内容便借鉴了之前的方法,实现还是很快的。这个题中,稍微有点难度的就是动态增删行和列了。增删行的话还是挺简单的,但是在这基础上海需要增删列,着实需要好好思考下表格的布局(数据的分配),因为在增删列之后进行增删行操作对表格数据的分配还是挺有意思的。
初始表格数据
//表格初始数据
dataList: {
tableHead: ["姓名", "年龄", "性别"],
tableBody: [
{ body1: "小白", body2: 18, body3: "女" },
{ body1: "小黑", body2: 19, body3: "男" },
{ body1: "小红", body2: 21, body3: "女" },
{ body1: "小黄", body2: 22, body3: "男" },
{ body1: "小绿", body2: 23, body3: "女" }
]
}
在这里,博主的阶梯思路是将thead,和tbody的数据装在两个数组当中,在点击增删行列的时候动态对数据进行增删操作。哦,对了,这之后对单元格的编辑操作就会有些许问题,单元格的定位会混乱。解决办法就是通过定位单元格的横纵坐标(索引)来实现双击单元格编辑功能。
对于模拟发送后台数据这个问题,还是比较简单的,在这里,博主将请求封装在了工具函数之中(毕竟做得越多越好,面试成功的机会越大嘛):
api接口封装
import axios from "axios";
// 提交表格数据接口
export const submitTableData = data => axios.post("/submitData", data);
模拟发送请求
// 提交表格数据
submit() {
let params = {
tableHead: JSON.stringify({ ...this.dataList.tableHead }),
tableBody: JSON.stringify({ ...this.dataList.tableBody })
};
submitTableData(params)
.then(res => {
let { code, data } = res;
if (code === 0) {
console.log(提交成功);
}
})
.catch(err => {
console.log(err);
});
}
时间过得太久了,很多解题过程中遇到的问题也不大想得起来了,大家见谅哈。最后贴一波代码(这里我将表格的数据抽出来放到父组件,通过组件传参传入子组件)。对了,想要完整项目的可以访问我的github哦~~~
父组件
<template>
<div id="app">
<input-click
:dataList="dataList"
:keyBody="keyBody"
:bodyRow="bodyRow"
@addRow="addRow"
@delRow="delRow"
@addCol="addCol"
@delCol="delCol"
/>
<!-- 提交表格数据 -->
<div style="textAlign:center">
<button @click="submit">提交表格数据</button>
</div>
</div>
</template>
<script>
import InputClick from "./components/InputClick";
import { submitTableData } from "@/api/apis";
export default {
components: {
InputClick
},
data() {
return {
// 表格初始数据
dataList: {
tableHead: ["姓名", "年龄", "性别"],
tableBody: [
{ body1: "小白", body2: 18, body3: "女" },
{ body1: "小黑", body2: 19, body3: "男" },
{ body1: "小红", body2: 21, body3: "女" },
{ body1: "小黄", body2: 22, body3: "男" },
{ body1: "小绿", body2: 23, body3: "女" }
]
},
//tableBody对象key值数组
keyBody: ["body1", "body2", "body3"],
// 初始表格行
bodyRow: {
body1: "",
body2: "",
body3: ""
}
};
},
methods: {
// 添加行
addRow(index) {
this.dataList.tableBody.splice(
index + 1,
0,
JSON.parse(JSON.stringify(this.bodyRow))
);
},
// 删除行
delRow(index) {
this.dataList.tableBody.splice(index, 1);
},
// 添加列
addCol(length) {
let key = "body" + length;
this.keyBody.push(key);
this.dataList.tableHead.splice(length, 0, "");
this.dataList.tableBody.forEach((item, index) => {
this.dataList.tableBody[index] = {
...this.dataList.tableBody[index],
[key]: ""
};
});
this.bodyRow = { ...this.bodyRow, [key]: "" };
},
// 删除列
delCol() {
let length = this.dataList.tableHead.length;
let keyBodyLength = this.keyBody.length - 1;
this.dataList.tableHead.splice(length - 1, 1);
this.dataList.tableBody.forEach((item, index) => {
delete item[this.keyBody[keyBodyLength]];
});
this.keyBody.pop();
},
// 提交表格数据
submit() {
let params = {
tableHead: JSON.stringify({ ...this.dataList.tableHead }),
tableBody: JSON.stringify({ ...this.dataList.tableBody })
};
submitTableData(params)
.then(res => {
let { code, data } = res;
if (code === 0) {
console.log(提交成功);
}
})
.catch(err => {
console.log(err);
});
}
}
};
</script>
<style lang="less" scoped>
</style>
子组件
<template>
<div class="table-edit">
<table>
<thead style="textAlign:left">
<tr>
<th
v-for="(val, index) in dataList.tableHead"
:key="index"
@dblclick="editText($event,dataList.tableHead, index)"
>
<input
v-if="showInputHead === index"
type="text"
@blur="inputStred(dataList.tableHead, index)"
v-focus
v-model="text"
/>
<span v-else>{{ val }}</span>
</th>
<th>
<button @click="delCol">删除列</button>
<button @click="addCol">新增列</button>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in dataList.tableBody" :key="index">
<td
v-for="(val, k, i) in item"
:key="i"
@dblclick="editText($event,dataList.tableBody, index, i)"
>
<input
v-if="showInputRow === index && showInputCol === i"
type="text"
@blur="inputStred(dataList.tableBody, index, k)"
v-focus
v-model="text"
/>
<span v-else>{{ val }}</span>
</td>
<td>
<button @click="delRow(index)">删除</button>
<button @click="addRow(index)">添加</button>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
props: {
dataList: {
type: Object,
default: () => {}
},
keyBody: {
type: Array,
default: []
},
bodyRow: {
type: Object,
default: () => {}
}
},
data() {
return {
showInputRow: "", //单元格横坐标
showInputCol: "", //单元格纵坐标
showInputHead: "", //显示隐藏输入框
text: "" //输入框编辑内容
};
},
methods: {
// 双击编辑
editText(e, data, indexRow, indexCol) {
this.text = e.target.innerText;
if (data === this.dataList.tableBody) {
this.showInputCol = indexCol;
this.showInputRow = indexRow;
} else this.showInputHead = indexRow;
},
// 失焦-取消编辑
inputStred(data, indexRow, key) {
data == this.dataList.tableBody
? (data[indexRow][`${key}`] = this.text)
: (data[indexRow] = this.text);
this.showInputRow = "";
this.showInputCol = "";
this.showInputHead = "";
this.text = "";
},
// 添加行
addRow(index) {
this.$emit("addRow", index);
},
// 删除行
delRow(index) {
this.$emit("delRow", index);
},
// 添加列
addCol() {
let length = this.dataList.tableHead.length + 1;
this.$emit("addCol", length);
},
// 删除列
delCol() {
this.$emit("delCol");
}
},
// 定义input自动聚焦指令
directives: {
focus: {
inserted: function(el) {
el.focus();
}
}
}
};
</script>
<style lang="less" scoped>
.table-edit {
table {
margin: 20px auto;
border-collapse: collapse;
border: 1px solid #ccc;
width: 800px;
line-height: 18px;
thead {
tr {
border: 1px solid #ccc;
th {
border: 1px solid #ccc;
width: 50px;
height: 20px;
span {
width: 100%;
display: inline-block;
}
input {
width: 100%;
height: 100%;
display: inline-block;
border: 0;
}
}
}
}
tbody {
tr {
border: 1px solid #ccc;
td {
border: 1px solid #ccc;
width: 50px;
height: 20px;
span {
width: 100%;
display: inline-block;
}
input {
width: 100%;
height: 100%;
display: inline-block;
border: 0;
}
}
}
}
}
}
</style>
最后附上项目github链接地址:tableEdit