Tag Archives: JavaScript

Javascript Array sort 在不同浏览器中的不同表现

昨晚发现了一个让我无法理解事情, 看下面的代码:

var x = [{id:1, val:1}, {id:1, val:32}, {id:1, val:42}];
x.sort(function(a, b){
  console.log(a.val, b.val, a.id <= b.id)
  if (a.id <= b.id){
    return 1;
  }else if (a.id > b.id){
    return -1;
  }
});
console.log(x.map(function(obj){return obj.val;}).join(','));

在IE已经Edge, 1.9.8版本的phantomjs里给出来的结果是: 1,32,42
而在Firefox, Chrome, Nodejs 下给出的是: 42,32,1
在比较函数里插入了一行代码发现了问题所在:

var x = [{id:1, val:1}, {id:1, val:32}, {id:1, val:42}];
x.sort(function(a, b){
  console.log(a.val, b.val, a.id <= b.id)
  if (a.id <= b.id){
    return 1;
  }else if (a.id > b.id){
    return -1;
  }
});
console.log(x.map(function(obj){return obj.val;}).join(','));

c

明显看出IE里a跟b的顺序与其他浏览器里不一样, IE里面是反的, 导致在这种特殊情况下结果的不一致, 看一下msdn与mdn上对于这个的不同描述:
mdn
m

感觉还是mdn上的更好理解, 而且Chrome跟Firefox参数的传入顺序似乎也更符合我们的心理预期.
如果排序过程中打印数值长度, 微软系列的竟然是0. 这也很特别.

关于Photoshop中图层的批量导出

最近又遇上了一个项目,需要把Photoshop中的各层全部导成相应的图片,并且要获取相应的图片在Photoshop中的实际位置的信息,用于在网页中重新生成与Photoshop中一样的整图的效果,于是整了一个JSX的脚本,似乎还挺有用处的,可以将photoshop中相应层中的图片先裁切掉多余的空白,之后将它们保存,并且最终生成一个xml文档或者是json的文档将相应的图像位置信息保存在其中。

不过还有几点问题:

1. PSD中不能有重名的层,重名的层中的图片会被相互覆盖。

2. PSD中不要有空层,有可能会引起错误。

时间紧,也没时间去完善,只能将就一下了。

另外直接用这个在图片出现重叠时会比较麻烦,好在有另一个强大的软件:TexturePacker(http://www.texturepacker.com),这个软件可以在Mac,Windows,Ubuntu等多个主流操作系统上运行, 可以从SWF或者直接将多张图合并成一张纹理图,同时可以生成相应格式的数据,包括JSON格式的,并且这个软件对于有技术类博客的网友,可以免费提供注册证书,无需花银子了,我的就是用的免费的,软件作者还很友好的,配合这个工具,再多的图也可以轻松排了。

使用DeepLink的网站添加Facebook Like Button

这年头使用DeepLink的网站越来越多了,像Flash整的网站,本身在一个页面里,DeepLink是必须的,国外的Flash基本都有这个功能,不过。。。国内这样的网站就差多了,基本不加,无法根据URL导航到特定的内容页,相当得不好用呢。

而现在Ajax之后,Html5也进入实际的使用了,这样的网站很多也不再没事就刷新页面,白一下屏,多不爽,也都是使用DeepLink了。但是这样的网站想使用Facebook Like Button这样的按钮时,有些个麻烦了。

Facebook Like Button 的代码是这样子的:

<div id="fb-root"></div>
<script>(function(d){
  var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
  js = d.createElement('script'); js.id = id; js.async = true;
  js.src = "//connect.facebook.net/en_US/all.js#appId=272021599483200&xfbml=1";
  d.getElementsByTagName('head')[0].appendChild(js);
}(document));</script>
<div class="fb-like" data-href="http://www.chrislearn.im" data-send="true" data-width="450" data-show-faces="true"></div>

这里的data-href就是Like的网站地址,Facebook会到这个页面去查找相应的og:title, og:description等等的值,然后将这个显示出来。但是,用DeepLink的网站因为页面没有刷新,因此,og:title这样的值是不会改变的,即使是用js改变它,也是没用的,Facebook不认识js.
我想到的一个解决办法是:
1. 修改这个script代码,原因是我想用js修改data-href的值。如果不改这个js,似乎这个js代码不会重复执行,即使改了data-href的值也不会有什么变化。大致上是移除这里的 script代码,用类似下面的代码代替, 并且在修改完data-href值后执行这个函数。

function createFacebookSdk() {
    var js, id = 'facebook-jssdk'; $('#'+id).remove();
    js = document.createElement('script'); js.id = id; js.async = true;
    js.src = "//connect.facebook.net/en_US/all.js#appId=219934971396743&xfbml=1";
    $('head')[0].appendChild(js);
}

2. 在每次地址的锚点部分改变后,改变data-href的值。比如http://www.chrislearn.im/#/level0/这个地址时,把data-href的值改成:http://www.chrislearn.im/?path=level0&title=demo&description=des.并且重新调用createFacebookSdk方法,重新生成like button按钮。
3. 下面就是服务器端了,服务器端页面可以根据查询字符串来修改og:title这样的值。因为服务器端修改的,因此Facebook可以取到这些个值。但是我们的网页其实是根据#/level0/部分来显示内容的,我并不想再整一个解析查询字符串的js函数,所以,可以在服务器端可以向页面写入一个location=”http://www.chrislearn.im/#/level0/“的javascript的脚本块,让页面转向。下面是我一个项目里的一小段服务器端代码:

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            string year = Request.QueryString["year"];
            string index = Request.QueryString["index"];
            if (!String.IsNullOrEmpty(year) && !String.IsNullOrEmpty(index))
            {
                string redirect = String.Format("window.location=\"Default.aspx#/{0}/{1}/\";", year, index);
                Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "RedirectByQueryString", redirect, true);

                OGTitle.Attributes["content"] = Request.QueryString["title"];
                OGDescription.Attributes["content"] = Request.QueryString["description"];
            }
        }
    }
}

