项目是springCloud+vue,前端用的elementUI,有个需求是实现编辑界面字段值、列表数据、和日历的三方数据联动
下面是功能截图
输入框为el-input-number
列表为el-table 可编辑表格(插槽实现)

由于我的逻辑较多,整体代码在400行左右,所以这里只简化说明,大神请绕过,轻吐槽(个人学习vue才一个多月,很多组件的用法或者语法,都还不是很熟悉)
首先引入日历组件,我用的是插槽,日历中要显示自定义内容,还是要用插槽,用例链接elementUI-calender
<el-calendar>
<!-- 这里使用的是 2.5 slot 语法,对于新项目请使用 2.6 slot 语法-->
<template
slot="dateCell"
slot-scope="{date, data}">
<p :class="data.isSelected ? 'is-selected' : ''">
{{ data.day.split('-').slice(1).join('-') }} {{ data.isSelected ? '✔️' : ''}}
</p>
</template>
</el-calendar>
<style>
.is-selected {
color: #1989FA;
}
</style>
项目中引入的日历组件
<template #calendarForm>
<el-calendar v-model="value">
<template slot="dateCell" slot-scope="{ date, data }">
<!--用div的作用是点击单元格范围尽可能的大-->
<div class="calendarDay" @click="showInfo(data)">
<div :class="data.isSelected ? 'selectedDay' : ''">
<div>{{ data.day.split("-").slice(2).join("-") }}</div>
<p :id="data.day" class="numClass"></p>
</div>
</div>
</template>
</el-calendar>
</template>
由于导入进来的日历组件样式尺寸需要调整所以自定义了一些属性来实现截图中的样式。备注:其实边界还有点问题,点击范围为div大小,比单元格差2px
.el-calendar-table .el-calendar-day {
height: 50px;
padding: 2px;
}
.calendarDay {
height: 48px;
box-sizing: border-box;
}
.selectedDay {
height: 48px;
box-sizing: border-box;
background-color: #4385f5;
}
点击日历单元格事件:showInfo(data)
这里需要设置input的值和table行的值
showInfo(data: any) {
console.log(data.day);
const day = data.day;
this.choosedDay = day;
//设置input值,value是要设置的input值,根据id获取p标签的值
[input的值] = document.getElementById(this.choosedDay)?.innerHTML
// 点击时,如果是已拆分的数据列表展示,否则展示
// 判断如果是锁定状态,则界面数据不可编辑 设置disabled属性
}
}
另外的逻辑:点击数字录入框的+、-按钮,日历自定义数据改变,点击【拆分】按钮,根据数字录入框的数据,拆分成多行。
由于+、-按钮组件内没有暴露出现成的事件接口,所以选用了change事件
备注:有一点不好的是点击日历赋值的时候,也会走numChange事件,这个需要单独处理,不然就会陷入死循环,程序崩掉。
this.newPlanData用于存放当前展示的日历单元格的日期和数据对应关系,如 newPlanData={“2021-09-10”:12,“2021-09-12”:8}
所以这是p标签为啥有id的原因,就是为了给它赋值或者从它里面取值
// 数据改变事件函数
numChange(data: any) {
// 判断是否在对象中,如果存在且值一样则不需要校验
const isIn = Object.prototype.hasOwnProperty.call(
this.newPlanData,
this.choosedDay
);
const oldVal = this.newPlanData[this.choosedDay];
if (isIn) {
if (oldVal != data) {
// 大于原数据则校验是否超出总数量
if (data > oldVal) {
} else {
(document.getElementById(this.choosedDay) as any).innerHTML = data;
}
}
} else {
//不存在的话要添加到newPlanData中
}
}
为了减少校验的代码,我们把日历单元格的点击限制在本月以内,切换月份只能点击右上角的按钮
.el-calendar-table :not(.is-range) td.next {
pointer-events: none;
}
.el-calendar-table :not(.is-range) td.prev {
pointer-events: none;
}
日历按钮事件也没有暴露的标准接口,我用的是监听value的变化,用来切换月份
// 监听日历值变化,用于跨月操作
@Watch("value")
dateChg(newVal: any, oldVal: any) {
//日期格式化使用moment.js
const defaultSelectedDate = moment(newVal).format("YYYY-MM-DD");
this.choosedDay = defaultSelectedDate;
console.log("变化的日期", defaultSelectedDate);
if (newVal != "" && oldVal != "") {
const newMonth = newVal.getMonth();
const oldMonth = oldVal.getMonth();
// 新的月份不等于旧的月份,重新赋值
if (newMonth != oldMonth) {
const pTabs = document.getElementsByClassName("numClass");
Array.prototype.forEach.call(pTabs, function (element) {
element.innerHTML = "";
});
const keys = Object.keys(this.newPlanData);
if (keys.length > 0) {
let isContains = false;
//这里是耍了点小聪明,英文p标签的ID变更后里面的值不会跟着变,所以上面清空后,在延迟加载新的数据
setTimeout(() => {
keys.forEach((every) => {
if (document.getElementById(every)) {
(document.getElementById(every) as any).innerHTML =
this.newPlanData[every];
}
// 选择的日期如果有数据,则更新至数字录入框
if (every === defaultSelectedDate) {
//设置值
isContains = true;
}
});
if (!isContains) {
//不包含数据,设置为空
}
}, 300);
}
}
}
}
大致逻辑就是这样,很多细节代码是和业务相关的,在这里就不贴出来了,还望轻喷
本文介绍了一个使用springCloud+vue和elementUI的项目,重点讨论了如何实现编辑界面中el-input-number、el-table和el-calender组件的三方数据联动。通过自定义日历插槽展示内容,并处理各种交互事件,如点击日历单元格、输入框加减按钮以及拆分按钮,确保数据同步。同时,文章提到了在处理过程中遇到的问题,如避免点击事件导致的死循环。
1592

被折叠的 条评论
为什么被折叠?



