【原】无脑操作:HTML5 + CSS + JavaScript实现比赛排程
1、背景:朋友请帮忙做一个比赛排程软件
2、需求:
① 比赛人数未知,可以通过文本文件读取参赛人员名称;
② 对参赛人员随机分组,一组两人,两两PK,如果是奇数人数,某一个参赛人员成为幸运儿自动晋级;
③ 比赛线下进行,比赛结束后,可以在线选择每组中晋级人员;
④ 晋级人员进行下一轮比赛分组,依此类推,直至最后一轮。
看完了以上的需求,聪明的你会做出什么样的分析和设计呢?以下是我的愚见。
3、分析:
① 考虑到该朋友的实际情况和业务需求,这个比赛排程软件显然越简单越傻瓜越好,所以在实现架构上不考虑BS架构,而考虑单页面呈现+参赛人员名称文本文档形式。
② 根据需求,大致绘制如下功能示意图,显然这样设计也是为了实现起来方便
4、实现:看到这里,聪明的你肯定有更好的实现方式啦!还请不低赐教哦!以下是我的实现写法
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <meta charset="UTF-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 8 <title>汤胖专用_比赛排程器</title> 9 <style> 10 label { 11 color: red; 12 } 13 14 div { 15 display: inline; 16 margin: 5px; 17 padding: 2px; 18 } 19 20 .initDiv { 21 background-color: black; 22 color: white; 23 } 24 25 .matchDiv { 26 background-color: orange; 27 color: black; 28 } 29 30 .playerDiv { 31 background-color: pink; 32 color: black; 33 } 34 35 .resultDiv { 36 background-color: green; 37 color: white; 38 } 39 40 .resultData { 41 background-color: blue; 42 color: white; 43 } 44 45 .selectDiv { 46 background-color: #666666; 47 color: white; 48 } 49 </style> 50 </head> 51 52 <body> 53 <fieldset> 54 <legend>汤胖专用_比赛排程器の使用说明</legend> 55 <ol> 56 <li>选择的文件必须是utf-8格式</li> 57 <li>使用Chrome浏览器或360浏览器的极速模式</li> 58 <li>第一轮排程时,选择要使用的文本文件(参考模板文件)</li> 59 <li>后续排程时,先点击刷新页面,再点击开始排程,即可使用上轮保存的过关人员</li> 60 </ol> 61 </fieldset> 62 <hr/> 63 <div> 64 <input type="file" id="btnFiles" /> 65 <input type="button" id="btnPlan" value="步骤2、开始排程" /> 66 <input type="button" id="btnSave" value="步骤3、保存数据" /> 67 <input type="button" id="btnUpdate" value="步骤4、刷新页面" /> 68 <hr/> 69 </div> 70 <script> 71 var arr = []; 72 var resultData = []; 73 74 // 扩展数组功能:实现随机排序 75 if (!Array.prototype.shuffle) { 76 Array.prototype.shuffle = function () { 77 for (var j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = 78 this[j], this[j] = x); 79 return this; 80 }; 81 } 82 83 // 扩展数组功能:实现删除指定值元素 84 if (!Array.prototype.removeByValue) { 85 Array.prototype.removeByValue = function (val) { 86 for (var i = 0; i < this.length; i++) { 87 if (this[i] == val) { 88 this.splice(i, 1); 89 break; 90 } 91 } 92 }; 93 } 94 95 // 页面初始化 96 window.onload = function () { 97 var btnFiles = document.getElementById('btnFiles'); 98 var btnPlan = document.getElementById('btnPlan'); 99 var btnSave = document.getElementById('btnSave'); 100 var btnUpdate = document.getElementById('btnUpdate'); 101 102 btnFiles.onchange = importFile; 103 btnPlan.onclick = matchPlan; 104 btnSave.onclick = saveData; 105 btnUpdate.onclick = updatePage; 106 }; 107 108 // 以CSS类名获取元素 109 var getClass = function (classname) { 110 return document.getElementsByClassName(classname); 111 }; 112 113 var importFile = function () { 114 // 获取读取的File对象 115 var selectedFile = document.getElementById("btnFiles").files[0]; 116 if (selectedFile.name) { 117 // 读取选中文件的文件名 118 var name = selectedFile.name; 119 // 读取选中文件的大小 120 var size = selectedFile.size; 121 122 // 读取操作 123 var reader = new FileReader(); 124 // 读取文件的内容 125 reader.readAsText(selectedFile); 126 127 reader.onload = function () { 128 // 当读取完成之后会回调这个函数,然后文件内容存储到result 129 var temparr = this.result.split(/[\s\n]/); 130 temparr.forEach(function (v, i) { 131 if (v != '') { 132 arr.push(v); 133 } 134 }); 135 136 // 第一轮排程时,文本文件内容存储在sessionStorage中,后续均使用sessionStorage 137 sessionStorage.setItem('resultData', arr); 138 }; 139 } 140 }; 141 142 var matchPlan = function () { 143 if (sessionStorage.getItem('resultData')) { 144 arr = sessionStorage.getItem('resultData').split(','); 145 } 146 147 var initLabel = document.createElement('label'); 148 initLabel.className = 'initLabel'; 149 initLabel.innerText = '初始数据:'; 150 document.body.appendChild(initLabel); 151 152 for (var i = 0; i < arr.length; i++) { 153 var tempdiv = document.createElement('div'); 154 tempdiv.id = 'initDiv' + i; 155 tempdiv.className = 'initDiv'; 156 tempdiv.innerText = arr[i]; 157 document.body.appendChild(tempdiv); 158 } 159 160 // 随机排序 161 arr.shuffle(); 162 163 // 换行 164 document.body.appendChild(document.createElement('br')); 165 document.body.appendChild(document.createElement('br')); 166 167 // 显示参赛人员数据 168 var matchLabel = document.createElement('label'); 169 matchLabel.innerText = '随机排序:'; 170 document.body.appendChild(matchLabel); 171 172 for (var i = 0; i < arr.length; i++) { 173 var tempdiv = document.createElement('div'); 174 tempdiv.id = 'matchDiv' + i; 175 tempdiv.className = 'matchDiv'; 176 tempdiv.innerText = arr[i]; 177 document.body.appendChild(tempdiv); 178 } 179 180 document.body.appendChild(document.createElement('hr')); 181 182 var temp = document.createElement('label'); 183 temp.className = 'initLabel'; 184 temp.innerText = '比赛分组:'; 185 document.body.appendChild(temp); 186 187 // 换行 188 document.body.appendChild(document.createElement('br')); 189 document.body.appendChild(document.createElement('br')); 190 191 for (var i = 0; i < arr.length; i++) { 192 if (i % 2 == 0) { 193 var groupLabel = document.createElement('label'); 194 groupLabel.innerText = "第" + (Math.round(i / 2) + 1) + "组:"; 195 document.body.appendChild(groupLabel); 196 197 var player1div = document.createElement('div'); 198 player1div.id = 'playerDiv' + i; 199 player1div.className = 'playerDiv'; 200 player1div.innerText = arr[i]; 201 document.body.appendChild(player1div); 202 } else { 203 var groupLabel = document.createElement('label'); 204 groupLabel.className = 'initLabel'; 205 groupLabel.innerText = " VS "; 206 document.body.appendChild(groupLabel); 207 208 var player2div = document.createElement('div'); 209 player2div.id = 'playerDiv' + i; 210 player2div.className = 'playerDiv'; 211 player2div.innerText = arr[i]; 212 document.body.appendChild(player2div); 213 214 // 换行 215 document.body.appendChild(document.createElement('br')); 216 document.body.appendChild(document.createElement('br')); 217 } 218 } 219 220 document.body.appendChild(document.createElement('hr')); 221 222 var resultLabel = document.createElement('label'); 223 resultLabel.innerText = "过关人员:"; 224 document.body.appendChild(resultLabel); 225 226 // 换行 227 document.body.appendChild(document.createElement('br')); 228 document.body.appendChild(document.createElement('br')); 229 230 for (var i = 0; i < getClass('playerDiv').length; i++) { 231 // 获取比赛分组div元素并绑定双击事件 232 getClass('playerDiv')[i].ondblclick = function () { 233 // 设置比赛分组div元素双击后不能再被双击 234 this.style['pointer-events'] = 'none'; 235 this.setAttribute("class", "selectDiv"); 236 237 var tempdiv = document.createElement('div'); 238 tempdiv.id = 'resultDiv' + i; 239 tempdiv.className = 'resultDiv'; 240 tempdiv.innerText = this.innerText; 241 document.body.appendChild(tempdiv); 242 243 resultData.push(this.innerText); 244 245 for (var i = 0; i < getClass('resultDiv').length; i++) { 246 getClass('resultDiv')[i].ondblclick = function () { 247 document.body.removeChild(this); 248 resultData.removeByValue(this.innerText); 249 250 for (var i = 0; i < getClass('selectDiv').length; i++) { 251 if (this.innerText == getClass('selectDiv')[i].innerText) { 252 // 设置比赛分组div元素可以被双击 253 getClass('selectDiv')[i].style['pointer-events'] = 'auto'; 254 getClass('selectDiv')[i].setAttribute("class", "playerDiv"); 255 } 256 } 257 }; 258 } 259 }; 260 } 261 }; 262 263 // 保存数据供下一轮排程使用 264 var saveData = function () { 265 // 使用HTML5的SessionStorage在当次会话期间在客户端浏览器中存储数据 266 sessionStorage.setItem('resultData', resultData); 267 }; 268 269 // 刷新页面,开始下一轮排程 270 var updatePage = function () { 271 window.location.reload(); 272 }; 273 </script> 274 </body> 275 276 </html>