OK了,大功告成。还有一点,Facebook的like button最后是以iframe来呈现,这样一个额外的好处是,容易浮到flash,silverlight上面。

Jquery UI Dialog 无法提交服务器解决方法

Jquery UI 库中的 Dialog 控件里如果存在表单,是无法直接提交到服务器的,因为在jquery.ui.dialog.js文件中(1.8.2版本中大概是在59行的位置)有这样的代码:
[javascript]
uiDialog = (self.uiDialog = $(”))
.appendTo(document.body)
.hide()
.addClass(uiDialogClasses + options.dialogClass)
.css({
zIndex: options.zIndex
})
// setting tabIndex makes the div focusable
// setting outline to 0 prevents a border on focus in Mozilla
.attr(‘tabIndex’, -1).css(‘outline’, 0).keydown(function(event) {
if (options.closeOnEscape && event.keyCode &&
event.keyCode === $.ui.keyCode.ESCAPE) {

self.close(event);
event.preventDefault();
}
})
[/javascript]
也就是说被创建的dialog元素是被添加到body元素中了,你想dialog的内容被作为子元素添加在了它所创建的这个dialog元素里,自然也会被从原始的form元素中拿出来了,这样它里面的表单元素也就无法知道自己提交到哪去了。

解决方法:
有人可能想直接修改上面这段代码,把.appendTo(document.body)改为类似.appendTo(document.forms[0])这样的代码。不过不管怎么说修改jquery这么成熟的库总不是明智的作法。我个人是在调用了dialog()方法后再将生成的元素放入到form中。
例如:
[javascript]
$(‘#control_panel_dialog’).dialog();
$(“body>div[role=dialog]”).appendTo(‘form:first’);
[/javascript]
或者:
[javascript]
$(‘#control_panel_dialog’).dialog().parent().appendTo(‘form:first’);
[/javascript]
或者:
[javascript]
$(‘#control_panel_dialog’).dialog();
$(‘.ui-dialog’).appendTo(‘form:first’);
[/javascript]
由于我正常是使用asp.net,正常只有一个 form 元素,这样的话直接加入到 ‘form:first’ 就好了。

Javascript 获取窗口宽度和高度值

获取页面高度,窗口高度,滚动条高度等参数值:

  1. function getPageScroll(){
  2. var yScroll;
  3. if (self.pageYOffset) {
  4. yScroll = self.pageYOffset;
  5. } else if (document.documentElement && document.documentElement.scrollTop){   // Explorer 6 Strict
  6. yScroll = document.documentElement.scrollTop;
  7. } else if (document.body) {// all other Explorers
  8. yScroll = document.body.scrollTop;
  9. }
  10. arrayPageScroll = new Array(”,yScroll)
  11. return arrayPageScroll;
  12. }
  13. function getPageSize(){
  14. var xScroll, yScroll;
  15. if (window.innerHeight && window.scrollMaxY) {
  16. xScroll = document.body.scrollWidth;
  17. yScroll = window.innerHeight + window.scrollMaxY;
  18. } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
  19. xScroll = document.body.scrollWidth;
  20. yScroll = document.body.scrollHeight;
  21. } else { // Explorer Mac…would also work in Explorer 6 Strict, Mozilla and Safari
  22. xScroll = document.body.offsetWidth;
  23. yScroll = document.body.offsetHeight;
  24. }
  25. var windowWidth, windowHeight;
  26. if (self.innerHeight) {  // all except Explorer
  27. windowWidth = self.innerWidth;
  28. windowHeight = self.innerHeight;
  29. } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
  30. windowWidth = document.documentElement.clientWidth;
  31. windowHeight = document.documentElement.clientHeight;
  32. } else if (document.body) { // other Explorers
  33. windowWidth = document.body.clientWidth;
  34. windowHeight = document.body.clientHeight;
  35. }
  36. // for small pages with total height less then height of the viewport
  37. if(yScroll < windowHeight){
  38. pageHeight = windowHeight;
  39. } else {
  40. pageHeight = yScroll;
  41. }
  42. if(xScroll < windowWidth){
  43. pageWidth = windowWidth;
  44. } else {
  45. pageWidth = xScroll;
  46. }
  47. arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight)
  48. return arrayPageSize;
  49. }

