JavaScript代码绘制课程表
任务要求
要求:把一个json字符串格式的课程表数据,在页面上绘制成一周的课表
数据样例:
var data = [
{
XKBH: "R0101",
KCMC: "*思想和中国特色*理论体系概论",
JSXM: "任XX",
SJDD: "周一3-5节,尚农楼1-17;..周四6-7节,尚农楼1-17;",
},
{
XKDM: "R0187",
KCMC: "中国近现代史纲要",
JSXM: "李X",
SJDD: "周二6-7节,普洱善御楼1-02;..周四1-2节,普洱尚射楼3-01;",
},
{
XKBH: "R0199",
KCMC: "管理信息系统",
JSXM: "王XX",
SJDD: "周一6-7节,普洱善御楼1-02;..周四8-9节,普洱尚射楼3-01;..周五1-2节,普洱尚射楼3-01;",
}
];
绘制结果样例
解决思路
- 绘制课程表样式的表格
- 解析json字符串数据,分离出各个信息
- 给每个表格格子命名
- 把相应的信息添加到对应的表格位置
- 解析该堂课占用的课节数,合并相应数量的单元格
- 把被合并的单元格元素删除
- 解决课程表时间冲突问题(怎样放置相应信息使表格不错乱,并且得出课程冲突的具体信息)
实现所使用到的框架技术:jquery
具体实现
一、绘制课程表表格
绘制表格元素的js方法。
注意:给表格、每一个格子元素和行元素都添加上唯一的标识符,即(class名称),方便之后添加对应课程信息使用,这里建议使用字母和数字,对周信息和课节信息进行唯一标识,比如(w1_j1)标识周一第一节课。
function createCourseTable(idName) {
var div_ = $("." + idName);
div_.css({ margin: "30px auto" });//表格居中,添加上下边距
var remind = '<h3 class="course_remind">课程表时间发生冲突,以下课表数据将不再准确!</h3>';
div_.html(remind);//添加记录信息
div_.append('<table class="tableCourse"></table>');//添加表格
var table_ = $(".tableCourse");
var tr_;
for (var i = 0; i <= 13; i++) {
if (i == 0) {
//添加周信息
table_.append('<tr class="headCourse"><th class="th_course"></th><th class="th_course">周一</th><th class="th_course">周二</th><th class="th_course">周三</th><th class="th_course">周四</th><th class="th_course">周五</th><th class="th_course">周六</th><th class="th_course">周天</th></tr >');
} else {
//添加时段信息
//<tr class="j1"></tr>
table_.append('<tr class="j' + i + '"></tr>');
tr_ = $(".j" + i);
//<th>1</th>
tr_.append('<th class="th_course">' + i + '</th>');
for (var j = 1; j <= 7; j++) {
//<td id="w1_j1"></td>
tr_.append('<td id="w' + j + '_j' + i + '" class="td_course"></td>');
}
}
}
}
使用方法
创建一个div块元素,给定一个class名称。
在js代码块中执行表格创建方法
该绘制方法的执行结果的部分样例代码
执行结果
给表格添加相应的样式,使之美观
/*课程表样式*/
.class_schedule {
width: 1000px;
}
.tableCourse {
table-layout: fixed;
width: 100%;
}
.th_course, .td_course, .tableCourse {
border-style: solid;
border-width: 2px;
border-color: rgb(156, 202, 213);
padding: 10px 8px;
}
.headCourse {
background-color: rgb(193, 235, 248);
}
.th_course {
text-align: center;
}
.j1, .j2, .j3, .j4, .j5 {
background-color: aquamarine;
}
.j6, .j7, .j8, .j9, .j10 {
background-color: rgb(235, 204, 163);
}
.j11, .j12, .j13 {
background-color: rgb(104, 115, 197);
}
.course_location {
font-weight: bold;
}
/*提示文字样式*/
.course_remind {
color: red;
display: none;
}
无数据的表格样式
到此时,空表就绘制完成了,接下来只需要往里面添加相应的数据,即可使它成为一张完整的课程表。
二、解析json字符串中包含的数据
1、解析基本数据
解析出可以直接得出的信息
下面是执行解析、添加数据的总调用方法
//数据模型
//var data = [
// {
// XKBH: "R0101",
// KCMC: "*思想和中国特色*理论体系概论",
// JSXM: "任XX",
// SJDD: "周一3-5节,尚农楼1-17;..周四6-7节,尚农楼1-17;",
// },
// {
// XKBH: "R0199",
// KCMC: "管理信息系统",
// JSXM: "王XX",
// SJDD: "周一6-7节,普洱善御楼1-02;..周五1-2节,普洱尚射楼3-01;",
// }
//];
//根据json对象解析出对应的数据,并在表格中展示
function classSchedule(data) {
data = JSON.parse(data);
//先清空record
record = "";
var temp;//课程对象
var id;//课程id
var lesson;//课程名称
var teacher;//教师
var date;//课程时间
for (var i = 0; i < data.length; i++) {
temp = data[i];
id = temp.XKBH;
lesson = temp.KCMC;
teacher = temp.JSXM;
//解析时间地点信息
date = resolveDate(temp.SJDD.toString());
//把数据添加到相应的位置
addHtml(id, lesson, teacher, date);
}
};
在这个主要方法中,把json对象转换成json对象,而且这个对象所包含的是多个课程信息的数组,通过循环可以遍历出每一个课程的相应信息。
这样就可以很容易的得出每一个课程的课程id、课程名称、任课教师的信息。
但是时间地点信息在一串数据里。
这里的难点是解析出这串数据里所包含的各个周信息,课节信息,位置信息。
我们需要将它所包含的时间和地点信息逐一解析出来。
在这,接着调用解析时间地点的方法,传入这一整个时间地点的数据。
这里的思路是把解析出来的各个数据封装到一个数组里,返回出来,和其它已经解析出来的信息统一的一起使用。
这里自定义一个对象,包含着周、开始课节、结束课节和位置的相应属性。
下面是记录信息的对象
///自定义记录解析完的上课时间、地点的类(对象)
function ReDate(week, timeBegin, timeEnd, location) {
this.week = week;
this.timeBegin = timeBegin;
this.timeEnd = timeEnd;
this.location = location;
}
接着是具体的解析数据代码。
下面是解析时间地点的主要方法
//数据样例
//"周二6-8节,普洱善御楼1-02;..周四1-2节,普洱尚射楼3-01;"
//根据课程时间、地点信息的数据解析出每一项结果
function resolveDate(date) {
date = date.split(";");//拆分每一个课程信息
var reDate = new Array();//存放解析完的数据对象
//"周二6-8节,普洱善御楼1-02"
for (var i = 0; i < date.length - 1; i++) {
// alert("d="+date[i]);
var temp = date[i].split(",");
// alert("temp="+temp);
if (i == 0) {
week = temp[0].substr(0, 2);
} else {
week = temp[0].substr(2, 2);
}
week = resolveWeek(week);
var patt = /\d{1,2}[-]{1}\d{1,2}/;
var time = patt.exec(temp[0]);
// alert("time="+time);
time = time[0].toString().split("-");
reDate[i] = new ReDate(week, time[0], time[1], temp[1]);
}
return reDate;
}
先观察信息的组成架构,每一个信息都是通过分号(;)分隔。
通过string的分割字符串方法,通过分号分割出一个一个分离的数据,并以数组的形式返回。
接着创建一个存放数据对象的数组,把数据解析完成放到对象里,然后把对象放到数组里,返回,方便统一使用。
因为数据拆分成一个个分开的数据,且存放于数组中,我们遍历数组,再次接着解析数组中的每个信息。
注意:最后一个通过分号拆分出的字符串信息为空,我们遍历该数组数据时,需要免除对最后一个数据的遍历。
接着是对数据里的每一条记录进行解析
观察数据发现,数据由逗号(,)分隔开时间和地点的数据。
我们通过逗号拆分数据。
数据拆分为单个的信息放在数组里。且都是有两个元素,第一个是时间,第二个是地点。所以可以直接得出位置信息,但是时间和课节需要继续解析。
先对第一个信息继续解析出周信息和课节数信息。
发现开头两个是周的信息,可以截取开头两个字符作为周信息。
但是,有多组课程记录时,第二个记录开始是以两个符号接头的。
所以解析第一个时截取开头两个,其他的截取第三第四个字符。
但是这里一个难点是解析出课节信息。
为了方便使用的是正则表达式匹配这个信息。
var patt = /\d{1,2}[-]{1}\d{1,2}/;//匹配:数字-数字
匹配出的结果是,例如:3-5
接着可以通过“-”拆分字符。
接着调用js中Number对象的格式转换功能解析出单个的开始课节和结束课节。
为了方便在表格里插入课程数据,把周信息也转换成对应的数字。
下面是解析周信息对应的代码
//根据周信息解析出对应代码
function resolveWeek(week) {
switch (week) {
case "周一": week = "1"; break;
case "周二": week = "2"; break;
case "周三": week = "3"; break;
case "周四": week = "4"; break;
case "周五": week = "5"; break;
case "周六": week = "6"; break;
case "周日": week = "7"; break;
}
return week;
}
然后把解析出来的周信息,开始课节,结束课节,位置信息,存放在自定义对象中,放入数组。等到循环结束,把数据返回到主要调用方法里调用添加信息的方法。
调用添加信息的方法。传入课程代码,课程名称,教师,周,开始结束课节,位置。
下面是调用课程信息添加到表格的方法,传入某节课的相关信息。
方法外是冲突信息的记录变量。直到所有方法运行结束可以一并返回到调用的位置。
var record = "";//记录课程冲突信息
//把对应数据添加到课程表里
//课程代码,课程名称,教师,周,开始时间,结束时间,位置
//问题:可能存在课程冲突情况
function addHtml(id, lesson, teacher, date) {
var temp;
for (var i = 0; i < date.length; i++) {
temp = date[i];
var l = $("#w" + temp.week + "_j" + temp.timeBegin);
if (l.length > 0 && l[0].innerText == "") {
//在表格中加入课程数据
l.html("<span class='course_id'>" + id + "</span> <span class='course_lesson'>" +
lesson + "</span><br><span class='course_teacher'>"
+ teacher + "</span><br>" + "<span class='course_location' >" +
temp.location + "</span>"
);
} else {
//说明该位置已经被其它课程占用,在冲突位置或者被合并位置
//循环往上找到冲突信息所在位置
var temp2;
for (var j = temp.timeEnd; j > 0; j--) {
temp2 = $("#w" + temp.week + "_j" + j);
if (temp2[0] != null && temp2.text() != "") {
//添加原课程冲突信息
record += "<br>【《 " + temp2.children('.course_id').text() + " " + temp2.children('.course_lesson').text() + " " + temp2.children('.course_teacher').text() + " 》";
//添加现课程冲突信息
record += "和《 " + id + " " + lesson + " " + teacher + " 》】";
}
}
//退出该层循环
continue;
}
var s = temp.timeEnd - temp.timeBegin;
//合并单元格
l.attr('rowspan', s + 1);
var object;//元素对象
var token = false;//标记合并单元格时是否会有冲突:【false】没有时间冲突,【true】有时间冲突
for (var j = 1; j <= s; j++) {
object = $("#w" + temp.week + "_j" + (Number.parseInt(temp.timeBegin) + j));
//该元素要合并的单元格所在的元素存在 并且元素的内容为空,则不冲突
if (object.length > 0 && object[0].innerText == "") {
object.remove();
} else if (object.length > 0) {
//若要合并的元素存在,但是内容不为空,则也冲突
token = true;
//记录冲突课程信息
record += "<br>【《 " + object.children('.course_id').text() + " " + object.children('.course_lesson').text() + " " + object.children('.course_teacher').text() + " 》";
//添加现课程冲突信息
record += "《 " + id + " " + lesson + " " + teacher + " 》】";
object.remove();
}
else {
//上面删除冲突的信息后
//可能存在单元格不存在的情况
token = true;
}
}
//有冲突则记录,并删除冲突的信息
//这样删除有数据的单元格可能存在空缺的单元格
//所有需要把空缺的单元格找回
if (token == true) {
//把丢失的单元格补充回来
//往下循环看丢失的格子并找回
var end = Number.parseInt(temp.timeEnd);
for (var j = 13; j > end; j--) {
object = $("#w" + temp.week + "_j" + (Number.parseInt(temp.timeEnd) + j));
if (object.length == 0) {
var obj;
//循环找到丢失元素之前的元素
for (var k = Number.parseInt(week); k > 0; k--) {
obj = $("#w" + k + "_j" + (Number.parseInt(temp.timeEnd) + j));
//若找到则在元素之后添加丢失的元素,没找到则继续循环向前找
if (obj.length > 0) {
obj.after("<td id='w" + temp.week + "_j" + (Number.parseInt(temp.timeEnd) + j) + "'></td>");
break;
}
}
} else {
//若该元素之下的第一个
break;
}
}
token = false;
}
}
}
首先是对传入的某天某次课的信息添加到对应的表格位置。
这里用到周信息和课节信息,进行拼接出格子对应的标识符,以便选中该格子,在该格子中进行信息的添加。
var l = $("#w" + temp.week + "_j" + temp.timeBegin);//例如:w1_j1
选中后即可在里面添加信息,同时根据课节信息,判断出这堂课要上几个课节,然后合并对应数量的列。
注意:合并后,被合并的对应位置格子会向右挤出,也就是会产生格子溢出。
这里的解决办法是:根据被合并的格子位置信息,选中并删除这个元素。
例如:格子添加数据的位置(w1_j1),有2个课节数,就要向下合并两个格子,即格子(w1_j2)被合并了,所以根据这个信息,把添加的数据的开始课节增加1,对应拼接出的信息就是被合并的格子位置,可以选中这个元素并删除它。
多个元素合并也是同理。
下面是jquery对象删除自身元素的方法。
接下来是整个算法最麻烦的地方:课程时间冲突处理。
添加课程信息时会有以下几个冲突情况:
- 添加课程时,该位置已经有数据在该位置上。
- 添加数据时,该位置不存在,即该位置已经被其它课程合并了。
- 添加信息并合并格子后,需要删除被合并的格子,但是要删除(即被合并)的格子已经有其它课程的信息。
- 第三条的处理,把该冲突信息记录下来,并把该有信息的格子删除,会导致删除的格子合并过的格子有空缺。
解决办法:
第一条处理:不添加该信息,但是记录改位置课程的冲突信息。
第二条处理:也不添该信息,但是从该位置的列往上遍历,找到发生冲突的课程,记录冲突信息。
第三条处理:在删除有信息的格子之前,记录冲突信息,再删除。
第四条处理:从添加的信息中,找到最后课节信息,往下遍历,判断该位置是否有元素存在,查找到不存在时,通过逻辑找到该格子的横排的前一个格子,在前一个格子后面添加上该元素。直到遍历一整列。
这里具体冲突解决的措施就不再细讲,也不太好说了,上面方法里的代码和文字解决办法里写的很明确了。
最后:可以在调用表格创建方法时,就传入数据。表格创建完成即刻调用课程信息添加绘制的方法,接着在所有方法执行完毕,检测记录冲突信息的变量是否为空,不为空把提示信息变显眼,提示用户,接着把冲突信息层层返回到最外层的调用,供调用着对冲突信息进行处理。
最终执行结果:
下面是没有冲突的课程表展示
有冲突时,显示冲突信息(存在四个课时段的冲突)
课表显示
本文地址:https://blog.csdn.net/l210148678/article/details/111144933
上一篇: js练习题
下一篇: paddleOCR环境配置教程