经过约两周的努力编写和调试,终于在昨天晚上完成了。因为做这个网站的缘故,再次新学习了大量东西,比如 jQuery,以及 Linux 下 Photoshop 的替代品 GIMP 等。同时也权当是一次练手,毕竟很久没写这种东西了。不过这次又一次与 IE 的 bug 及非标准化进行了顽强的斗争……
我要记录下在这个过程中遇到的种种问题和解决方法,以后再遇到就有地方查了~
客户端部分
很早就听说了 jQuery,上次看完 wp-codebox 的代码才顿觉 jQuery 的强大,因此这次选择了这个。经过短暂的学习就基本了解了,还是比较简单的。此外,jQuery 的插件库相当强大,里面找到了所有我需要的东西,包括上传文件的插件和播放器的插件等。
编写客户端代码最艰苦的部分就是配色和设计界面,以及在各个浏览器中调试。关于兼容性的问题放在后面说,前面先写点关于 JavaScript 代码的事。
第一个比较有趣的问题是关于浮点数保留精度的问题。虽然保留精度大是件好事,可是 JavaScript 没有如 C 中的 printf 那么方便的东西(不过网上似乎也有类似实现,不过 JavaScript 实现这个东西……还是算了吧……)。而一下把很长很长的浮点数显示在用户面前,也绝对不是件好事。经过搜寻,最后使用下面代码实现:
1 2 3 4 5 6 | Number.prototype.fix = function (num) { with (Math) return round(this.valueOf() * pow(10, num)) / pow(10, num); }; String.prototype.fix = function (num) { return parseFloat(this).fix(num); }; |
第二个问题就是关于 MP3 播放器背景的问题。我用的这个播放器插件极具可定制性,背景色和前景色都能定制,不过要求都要使用十六进制的形式传入。为了更好的适应主题颜色,我就使用 jQuery 的 .css 方法在脚本中现场获取当前在 CSS 中定义的前景色和背景色。结果发现,其在 Firefox 内返回的是类似 rgb(0, 0, 0) 这样的颜色表大形式。据说在 Firefox 中永远放回这种形式,而 IE 中则总是返回你实际设置时使用的格式。针对这个问题,我写了下面代码来解决(毋庸置疑,这又是抄的):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | var hex = function (n) { if (n == null) return '00'; n = parseInt(n); if (n == 0 || isNaN(n)) return '00'; n = Math.round(n); if (n < 0) n = 0; else if (n > 255) n = 255; return '0123456789abcdef'.charAt((n - n % 16) / 16) + '0123456789abcdef'.charAt(n % 16); }; var color2hex = function (color) { if (color.search(/rgb/i) > -1) { color = color.substring(4, color.length - 1).split(', '); return hex(color[0]) + hex(color[1]) + hex(color[2]); } else if (color.charAt(0) == '#') { color = color.substring(1); if (color.length == 3) { return color.charAt(0) + color.charAt(0) + color.charAt(1) + color.charAt(1) + color.charAt(2) + color.charAt(2); } else { return color; } } }; |
另外就是,为了防止大家大量重复提交同样音乐,这次加入了搜索功能,而且在提交一个音乐的时候就会自动进行搜索,并提示用户检查是否已有相同曲目被提交。至于搜索的实现,采用的是客户端搜索,算法上采用了非常著名而简单的 LCS (Longest common subsequence, 最长公共子序列) 这一 oier 的居家旅行杀人放火必备算法。事实证明,这一算法其实是很有效的~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function lcs(str1, str2) { if (! str1 || ! str2) return 0; var arr = []; var i, j; for (i = 0; i < str1.length; ++i) { arr[i] = []; for (j = 0; j < str2.length; ++j) { arr[i][j] = Math.max(i ? arr[i-1][j] : 0, j ? arr[i][j-1] : 0); if (str1.charAt(i) == str2.charAt(j)) arr[i][j] = Math.max(arr[i][j], i && j ? arr[i-1][j-1] + 1 : 1); } } return arr[str1.length-1][str2.length-1]; } |
搜索算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | function search(type, text, callback) { text = text.replace(/\s+/g, '').toLowerCase(); var threshold = text.length * 0.25; var result = []; getList(type, function (value) { if (! value || typeof value == 'number') { callback(value); return; } var itemtext, item, i; for (i = 0; i < value.length; ++i) { item = value[i]; itemtext = (item.source + item.title).replace(/\s+/g, '').toLowerCase(); item.len = itemtext.length; item.lcs = lcs(text, itemtext); if (item.lcs > threshold) result.push(item); } result.sort(function (item1, item2) { if (item1.lcs > item2.lcs) return -1; if (item1.lcs < item2.lcs) return 1; if (item1.len < item2.len) return -1; if (item1.len > item2.len) return 1; return 0; }); callback(result); }); } |
还有一个是关于换肤的。上一次有一篇文章测试过了基于更换 link 标签 href 属性换肤的可行性分析,这次就应用于了这个平台上。但在测试中发现 IE 并不像想像的那么完美。事实上,IE 在这个的测试过程中是非常废品的,几乎相当于不能换。经过多次实验,发现原因出在——IE6 在页面加载完毕后永远不会显示其还没有下载的样式信息。也就是说,更改 href 后,虽然 IE6 将原来的样式表无效化了,但此时发现新的样式表不在其缓存中,便拒绝启用新的样式表。但奇怪的是,IE6 这个时候事实上会连接服务器下载新的样式,因此在下一次访问的时候上次点过的皮肤就可以用了。这说明,我们只要要求 IE 预装载以后可能用到的东西就可以了。因此我就在页面底部加入了一个隐藏的 iframe 用于下载样式表和需要的图片。
除此之外,就是一些关于样式的新发现。我第一次知道当一个元素的 position 属性设置为 relative 的时候,对这个对象本身没有影响,但却使得其使用 position 属性的子元素的位移变由相对页面的位移变为相对该元素的位移。这的上传进度条的实现方法便是应用这一机制。
说到上传进度条,不得不说 Uploadify 这一插件真的很强大……我将其默认的上传进度和管理通过对各个必要函数绑定返回 false 来屏蔽掉了。
最后是关于 jQuery 优化的问题。虽然 jQuery 的官方测试表明,jQuery 的效率非常惊人,但优化下总归是有好处的。参考的资料见下面了,说说我大体做了哪些优化吧。一是缓存 jQuery 对象,防止重复调用选择器带来的性能损失。第二个是为选择器加上上下文限制,第三个是将部分效果移至 $(window).load 里。
在客户端的脚本部分的最最后,小小的埋怨一下 JavaScript 这个语言……我觉得实在是没有 Python 优美啊!什么时候 Python 能成为通用的客户端脚本啊,那个时候用 Python 就可以通吃服务器端和客户端了……
说完了脚本,来说说这次的界面。这次界面个人还是很满意的。在界面设计中,我自认为值得一提的是那个圆角,为什么呢?因为我以前一直以为 GIMP 不能画圆角。这次去网上找了才知道,GIMP 远比我想象的强大的多!猜猜圆角是怎么画出来的?是通过高斯模糊+调整色阶。具体的实现方法放在下面参考资料里面了,这里就不详述了。但我真的觉得很强大,虽然 GIMP 和 Photoshop 等商业软件还有差距,不过对于我来说,看来足够了。
最后再提下这次发现的不同浏览器的兼容性问题:
- 对于不显示的 Flash,IE 无法与其交互
- 对于曾经被隐藏但再次出现的 Flash,IE6 无法与其交互
- 解决方案:完全销毁原有 Flash 对象并重建
- IE 中隐藏的 Flash MP3 播放器可以发出声音,但 Firefox 不行
- 解决方案:统一的办法就是直接销毁播放器,而非单单让其隐藏
- IE 的 JavaScript 解析器不支持用 [index] 的方式索引字符
- 解决方案:使用原有标准的 .charAt(index) 方式索引
- 在 IE6 中,显示时尚未下载完成的 CSS 元素永远不会显示(如背景图片)
- 解决方案:在页面中加入一个隐藏的 iframe 用于预加载
- IE6 中的双倍外边距 bug
- 解决方案:给相应对象加上 display:inline; 属性,或通过 hack 专门调低在 IE6 下的外边距
- IE6 对于 display 的 inline-block 属性支持不完善
- 解决方案:给相应对象加上 zoom:1; 属性
- IE6 不支持半透明的 png 图片
- 解决方案:采用 IE 专有的过滤器 filter:progid:DXImageTransform.Microsoft.AlphaImageLoader 可以完美解决
IE 的兼容性烦死人啊……看看我的 ie6-fix.css 和 ie7-fix.css 就知道了……
使用部件
- jQuery: The Write Less, Do More, JavaScript Library
- Uploadify – jQuery File Upload Plugin Script
- SWFObject
- jMP3: Sean O’s JavaScript MP3 Player / jQuery plugin
- JSON plugin for jQuery
参考资料
- jQuery中文入门教程
- 如何格式化浮点数计算结果 JavaScript – CSDN社区
- jQuery.sifrSettings
- jQuery性能优化指南 (全部) – 烟雨博客
- 1.3 圆整圆角 – The Gimp – 思魂轩
- Uploadify • View topic – Uploadify doesnt fire uploadifyUpload/uploadifyClearQueue
- IE6下margin双倍问题 – 绯雨的天空
- Making Internet Explorer use PNG Alpha transparency
Pages: 1 2
看的头晕了…
已经在帖吧里置顶了……
看起来反响还是不错的,对平台,以及对活动……
不过,我一直担心这个上传功能……要是有人吃饱撑着传N个20M的MP3上去,把服务器硬盘撑爆,或者把数据库拖跨……
虽然单机很难做到,但是多台机子用脚本同时上传的话……这莫非就是DDOS了……
那个…那个…你的主页在opera mini上的显示很有问题……