jsfl SyntaxError:unterminated string literal

前一阵子写了个Flash网站的框架,类似GaiaFramework,我也想做一个给它有点类似的Flash扩展,让Flash的操作跟简单,省去重复劳动,所以这两天试着写了一下jsfl,一不小心就遇到了一个“SyntaxError:unterminated string literal”的错误。

网上找了一下,也没找到好的解答。后来看了一下代码,终于明白这个错误是如何出现的了。事实上我是在Flash里调用jsfl读取了一个外部的XML文件,然后,试图在扩展面板运行时打印这段XML的内容时出现了这个错误的。

public static function out(m:String)
{
MMExecute(“fl.trace(\”” + m + “\”);”);
}

上面这个就是用来调用jsfl在面板运行时打印读取到了XML内容的ActionScript的代码了,跟GaiaFramework里的是一个样的(算我抄袭他的吧,呵呵!)。也就是调用了fl.trace这个方法打印一个字符串。看上去没什么问题,但是在我把XML作为内容给它时,却出错了,开始还以为是jsfl读取文件时有问题,后来试了一下,把XML中的换行去掉就可以打印。于是,觉得问题还在这个方法了。

再细看这个方法,其实是有问题的,这个跟在jsfl里直接调用fl.trace(m);是不一样的。如果在jsfl中直接调用,那m对于fl.trace这个方法来说就是个字符串变量,fl.trace就是在打印字符串变量了,对于字符串里是不是有换行对这个方法没有影响。

但是上面是在ActionScript中调用fl.trace方法,是没有办法把m这个变量传给fl.trace这个方法的,只能将m变量的值传给fl.trace方法了。”fl.trace(\”” + m + “\”);”这个是一个字符串,而在把它当作jsfl代码执行前,m的值以经是被替换成具体的m变量的值。相当于在执行”fl.trace(\”” + “XXXX”+ “\”);”。而这个时候,如果m的值里面有换行或者”,‘号时,就会导致上面的这段代码不合js语法。最终导致上面的错误。

如果要解决错误,就的让上面的代码符合语法规范,将换行和“,’等符号替换成相应的转意字符。

public static function out(m:String)
{
m = m.replace(/\”/g, “\\\””);
m = m.replace(/\’/g, “\\\'”);
m = m.replace(/[\r\n]+/g, “\\r”);
MMExecute(“fl.trace(\”” + m + “\”);”);
}

上面就是改后的代码,试了一下,错误没有再报,内容也打印出来了。问题解决。其实在其他的javascript中也可能会遇到类似的错误的。