项目需求是:根据选择的起始时间,下面的表格自动生成,并且表格里面的输入框的值支持从.xlsx文件里面粘贴复制,直接填入
解决:这里引入day.js来处理时间生成表格(用npm i dayjs下载),利用改变第一行第一列的输入框的值来解决填入所有输入框
1.在开始时间和结束时间都选择,并且开始时间时间戳要小于结束时间才会生成对应表格(第一行第一个输入框自动获取焦点),否则表格数据为空数组。
2.在.xlsx文件中ctrl+c复制数据
3.因为上面第一行第一列的输入框已经获取焦点和我们已经ctrl+c复制了数据,所以我们直接ctrl+v就行了
html代码如下:
<template>
<div class="clip-board">
<div class="clip-board-header">
<el-date-picker
v-model="beginTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="年/月/日"
size="mini"
@change="selectTime"
>
</el-date-picker>
<span class="span-margin">至</span>
<el-date-picker
v-model="endTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="年/月/日"
size="mini"
@change="selectTime"
>
</el-date-picker>
</div>
<div class="clip-board-body">
<el-table :data="templatePlanList" border show-summary>
<el-table-column label="时间" align="center">
<template slot-scope="scope">
<p>
{{
scope.row.yearMonth == "合计"
? scope.row.yearMonth
: setDate(scope.row.yearMonth)
}}
</p>
</template>
</el-table-column>
<el-table-column align="center">
<template slot="header">
<p>年度交易计划(台)</p>
</template>
<el-table-column label="宋plus dmi" align="center" prop="jfYear">
<template slot-scope="scope">
<el-input
v-model="scope.row.jfYear"
size="small"
placeholder="请输入"
:class="[scope.row.isOneInput ? 'one-input' : '']"
@input="setOneInput(scope.row.isOneInput, scope.row.jfYear)"
></el-input>
</template>
</el-table-column>
<el-table-column label="宋pro dmi" align="center" prop="gfYear">
<template slot-scope="scope">
<el-input
v-model="scope.row.gfYear"
size="small"
placeholder="请输入"
></el-input>
</template>
</el-table-column>
<el-table-column label="秦plus dmi" align="center" prop="dgYear">
<template slot-scope="scope">
<el-input
v-model="scope.row.dgYear"
size="small"
placeholder="请输入"
></el-input>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="月度交易计划(台)" align="center">
<el-table-column label="宋plus dmi" align="center" prop="jfMonth">
<template slot-scope="scope">
<el-input
v-model="scope.row.jfMonth"
size="small"
placeholder="请输入"
></el-input>
</template>
</el-table-column>
<el-table-column label="宋pro dmi" align="center" prop="gfMonth">
<template slot-scope="scope">
<el-input
v-model="scope.row.gfMonth"
size="small"
placeholder="请输入"
></el-input>
</template>
</el-table-column>
<el-table-column label="秦plus dmi" align="center" prop="dgMonth">
<template slot-scope="scope">
<el-input
v-model="scope.row.dgMonth"
size="small"
placeholder="请输入"
></el-input>
</template>
</el-table-column>
</el-table-column>
</el-table>
</div>
</div>
</template>
js代码如下:
<script>
import dayjs from "dayjs";
export default {
data() {
return {
beginTime: "",
endTime: "",
templatePlanList: [],
paste: "",
};
},
methods: {
//给年度计划中的第一列绑定的函数
setOneInput(flag, newValue) {
//这里flag为true说明是第一行第一列的输入框的值发生变化才调用
if (flag) {
// 这里用JSON.stringify可以看你在.xlsx里面复制的文本的格式(里面含有空字符串,\n或者\t),下面分割字符串要用到
//我打印的是复制的文本用" "换行,用\t间隔
console.log(JSON.stringify(newValue), ",,,,,");
//这里判断下是因为可能你没有用复制这个功能,而是自己输入改变的第一行第一列输入框的值,那就不用分割,赋值给其他输入框
if (newValue.indexOf(" ") && newValue.indexOf("\t")) {
let arr = newValue.split(" ");
for (let i = 0; i < arr.length; i++) {
arr[i] = arr[i].split("\t");
}
for (let i = 0; i < arr.length; i++) {
if (this.templatePlanList[i]) {
this.templatePlanList[i].jfYear = arr[i][0] ?? "";
this.templatePlanList[i].gfYear = arr[i][1] ?? "";
this.templatePlanList[i].dgYear = arr[i][2] ?? "";
this.templatePlanList[i].jfMonth = arr[i][3] ?? "";
this.templatePlanList[i].gfMonth = arr[i][4] ?? "";
this.templatePlanList[i].dgMonth = arr[i][5] ?? "";
}
}
}
}
},
setDate(yearMonth) {
return dayjs(yearMonth).format("YYYY年M月");
},
// 选择时间时触发
selectTime() {
if (
this.beginTime &&
this.endTime &&
dayjs(this.beginTime).isBefore(dayjs(this.endTime))
) {
let templatePlanList = [];
// 判断一下开始时间和结束时间差了多少月
let diffMonnth = dayjs(this.endTime).diff(
dayjs(this.beginTime),
"month"
);
//将开始时间的那个月加进去
templatePlanList.push(dayjs(this.beginTime).format("YYYY-MM"));
for (let i = 0; i < diffMonnth; i++) {
//这里用dayjs的api,获取开始时间一个月,二个月,三个月。。。之后的时间,再格式化自己想要的格式
let time = dayjs(this.beginTime)
.add(i + 1, "month")
.format("YYYY-MM");
templatePlanList.push(time);
}
let advances = [];
for (let i = 0; i < templatePlanList.length; i++) {
//当为第一行时isOneInput为true,上面判断是否是第一行第一列的输入框时用
advances.push({
yearMonth: templatePlanList[i],
isOneInput: i===0,
jfYear: "",
gfYear: "",
dgYear: "",
jfMonth: "",
gfMonth: "",
dgMonth: "",
});
}
this.templatePlanList = advances;
//在数据处理好,dom加载完后找到第一行第一列输入框让它获取焦点
this.$nextTick(() => {
const pasteText = document.querySelector(
".one-input > .el-input__inner"
);
if (pasteText) {
pasteText.focus();
}
});
} else {
this.templatePlanList = [];
}
},
},
mounted() {
// 下面是ctrl v之后才会触发,可以拿到复制的数据
// document.addEventListener("paste", (e) => {
// e.preventDefault(); //阻止默认粘贴事件
// e.stopPropagation(); //阻止事件冒泡
// this.paste = (e.clipboardData || window.clipboardData).getData("text"); //以text方式接收粘贴内容
// console.log(this.paste, "paste...");
// });
},
};
</script>
我以为这样需求就ok了,但是…项目部测试的时候发现粘贴复制的格式是不同的,那我上面写的拆分的规则就完全不适用,所以并不能用格式拆分会有很多坑,所以就有了下面的2.0,适用于任何格式的粘贴复制.
原理:利用粘贴复制时可以控制粘贴的格式,默认粘贴成string字符串,我们可以更改成粘贴为html,再去处理html中的表格,拿到表格dom—>td里面的值,进行一个个赋值,这样实现粘贴复制,代码如下:(下面的代码只适合全部粘贴复制,不能精确地在任意行和列开始复制到任意行和列)
<template>
<div class="clip-board">
<div class="clip-board-header">
<el-date-picker
v-model="beginTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="年/月/日"
size="mini"
@change="selectTime"
>
</el-date-picker>
<span class="span-margin">至</span>
<el-date-picker
v-model="endTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="年/月/日"
size="mini"
@change="selectTime"
>
</el-date-picker>
</div>
<div class="clip-board-body">
<el-table :data="templatePlanList" border show-summary>
<el-table-column label="时间" align="center">
<template slot-scope="scope">
<p>
{{
scope.row.yearMonth == "合计"
? scope.row.yearMonth
: setDate(scope.row.yearMonth)
}}
</p>
</template>
</el-table-column>
<el-table-column align="center">
<template slot="header">
<p>年度交易计划(台)</p>
</template>
<el-table-column label="宋plus dmi" align="center" prop="jfYear">
<template slot-scope="scope">
<el-input
v-model.trim="scope.row.jfYear"
size="small"
placeholder="请输入"
@paste.native="paste($event, scope)"
></el-input>
</template>
</el-table-column>
<el-table-column label="宋pro dmi" align="center" prop="gfYear">
<template slot-scope="scope">
<el-input
v-model.trim="scope.row.gfYear"
size="small"
placeholder="请输入"
@paste.native="paste($event, scope)"
></el-input>
</template>
</el-table-column>
<el-table-column label="秦plus dmi" align="center" prop="dgYear">
<template slot-scope="scope">
<el-input
v-model.trim="scope.row.dgYear"
size="small"
placeholder="请输入"
@paste.native="paste($event, scope)"
></el-input>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="月度交易计划(台)" align="center">
<el-table-column label="宋plus dmi" align="center" prop="jfMonth">
<template slot-scope="scope">
<el-input
v-model="scope.row.jfMonth"
size="small"
placeholder="请输入"
@paste.native="paste($event, scope)"
></el-input>
</template>
</el-table-column>
<el-table-column label="宋pro dmi" align="center" prop="gfMonth">
<template slot-scope="scope">
<el-input
v-model="scope.row.gfMonth"
size="small"
placeholder="请输入"
@paste.native="paste($event, scope)"
></el-input>
</template>
</el-table-column>
<el-table-column label="秦plus dmi" align="center" prop="dgMonth">
<template slot-scope="scope">
<el-input
v-model="scope.row.dgMonth"
size="small"
placeholder="请输入"
@paste.native="paste($event, scope)"
></el-input>
</template>
</el-table-column>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import dayjs from "dayjs";
import $ from "jquery";
export default {
data() {
return {
beginTime: "",
endTime: "",
templatePlanList: [],
};
},
methods: {
// ctrl+v会触发该粘贴函数
paste(event, v) {
let rowIndex = v.$index;
this.templatePlanList[rowIndex].jfYear = "";
this.templatePlanList[rowIndex].gfYear = "";
this.templatePlanList[rowIndex].dgYear = "";
this.templatePlanList[rowIndex].jfMonth = "";
this.templatePlanList[rowIndex].gfMonth = "";
this.templatePlanList[rowIndex].dgMonth = "";
this.canPaste(event, this.input);
},
input(v) {
let data = [];
data = this.filterData(v);
this.templatePlanList.map((item1, index1) => {
item1.jfYear = data[index1] ? data[index1][0]?.trim() ?? "" : "";
item1.gfYear = data[index1] ? data[index1][1]?.trim() ?? "" : "";
item1.dgYear = data[index1] ? data[index1][2]?.trim() ?? "" : "";
item1.jfMonth = data[index1] ? data[index1][3]?.trim() ?? "" : "";
item1.gfMonth = data[index1] ? data[index1][4]?.trim() ?? "" : "";
item1.dgMonth = data[index1] ? data[index1][5]?.trim() ?? "" : "";
});
},
// 将html表格转化成数组存起来
filterData(v) {
let data = [];
$(v)
.find("tr")
.each(function () {
var trArr = [];
var tdArr = $(this).children();
for (let i = 0; i < tdArr.length; i++) {
trArr.push($(tdArr[i]).text());
}
data.push(trArr);
});
return data;
},
// 判断是否能复制粘贴
canPaste(event, fun) {
// 先用event.clipboardData || event.originalEvent判断能不能ctrl+v
if (event.clipboardData || event.originalEvent) {
// 再用event.clipboardData || window.clipboardData取数据
var clipboardData = event.clipboardData || window.clipboardData;
// 将ctrl+v的内容转变为text/html格式
var val = clipboardData.getData("text/html");
if (!val) {
this.$message({
message: "你没有复制任何内容",
type: "info",
});
} else {
if (val.indexOf("table") === -1) {
this.$message({
message: "你复制的内容不是Excel选中区域,请检查",
type: "info",
});
} else {
// 一定要阻止默认的,不然粘贴不对,切记
event.preventDefault();
fun(val);
}
}
} else {
this.$message({
message: "浏览器不支持复制",
type: "info",
});
}
},
// 这里转换一下,后端要的是2022-06这种格式,但是显示显示的是2022年6月
setDate(yearMonth) {
return dayjs(yearMonth).format("YYYY年M月");
},
// 选择终止合同的时间时触发
selectTime() {
if (
this.beginTime &&
this.endTime &&
dayjs(this.beginTime).isBefore(dayjs(this.endTime))
) {
// 下面获取的是距离开始时间一年后的时间
let beginApartYear = dayjs(this.beginTime)
.add(1, "year")
.format("YYYY-MM-DD");
let flag =
dayjs(this.endTime).isBefore(dayjs(beginApartYear)) ||
dayjs(this.endTime).isSame(dayjs(beginApartYear));
if (flag) {
let templatePlanList = [];
// 判断一下起止时间
let diffMonnth = dayjs(this.endTime).diff(
dayjs(this.beginTime),
"month"
);
templatePlanList.push(dayjs(this.beginTime).format("YYYY-MM"));
for (let i = 0; i < diffMonnth; i++) {
let time = dayjs(this.beginTime)
.add(i + 1, "month")
.format("YYYY-MM");
templatePlanList.push(time);
}
let advances = [];
for (let i = 0; i < templatePlanList.length; i++) {
advances.push({
yearMonth: templatePlanList[i],
jfYear: "",
gfYear: "",
dgYear: "",
jfMonth: "",
gfMonth: "",
dgMonth: "",
});
}
this.templatePlanList = advances;
} else {
this.$message({
message: "开始日期和结束日期相差不能超过一年!",
type: "info",
});
this.templatePlanList = [];
}
} else {
this.templatePlanList = [];
}
},
},
};
</script>
<style lang='scss' scoped>
.clip-board {
width: 100%;
height: 100%;
flex-direction: column;
.clip-board-header {
padding: 20px 0;
.span-margin {
margin: 0 10px;
}
}
}
</style>