前言
最近团队面临解散,上面感觉想把我们一刀切,当天心里就很郁闷,于是想到了换工作,哎不想换现在也不行了。。。。
当时联系到一个我认为不错的大哥,他给了我一道题,我一看,感觉有点水平,大概和HTML5有关系,但是我工作中一直想学但没机会学习,现在也只能硬着头皮做做了。
访问地址我给关了,今早一来,磁盘空间都要挂了,图片“应有尽有”,好吧,伟大的程序员不差...
这是一道面试题
此次考察题目:
1. 用户可以选择1个或多个图片进行上传,支持拖拽文件上传和弹出文件选择窗口2种方式;
2. 用户可以看见上传的过程,清楚每个文件上传的进度;
3. 上传后,用户可以选择不同的图片进行裁剪;
4. 裁剪选择区域的时候,用户可以查看到裁剪后的效果图;
5. 测试能够通过最新版的IE/FF/CHROME
我实现的功能:
1、选择1或者多个图片上传
2、拖曳上传
3、上传状态显示/上传进度条
4、裁剪图片、预览图片、保存裁剪后的图片
基本所有功能皆以完成;
注意事项:
此次题目共花去我两天左右时间,加上平时工作时中午时间,约12小时。
而且这道题需要不只是前端方面的知识,过程中我使用了较熟悉的.net技术,作为服务器端语言,所以本地若需运行需要.net程序运行环境(安装vs2010即可),若无环境,需要给我一定时间上服务器部署以作为演示;
兼容性:
该程序中使用的很多东西都是HTML5里面的,所以兼容性只能做到最新浏览器兼容,我这里对以下浏览器做过测试:
测试过的浏览器:firefox、chrome
应该支持的浏览器:IE10
对于不支持的浏览器:
虽然功能差点,但也能进行操作(渐进增强),
不支持功能:
1、多图片上传
2、拖曳上传
3、上传状态
不足:
1、该功能要做好,个人认为需要至少1周时间,所以我暂时只能做到这个样子;
2、项目中代码未封装、未优化,若有必要,后面点我会封装优化一下;
题目评价
不知道各位大哥是怎么看的,但是就我这水平的小鱼一看,认为该题确实有点水平,就我的知识面来看,在html5出现之前,这就是一坨铁,我所想到的就只有flash可以做。。。
不然就是后端程序相当恶心的配合,最后会得到四个字“费力不讨好”(我知道是5字了。。)
但就该题而言能做起、并且能做好,没有一定水准还真不行。。。。有点自夸的嫌疑了(别喷我承认我查了资料好不)。。。
功能截图
程序主要代码
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 3 <html xmlns="http://www.w3.org/1999/xhtml"> 4 <head> 5 <title></title> 6 <style type="text/css"> 7 body, ol, ul, h1, h2, h3, h4, h5, h6, p, th, td, dl, dd, form, fieldset, legend, input, textarea, select { margin: 0; padding: 0; } 8 body { background: none repeat scroll 0 0 #D1D1D1; font: 14px "宋体","Arial Narrow",HELVETICA; } 9 h1, h2, h3, h4, h5, h6 { font-weight: bold; font-size: 14px; } 10 .over_h{ overflow: hidden;} 11 .clear { clear: both;} 12 13 .image_list { width: 250px; position: fixed; top: 0; bottom: 0; right: 0; overflow-x: hidden; overflow-y: scroll; } 14 .up_image { margin-right: 260px; height: 200px;} 15 .img_tailor { min-height: 200px; margin: 10px 260px 0 0;} 16 17 .box { border: 1px solid #E0E0E0; background: white; } 18 .box .title { background: #336699; padding: 10px; color: White; } 19 20 .up_img { border: 1px dashed #DDDDDD; width: 140px; height: 140px; margin: 10px; float: left; cursor: pointer; text-align: center; } 21 .up_img img{ vertical-align: middle; } 22 .up_img a { position: relative; overflow: hidden; display: inline-block; color: #005197; margin-top: 15px; } 23 .up_img input { position: absolute; right: 0; top: 0; height: 100px; opacity: 0; filter: alpha(opacity=0); cursor:pointer;} 24 25 26 .pre_img { margin: 10px 10px 10px 170px; border: 1px dashed #DDDDDD; height: 140px; overflow-x: hidden; overflow-y: scroll; } 27 .dragAreaOver{ border-color: Red; } 28 29 .image_upload{ margin: 5px; border: 1px solid #E0E0E0; text-align: center; padding: 5px; display: inline-block; position: relative; } 30 .image_upload img{ max-height: 115px; max-width: 115px; } 31 .image_upload .rate { position: absolute; top: 6px; left: 6px; padding: 0 5px; color: White; background: black; border-radius: 5px; filter:alpha(opacity=70); -moz-opacity:0.7; -khtml-opacity: 0.7; opacity: 0.7; } 32 .image_upload .delete { background: url("images/del.png") no-repeat scroll 0 0 transparent; cursor: pointer; height: 16px; position: absolute; right: -6px; top: -6px; width: 16px;} 33 34 .img_list { margin: 10px; } 35 .img_list li { text-align: center; list-style: none;} 36 .img_list li:hover { background-color: #E8F2FD; } 37 .img_list li img{ max-height: 160px; max-width: 160px; padding: 5px; border: 1px solid #E0E0E0; cursor: pointer; } 38 39 .img_container{ margin: 10px auto; border: 1px solid #E0E0E0; overflow: hidden; width: 300px; display: none; } 40 .img { float: left; position: relative;} 41 42 .tailor_border { width: 120px; height: 120px; position: absolute; background: black; filter:alpha(opacity=40); -moz-opacity:0.4; -khtml-opacity: 0.4; opacity: 0.4;} 43 44 .pre_container { position:absolute; top: 260px; right:270px; border: 1px solid #E0E0E0; width: 200px; height: 350px; text-align: center; display: none; } 45 .pre_container h3 { padding: 5px; border-bottom: 1px solid #E0E0E0;} 46 .pre_view { border: 1px solid #E0E0E0; width: 120px; height: 120px; margin: 10px auto; padding: 5px; overflow: hidden; position: relative; } 47 .save_view { margin: 10px auto; } 48 .save_view img{ border: 1px solid #E0E0E0; padding: 5px; } 49 .pre_view_img { position: absolute; } 50 51 </style> 52 </head> 53 <body> 54 <div class="box up_image"> 55 <h3 class="title"> 56 上传图片</h3> 57 <div class="main over_h"> 58 <div class="up_img" id="up_img" title="上传图片"> 59 <iframe id="if_upload" name="if_upload" style="display: none;" ></iframe> 60 <form id="uploadForm" target="if_upload" action="fileUpload.ashx?t=iframe" method="post" enctype="multipart/form-data"> 61 <a class="fl"><img src="images/upload.jpg" alt=""/><input id="files" type="file" size="4" name="file[]" multiple /></a> 62 63 </form> 64 </div> 65 <div class="pre_img" id="pre_img"> 66 </div> 67 </div> 68 </div> 69 <div class="box image_list"> 70 <h3 class="title"> 71 图片列表</h3> 72 <div class="main"> 73 <ul id="img_list" class="img_list"> 74 </ul> 75 </div> 76 </div> 77 <div class="box img_tailor"> 78 <h3 class="title"> 79 图片剪切</h3> 80 <div class="main"> 81 <div class="img_container" id="img_container"> 82 <div id="img" class="img"> 83 <div class="tailor_border" id="tailor_border"> 84 </div> 85 <img alt="" id="tailor_pic"> 86 </div> 87 </div> 88 <div class="pre_container" id="pre_container"> 89 <h3>预览</h3> 90 <div id="pre_view" class="pre_view"> 91 <div id="pre_view_img" class="pre_view_img"> 92 <img alt="" id="pre_pic"> 93 </div> 94 </div> 95 <button type="button" id="save"> 96 保存</button> 97 <div id="save_view" class="save_view"> 98 </div> 99 </div> 100 101 </div> 102 103 <script src="js/jquery-1.7.1.js" type="text/javascript"></script> 104 <script type="text/javascript"> 105 106 //处理低版本浏览器上传问题 107 function iframe_ipload(src) { 108 var j_img_list = $('#img_list'), 109 j_pre_img = $('#pre_img'); 110 111 var up = $('<div class="image_upload" ></div>'); 112 var img = $('<img src="' + src + '" alt="" >'); 113 var rate = $('<div class="rate">100%</div>'); 114 up.append(img); 115 up.append(rate); 116 j_pre_img.append(up); 117 118 var li = $('<li></li>'); 119 var _i = $('<img title="裁剪图片" src="' + src + '" alt="">'); 120 showImg(_i); 121 li.append(_i); 122 j_img_list.append(li); 123 124 // upload(files[k], k); 125 126 } 127 function showImg(el) { 128 var j_img_container = $('#img_container'), 129 j_pre_container = $('#pre_container'), 130 j_tailor_pic = $('#tailor_pic'), 131 j_img = $('#img'), 132 j_pre_pic = $('#pre_pic'); 133 134 el.click(function () { 135 j_pre_container.show(); 136 j_img_container.show(); 137 j_pre_pic.attr('src', el.attr('src')); 138 j_tailor_pic.attr('src', el.attr('src')); 139 initWidthByImg(j_img, j_img_container); 140 }); 141 } 142 //通用方法 143 function initWidthByImg(img, img_container) { 144 setTimeout(function () { 145 img_container.css('width', img.width()); 146 }, 50) 147 148 } 149 150 $(document).ready(function () { 151 var j_up_img = $('#up_img'), 152 j_pre_img = $('#pre_img'), 153 j_img_list = $('#img_list'), 154 j_tailor = $('#tailor_border'), 155 j_img_container = $('#img_container'), 156 j_img = $('#img'), 157 j_pre_view_img = $('#pre_view_img'), 158 j_save = $('#save'), 159 j_save_view = $('#save_view'), 160 j_pre_container = $('#pre_container'), 161 j_tailor_pic = $('#tailor_pic'), 162 j_pre_pic = $('#pre_pic'), 163 j_uploadForm = $('#uploadForm'); 164 165 j_file = $('#files'); 166 167 //需要上传的文件 168 var files = null; 169 170 //判断是否支持高级特性,经测试若是不支持filereader与file 171 var is_support = true; 172 if (typeof FileReader === 'undefined') is_support = false; 173 174 //当点击图片时,触发上传事件 175 j_file.change(function () { 176 initDom(); 177 if (is_support) { 178 var file = j_file.get(0); 179 if (!file.files[0]) is_support = false; 180 //支持高级功能的浏览器 181 files = file.files; 182 if (files) { 183 preView(files); 184 } 185 } else { 186 //不支持的话采用传统方式,渐进增强,支持IE7,8 187 j_uploadForm.submit(); 188 } 189 }); 190 191 if (is_support) { 192 //拖放上传图片 193 var dragArea = j_up_img.get(0); 194 /************拖放相关************/ 195 j_up_img.bind('dragover', function (e) { 196 $(this).addClass('dragAreaOver'); 197 e.stopPropagation(); 198 e.preventDefault(); 199 }); 200 j_up_img.bind('dragleave', function (e) { 201 202 $(this).removeClass('dragAreaOver'); 203 e.stopPropagation(); 204 e.preventDefault(); 205 }); 206 dragArea.addEventListener("drop", function (e) { 207 files = e.target.files || e.dataTransfer.files; 208 initDom(); 209 preView(files); 210 e.stopPropagation(); 211 e.preventDefault(); 212 213 }, false); 214 } 215 /************剪切相关************/ 216 //开始剪切时,初始化宽度 217 218 219 dragFunc(j_tailor, j_tailor, j_img_container, function (e) { 220 j_pre_view_img.css('left', '-' + j_tailor.css('left')); 221 j_pre_view_img.css('top', '-' + j_tailor.css('top')); 222 223 }); 224 225 j_save.click(function () { 226 var offset = j_tailor.offset(), 227 o = j_img.offset(); 228 var pic_src = j_pre_pic.attr('src'); 229 pic_src = 'temp' + pic_src.substr(pic_src.lastIndexOf('/')); 230 231 $.get('scissors.axd', { 232 action: 'GenerateBitmap', 233 src: pic_src, 234 zoom: 1, 235 x: (offset.left - o.left) * (-1), 236 y: (offset.top - o.top) * (-1), 237 // x: -50, 238 //y: -50, 239 width: j_tailor.width(), 240 height: j_tailor.height(), 241 t: Math.random() 242 }, function (data) { 243 if (data && typeof data == 'string') { 244 data = eval('(' + data + ')'); 245 } 246 var src = data.src; 247 j_save_view.html('<img src="' + src + '" alt="" />'); 248 }); 249 250 }); 251 252 253 254 function initDom() { 255 j_pre_img.html(''); 256 //j_img_list.html(''); 257 } 258 259 function preView(files) { 260 for (var k = 0, len = files.length; k < len; k++) { 261 var file = files[k]; 262 var reader = new FileReader(); 263 reader.readAsDataURL(file); 264 (function (k) { 265 reader.onloadend = function (e) { 266 if (reader.error) { 267 alert(reader.error); 268 } else { 269 var up = $('<div class="image_upload" id="up_' + k + '"></div>'); 270 var img = $('<img src="' + this.result + '" alt="" id="img_' + k + '">'); 271 var rate = $('<div class="rate" id="rate_' + k + '">0%</div>'); 272 up.append(img); 273 up.append(rate); 274 j_pre_img.append(up); 275 upload(files[k], k); 276 277 } 278 }; 279 })(k); 280 } //for 281 } 282 283 function upload(file, k) { 284 var up = $('#up_' + k); 285 var img = $('#img_' + k); 286 var rate = $('#rate_' + k); 287 var del = $('#del_' + k); 288 var fd = new FormData(); 289 fd.append('upload', file); 290 var xhr = new XMLHttpRequest(); 291 xhr.upload.addEventListener('progress', function (e) { 292 var percentComplete = Math.round((e.loaded) * 100 / e.total); 293 rate.html(percentComplete.toString() + '%'); 294 }, false); 295 // 文件上传成功或是失败 296 xhr.onreadystatechange = function (e) { 297 if (xhr.readyState == 4) { 298 if (xhr.status == 200) { 299 rate.html('100%'); 300 var url = xhr.responseText; 301 var li = $('<li></li>'); 302 var _i = $('<img title="裁剪图片" src="' + url + '" alt="">'); 303 showImg(_i); 304 li.append(_i); 305 j_img_list.append(li); 306 307 } 308 } 309 }; 310 xhr.open("POST", "fileUpload.ashx"); 311 //发送 312 xhr.send(fd); 313 } 314 315 function dragFunc(dragDiv, dragBody, parent, func_up) { 316 if (dragDiv[0] && dragBody[0]) { 317 var dragAble = false; 318 var x1 = 0; 319 var y1 = 0; 320 var l = 0; 321 var t = 0; 322 var p_t = 0; 323 var p_l = 0; 324 var init_position = ''; 325 326 var divOffset = dragBody.offset(); 327 dragDiv.mousedown(function (e) { 328 var ss = this; 329 // var rootId = 330 init_position = dragBody.css("position"); 331 dragBody.css("position", "absolute"); 332 dragDiv.css("cursor", "move"); 333 dragAble = true; 334 // 当前鼠标距离div边框的距离 335 // 当前鼠标坐标,减去div相对左边的像素 336 l = parseInt(dragBody.css("left")) ? parseInt(dragBody.css("left")) : 0; 337 t = parseInt(dragBody.css("top")) ? parseInt(dragBody.css("top")) : 0; 338 339 if (parent && parent[0]) { 340 p_l = parent.offset().left; 341 p_t = parent.offset().top; 342 } 343 344 x1 = e.clientX - l - p_l; 345 y1 = e.clientY - t - p_t; 346 x1 = x1 > 0 ? x1 : 0; 347 y1 = y1 > 0 ? y1 : 0; 348 this.setCapture && this.setCapture(); 349 }); 350 dragDiv.mousemove(function (e) { 351 if (!dragAble) 352 return; 353 // 当前div左边的坐标 354 // 当前鼠标坐标,减去鼠标拖动量 355 var x2 = 0; 356 var y2 = 0; 357 //需要考虑滚动条问题!!! 358 var top = $(document).scrollTop() ? $(document).scrollTop() - 40 : 0; 359 var left = $(document).scrollLeft() ? $(document).scrollLeft() - 40 : 0; 360 x2 = e.clientX - x1 + left - p_l; 361 y2 = e.clientY - y1 + top - p_t; 362 x2 = x2 > 0 ? x2 : 0; 363 y2 = y2 > 0 ? y2 : 0; 364 365 //当鼠标值较大时需要处理 366 if (e.clientX > 600) { 367 $('#pre_container').css('left', '10px'); 368 $('#pre_container').css('right', ''); 369 } else { 370 $('#pre_container').css('left', ''); 371 $('#pre_container').css('right', '270px'); 372 } 373 374 if (Math.abs(l - x2) > 10 || Math.abs(t - y2) > 10) { 375 dragBody.css("left", x2 + "px"); 376 dragBody.css("top", y2 + "px"); 377 } 378 if (func_up && typeof func_up == 'function') { 379 func_up(e); 380 } 381 }); 382 dragDiv.mouseup(function (event) { 383 if (!dragAble) 384 return; 385 dragAble = false; 386 dragBody.css("position", init_position); 387 if (dragBody.css("position") == 'fixed') { 388 var t = parseInt(dragBody.css('top')); 389 var st = $(document).scrollTop() ? $(document).scrollTop() : 0; 390 dragBody.css('top', (t - st) + 'px'); 391 } 392 // dragDiv.css("position", "relative"); 393 this.releaseCapture && this.releaseCapture(); 394 395 }); 396 } 397 } 398 }); 399 400 </script> 401 </body> 402 </html>
感悟
写之前,本来感觉好多话要说,但是最后发现自己就一个标题党。。。
感悟这个东西你说之前感觉很多很多,但真的要写的时候却发现什么也没有了。
由此我想到了另外一件事情,曾经很多很要好的兄弟,平时非常思念,但真的拿起电话、见面时反而没什么话可说。。。。
哎,其实我想说在这段时间的业余时间中,总在看书学习,却没有动力,没有效果,很搞笑的是这次面试题却带给了我不一样的感觉;
我真的就以此接触了一直想学习而没有学习的HTML5的东西,我突然可以两天晚上开开心心的编码,甚至晚上睡觉时候也会思考,
我仿佛回到了大学和同学一起做项目的时光,没有多余的想法,就是想学东西,就是想做好而已。。。。
就在这个过程中,我觉得我找到了我丢失已久的“安静”,因为我心不静已经很久了,为了工资为了提升,却忘了刚刚出校门所思所想了。。。
调用曾经高手们的一句话:
如果能够只为挥剑而挥剑,或许就能更接近我所追求的境界,但又谈何容易呢?