根据所选的起始日期间隔,自动生成对应行数的表格,并且支持在第一行第一列的输入框内粘贴表格的数据

本文介绍如何在前端实现从Excel文件中复制数据并粘贴到网页表格中,包括使用day.js生成时间范围内的表格及处理不同格式的粘贴数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目需求是:根据选择的起始时间,下面的表格自动生成,并且表格里面的输入框的值支持从.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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值