分类目录归档:web

从一行代码里面学点JavaScript

现如今,JavaScript无处不在,因此关于JavaScript的新知识也是层出不穷。JavaScript的特点在于,要学习它的语法入门简简单,但是要精通使用它的方式却是一件不容易的事。

来看看下面的这段代码,它来自于谷歌“名猿”Addy Osmani在几天前贴出的一段代码,它的作用是用来调试你的CSS层。全部代码只有三行,但是你绝对可以把它放在一行里面完成:

[].forEach.call($$(“*”),function(a){

a.style.outline=”1px solid #”+(~~(Math.random()*(1<<24))).toString(16)

})

现在,在你的Chrome浏览器的控制台中输入这段代码,你会发现不同HTML层都被使用不同的颜色添加了一个高亮的边框。是不是非常酷?但是,简单来说,这段代码只是首先获取了所有的页面元素,然后使用一个不同的颜色为它们添加了一个1ps的边框。想法很简单,但是真要实现起来却不是那么容易的一件事。在下面的内容中,我们将一起一步一步学习如何理解上面的这段代码。

选择页面中所有的元素

我们需要做的第一件事情是获取页面中所有的元素,在上面的代码中,Addy使用了一个Chrome浏览器中特有的函数$$。你可以在你的Chrome浏览器控制台中输入$$(‘a’),然后你就能得到一个当前页面中所有锚元素的列表。

$$函数是许多现代浏览器命令行API中的一个部分,它等价于document.querySelectorAll,你可以将一个CSS选择器作为这个函数的参数,然后你就能够获得当前页面中所有匹配这个CSS选择器的元素列表。如果你在浏览器控制台以外的地方,你可以使用document.querySelectorAll(‘*’)来代替$$(‘*’)。更多关于$$函数的详细内容可以查看Chrome开发者工具的文档。

当然,除了使用$$函数之外,我们还有一种更简单的方法,document.all,虽然这并不是一种很规范的使用方法,但是它几乎在每一个浏览器中都能运行成功。

迭代所有的元素

经过第一步,我们已经获得了页面内所有的元素,现在我们想做的事情是遍历每一个元素,然后为它们添加一个彩色边边框。但是上面的代码究竟是怎么一回事呢?

[].forEach.call( $$(‘*’), function( element ) { /* 在这里修改颜色 */ });

首先,我们通过选择器获得的列表是一个NodeLists对象,它和JavaScript中的数组有点像,你可以使用方括号来获取其中的节点,你也可以检查它其中包含多少个元素,但是它并没有实现数组包含的所有方法,因此我们并不能使用$$(‘*’).forEach()来进行迭代。在JavaScript中,有好几个类似于数组但是并不是数组的对象,除了前面的NodeLists,还有函数的参数集合arguments,在这里我们可以使用call或apply函数将函数的方法运用到这些对象上。例如下面的例子:

function say(name) {

console.log( this + ‘ ‘ + name );

}

say.call( ‘hola’, ‘Mike’ ); // 打印 ‘hola Mike’

// 你也可以将这种方法有用在arguments对象上 function example( arg1, arg2, arg3 ) { return Array.prototype.slice.call(arguments, 1); // Returns [arg2, arg3] }

在Addy的代码中,使用了[].forEach.call而不是Array.prototype.forEach.call,二者等价,但是前者可以节省几个字节。

为元素添加颜色

为了让元素都有一个漂亮的边框,我们在上面的代码中使用了CSS属性outline。outline属性位于CSS盒模型之外,因此它并不影响元素的属性或者元素在布局中的位置,这对于我们来说非常有用。这个属性和修改border属性非常类似,因此下面的代码应该不会很难理解:

a.style.outline=”1px solid #” + color

真正有趣的地方在于定义颜色部分:

~~(Math.random()*(1<<24))).toString(16)

天呐,上面的代码是什么意思?在JavaScript中,比特操作符并不是经常被使用,因此这里可能会让很多程序员感到很疑惑。

我们想达到的目的是活的一个十六进制格式的颜色例如白色对应的是FFFFFF,蓝色对应的是0000FF,或者随便一个颜色37f9ac。虽然我们人类喜欢十进制,但是我们的代码常常会需要十六进制的东西。

我们首先要学会如何使用toString函数将一个十进制的数组转换为一个十六进制整数。这个函数可以接受一个参数,如果参数缺省,默认为十进制,但是你完全可以使用别的数组:

(30).toString(); // “30”

(30).toString(10); // “30”

(30).toString(16); // “1e” 十六进制

(30).toString(2); // “11110” 二进制

(30).toString(36); // “u” 36是允许的最大参数值

除此之外,你可以使用parseInt函数将十六进制数字转换为十进制。

parseInt(“30”); // “30”

parseInt(“30”, 10); // “30”

parseInt(“1e”, 16); // “30”

parseInt(“11110”, 2); // “30”

parseInt(“u”, 36); // “30”

因此,我们现在只需要一个位于0和ffffff之间的十六进制数,由于:

parseInt(“ffffff”, 16) == 16777215

而这里的16777215实际上是2^24-1。

如果你对二进制数学熟悉的话,你可能会知道1<<24 == 16777216。

再进一步,你每在1后面添加一个0,你就相当于多做了一次2的乘方:

1 // 1 == 2^0

100 // 4 == 2^2

10000 // 16 == 2^4

1000000000000000000000000 // 16777216 == 2^24

因此,在这里我们可以知道Math.random()*(1<<24)表示一个位于0和16777216之间的数。

但是这里并没有结束,因为Math.random返回的是一个浮点数,但是我们只想要整数部分。我们的代码中使用波浪号操作符来完成这件事。波浪操作符在JavaScript中被用来对一个变量进行取反。

但是我们在这里并不关心取反,我们指向获取整数部分。因此我们还可以知道两次取反可以去掉一个浮点数的小数部分,因此~~的作用相当于parseInt:

var a = 12.34, // ~~a = 12

b = -1231.8754, // ~~b = -1231

c = 3213.000001 // ~~c = 3213

;

~~a == parseInt(a, 10); // true

~~b == parseInt(b, 10); // true

~~c == parseInt(c, 10); // true

当然,我们还有一种更加简洁的方法,使用OR操作符:

~~a == 0|a == parseInt(a, 10)

~~b == 0|b == parseInt(b, 10)

~~c == 0|c == parseInt(c, 10)

最终,我们获得了一个位于0和16777216之间的随机整数,也就是我们想要的随机颜色。此时我们只需要使用toString(16)将它转化为十六进制数即可。

总结

现在,你已经完全理解了前面的这一行代码中的各个部分。作为一个程序员,我们应该在完成工作之后多问自己几遍为什么,还有没有更好更简洁的方法。当然,最应该做的事情当然是多阅读程序代码,也许你就能从某一行代码中学到很多新东西。

关于JavaScript中的复制

在做项目时有一个需求,是需要复制内容到剪切板,因为有众多浏览器,所以要兼容性很重要

1、最简单的copy,只能在IE下使用

使用clipboardData方法

2、跨浏览器的,但是Firefox无法复制

   

   

   

测试后,Firefox访问失败

3、万能的flash

不要重复造轮子了,有一个使用广泛的类库ZeroClipboard

Zero Clipboard 的实现原理

Zero Clipboard 利用 Flash 进行复制,之前有 Clipboard Copy 解决方案,其利用的是一个隐藏的 Flash。但最新的 Flash Player 10 只允许在 Flash 上进行操作才能启动剪贴板。所以 Zero Clipboard 对此进行了改进,用了一个透明的 Flash ,让其漂浮在按钮之上,这样其实点击的不是按钮而是 Flash ,也就可以使用 Flash 的复制功能了。

  • 创建一个透明的flash
  • 将这个flash浮在按钮上层
  • 确定要复制的文本是什么
  • 监听这个透明flash的鼠标点击事件
  • 该flash被点击之后,完成剪切板处理

对于这几件事,ZeroClipboard分别提供了不同的api,来完成整个需求

如何使用 Zero Clipboard

完整代码直接下载即可

git clone https://github.com/chenpingzhao/easycopy.git

关于ZeroClipboard.js

var ZeroClipboard = {

    version: “1.0.7”,

    clients: {},

    moviePath: “zeroclipboard.swf”,

    nextId: 1,

    $: function(A) {

        if (typeof(A) == “string”) {

            A = document.getElementById(A)

        }

        if (!A.addClass) {

            A.hide = function() {

                this.style.display = “none”

            };

            A.show = function() {

                this.style.display = “”

            };

            A.addClass = function(B) {

                this.removeClass(B);

                this.className += ” ” + B

            };

            A.removeClass = function(D) {

                var E = this.className.split(/\s+/);

                var B = -1;

                for (var C = 0; C < E.length; C++) {

                    if (E[C] == D) {

                        B = C;

                        C = E.length

                    }

                }

                if (B > -1) {

                    E.splice(B, 1);

                    this.className = E.join(” “)

                }

                return this

            };

            A.hasClass = function(B) {

                return !!this.className.match(new RegExp(“\\s*” + B + “\\s*”))

            }

        }

        return A

    },

    setMoviePath: function(A) {

        this.moviePath = A

    },

    dispatch: function(D, B, C) {

        var A = this.clients[D];

        if (A) {

            A.receiveEvent(B, C)

        }

    },

    register: function(B, A) {

        this.clients[B] = A

    },

    getDOMObjectPosition: function(C, A) {

        var B = {

            left: 0,

            top: 0,

            width: C.width ? C.width : C.offsetWidth,

            height: C.height ? C.height : C.offsetHeight

        };

        while (C && (C != A)) {

            B.left += C.offsetLeft;

            B.top += C.offsetTop;

            C = C.offsetParent

        }

        return B

    },

    Client: function(A) {

        this.handlers = {};

        this.id = ZeroClipboard.nextId++;

        this.movieId = “ZeroClipboardMovie_” + this.id;

        ZeroClipboard.register(this.id, this);

        if (A) {

            this.glue(A)

        }

    }

};

ZeroClipboard.Client.prototype = {

    id: 0,

    ready: false,

    movie: null,

    clipText: “”,

    handCursorEnabled: true,

    cssEffects: true,

    handlers: null,

    //我们可以通过下面这个api,将flash和按钮重叠,且浮在按钮之上

    glue: function(D, B, E) {

        this.domElement = ZeroClipboard.$(D);

        var F = 99;

        if (this.domElement.style.zIndex) {

            F = parseInt(this.domElement.style.zIndex, 10) + 1

        }

        if (typeof(B) == “string”) {

            B = ZeroClipboard.$(B)

        } else {

            if (typeof(B) == “undefined”) {

                B = document.getElementsByTagName(“body”)[0]

            }

        }

        var C = ZeroClipboard.getDOMObjectPosition(this.domElement, B);

        this.div = document.createElement(“div”);

        var A = this.div.style;

        A.position = “absolute”;

        A.left = “” + C.left + “px”;

        A.top = “” + C.top + “px”;

        A.width = “” + C.width + “px”;

        A.height = “” + C.height + “px”;

        A.zIndex = F;

        if (typeof(E) == “object”) {

            for (addedStyle in E) {

                A[addedStyle] = E[addedStyle]

            }

        }

        B.appendChild(this.div);

        this.div.innerHTML = this.getHTML(C.width, C.height)

    },

 

    /*IE 的 Flash JavaScript 通信接口上有一个 bug 。

    你必须插入一个 object 标签到一个已存在的 DOM 元素中。并且在写入 innerHTML 之前请确保该元素已经 appendChild 方法插入到 DOM 中*/

    getHTML: function(D, A) {

        var C = “”;

        var B = “id=” + this.id + “&width=” + D + “&height=” + A;

        if (navigator.userAgent.match(/MSIE/)) {

            var E = location.href.match(/^https/i) ? “https://” : “http://”;

            C += ‘

        } else {

            C += ‘

        }

        return C

    },

    hide: function() {

        if (this.div) {

            this.div.style.left = “-2000px”

        }

    },

    show: function() {

        this.reposition()

    },

    destroy: function() {

        if (this.domElement && this.div) {

            this.hide();

            this.div.innerHTML = “”;

            var A = document.getElementsByTagName(“body”)[0];

            try {

                A.removeChild(this.div)

            } catch (B) {}

            this.domElement = null;

            this.div = null

        }

    },

    /* 因为按钮上漂浮有一个 Flash 按钮,所以当页面大小发生变化时,Flash 按钮可能会错位,就点不着了

    Zero Clipboard 提供了一个 reposition() 方法,可以重新计算 Flash 按钮的位置。我们可以将它绑定到 resize 事件上

    bind(window, “resize”, function(){ clip.reposition(); });

   

    function bind(obj, type, fn) {

        if (obj.attachEvent) {

            obj[‘e’ + type + fn] = fn;

            obj[type + fn] = function() {

                obj[‘e’ + type + fn](window.event);

            }

            obj.attachEvent(‘on’ + type, obj[type + fn]);

        } else

            obj.addEventListener(type, fn, false);

    }*/

 

    reposition: function(C) {

        if (C) {

            this.domElement = ZeroClipboard.$(C);

            if (!this.domElement) {

                this.hide()

            }

        }

        if (this.domElement && this.div) {

            var B = ZeroClipboard.getDOMObjectPosition(this.domElement);

            var A = this.div.style;

            A.left = “” + B.left + “px”;

            A.top = “” + B.top + “px”

        }

    },

    setText: function(A) {

        this.clipText = A;

        if (this.ready) {

            this.movie.setText(A)

        }

    },

    addEventListener: function(A, B) {

        A = A.toString().toLowerCase().replace(/^on/, “”);

        if (!this.handlers[A]) {

            this.handlers[A] = []

        }

        this.handlers[A].push(B)

    },

    setHandCursor: function(A) {

        this.handCursorEnabled = A;

        if (this.ready) {

            this.movie.setHandCursor(A)

        }

    },

 

    /*鼠标移到按钮上或点击时,由于有 Flash 按钮的遮挡,所以像 css “:hover”, “:active” 等伪类可能会失效。

    setCSSEffects() 方法就是解决这个问题。首先我们需要将伪类改成类

    copy – botton: hover {

        border – color: #FF6633;

    }

    可以改成下面的 “:hover” 改成 “.hover”

   

    copy – botton.hover {

        border – color: #FF6633;

    }

    我们可以调用 clip.setCSSEffects( true ); 这样 Zero Clipboard 会自动为我们处理:将类 .hover 当成伪类 :hover*/

 

    setCSSEffects: function(A) {

        this.cssEffects = !! A

    },

    /*Zero Clipboard 提供了一些事件,你可以自定义函数处理这些事件。

    Zero Clipboard 事件处理函数为 addEventListener(); 例如当 Flash 完全载入后会触发一个事件 “load”

 

    clip.addEventListener( “load”, function(client) {

        alert(“Flash 加载完毕!”);

    });*/

 

    receiveEvent: function(D, E) {

        D = D.toString().toLowerCase().replace(/^on/, “”);

        switch (D) {

            case “load”:

                this.movie = document.getElementById(this.movieId);

                if (!this.movie) {

                    var C = this;

                    setTimeout(function() {

                        C.receiveEvent(“load”, null)

                    }, 1);

                    return

                }

                if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {

                    var C = this;

                    setTimeout(function() {

                        C.receiveEvent(“load”, null)

                    }, 100);

                    this.ready = true;

                    return

                }

                this.ready = true;

                this.movie.setText(this.clipText);

                this.movie.setHandCursor(this.handCursorEnabled);

                break;

            case “mouseover”:

                if (this.domElement && this.cssEffects) {

                    this.domElement.addClass(“hover”);

                    if (this.recoverActive) {

                        this.domElement.addClass(“active”)

                    }

                }

                break;

            case “mouseout”:

                if (this.domElement && this.cssEffects) {

                    this.recoverActive = false;

                    if (this.domElement.hasClass(“active”)) {

                        this.domElement.removeClass(“active”);

                        this.recoverActive = true

                    }

                    this.domElement.removeClass(“hover”)

                }

                break;

            case “mousedown”:

                if (this.domElement && this.cssEffects) {

                    this.domElement.addClass(“active”)

                }

                break;

            case “mouseup”:

                if (this.domElement && this.cssEffects) {

                    this.domElement.removeClass(“active”);

                    this.recoverActive = false

                }

                break

        }

        if (this.handlers[D]) {

            for (var B = 0, A = this.handlers[D].length; B < A; B++) {

                var F = this.handlers[D][B];

                if (typeof(F) == “function”) {

                    F(this, E)

                } else {

                    if ((typeof(F) == “object”) && (F.length == 2)) {

                        F[0][F[1]](this, E)

                    } else {

                        if (typeof(F) == “string”) {

                            window[F](this, E)

                        }

                    }

                }

            }

        }

    }

};

【转】AJAX 请求区分 $_SERVER['HTTP_X_REQUESTED_WITH'] 小解

关于这个内容,很多人都有所了解.但从我搜索的内容来看,他们只是略微看一下,根本不知道里面到底是什么情况.

受到很多模版代码的影响,大家都以为php有这样一个自定义变量:$_SERVER[‘HTTP_X_REQUESTED_WITH’].  其实根本不是那么回事.
$_SERVER是一个包含诸如头信息(header),路径(path)和脚本位置(script locations)的数组.这是PHP手册的原话.

有一些头信息是系统本身就存在的,且不能更改,比如说HOST,USER_AGENT等等,注意我们常用到的是$_SERVER[‘HTTP_HOST’],$_SERVER[‘HTTP_USER_AGENT’],这里面都有HTTP前缀,实现上在header信息里面是没有HTTP前缀的,信息名称只是HOST之类的,$_SERVER自动的为他们加上HTTP前缀,1是为了防止与本身的其它信息相冲突,2是为了表示他们是header头部的信息.所以$_SERVER中的变量凡是带有HTTP前缀的均是header信息,没有的则不是,如:$_SERVER[‘QUERY_STRING’], $_SERVER[‘PHP_SELF’]等.

用户可以创建自定义的header头部信息,并把这些信息发送给服务器端,服务器端就会记录这些header信息,并把他们存储到$_SERVER变量中,当然实现的变量名称变成了”HTTP_”连上用户的变量名称.比如上面的判断ajax请求.实际上是在向服务器发送异步请求之前,向header中加入一条header信息,实际的语句应该是:

HttpRequest对象.setRequestHeader(“X_REQUESTED_WITH”,”任意字符串”);服务器端通过$_SERVER[‘HTTP_X_REQUESTED_WITH’]这个变量是否存在,或具体的值来判断是否是ajax请求或具体是哪一条ajax请求.  所以利用这个不但可以验证请求是否是ajax请求,还可以获取更多的信息.

同样我们可以在header中任意设置其它的信息,用于跟服务器端进行数据交流.

比如:xmlHttpRequest.setRequestHeader(“test”,”just a test”);  那么被请求的服务器页面中的变量$_SERVER[‘HTTP_TEST’]的值就是”just a test”; 注意这里面前面的test不固定大小写.后面的$_SERVER[‘HTTP_TEST’]必须是大写.

全方位比较PHP的Node.js的优缺点

【编者按】PHP vs Node.js之争由来已久,前者用于动态网页开发,后者是用来编写高性能网络服务器的JavaScript工具包,到底他们如何?InfoWorld测试中心的Peter Wayner日前撰文指出两者的优势所在,不妨一看。

以下为译文:

这是典型好莱坞情节:分道扬镳的两位老朋友间的战斗。摩擦经常开始于一位对另一位不言而喻的领域感兴趣。这部电影的编程语言版本是Node.js的引入将好友情节变成一场旗鼓相当的比赛。PHP和JavaScript,两个曾经一起统治互联网的合作伙伴现在为了开发者心中的份额开始一决雌雄。

在过去,他们的合作关系很简单。JavaScript处理浏览器上的小细节,PHP处理所有的存在于80端口和MySQL的服务器端任务。这个幸福的联合不断支持着因特网的许多关键部分。在WordPress、Drupal和Facebook上,人们几乎不会离开PHP一分钟。

但是,后来一些聪明的孩子发现他能使JavaScript运行在服务器上。突然,我们发现没必要使用PHP构建下一代服务器栈了。一种语言就足够建立Node.js和运行在客户端的框架。对一些人来说,“JavaScript无处不在”变成了咒语。

当然,结局并没有写完。相比较与吹嘘Node.js的纯粹和JavaScript无处不在的简单的程序员,还有另外的程序员,他们对深度代码库和了解PHP的稳定性感到满意。怪老头能够击退服务器端新贵吗?JavaScript能推翻它的老朋友,实现统治世界吗?我们在微波炉里再抓一把爆米花,坐下来瞧瞧。

PHP赢在何处:混合内容的代码

你正在打字,想法随之变成你网站中的文本。你想为进程添加一个分支,根据URL的一些参数,一点if-then语句就会使它看起来漂亮。或者可能你想从数据库中加入文本或数据。用PHP,你能打开PHP魔法标签在几秒内开始编写代码。不需要模板——一切都是一个模板。不需要额外的文件或者煞费苦心的体系结构,因为可编程逻辑能量就在你的指尖。

Node赢在何处:分离的内容

混合内容的代码是拐杖,最终会使你受到损害。当然,在最初的两到三次,混合HTML代码是有趣的。但是不久,你的代码库乱成一团。真正的程序员添加结构,从逻辑层分离出装饰层。对新的程序员来说,代码很容易理解清楚,便于维护。运行在Node.js的框架由这样的程序员所建,他们知道当模型,视图和控制器分离时,生活会变得更好。

PHP赢在何处:深的代码库

网络充满了PHP代码。最受欢迎的构建网站平台(WordPress、Drupal和Joomla)都是用PHP编写。不仅这些开源平台,大部分他们插件也是用PHP编写。网上到处有PHP代码,它等着你去下载、修改和为你所用。

Node赢在何处:新的代码意味着更多现代特征

当然,网上有数以千计的开源PHP文件,但是一些是8岁的WordPress插件希望、祈祷有人下载它们。有谁愿意去花费几个小时、几天或者是几周的时间去倒腾那些已经好几年没有更新的代码?Node.js插件不仅是新的,而且用最新体系的完整知识构建而成。

PHP赢在何处:简单(在一定程度上)

PHP中没有太多的东西:几个处理字符串、数字的变量和基本函数。它除了把数据从80端口移动到数据库并返回,不会做的太多。这是应该做的。现代数据库是个神奇的工具,它能离开重的负载。对不应该复杂工作,PHP的复杂度是适量的。

Node赢在何处:闭包和更多的复杂性

JavaScript可能会有许多把一些人逼疯的小特质。但在大多数情况下,它是一个娱乐现代语法的现代语言,有几个有用的特征,比如闭包。你能容易地重新配置和拓展它,使强大的函数库像jQuery成为可能。你能像传递对象一样四处传递函数。为什么限制你自己呢?

PHP赢在何处:不需要客户端应用程序

所有的关于在浏览器和服务器上使用相同的语言的讨论是好的,但是如果你不需要在浏览器上使用任何语言呢?如果你运送HTML表单中数据呢?浏览器弹出,不会出现被未启动的JavaScript造成的令人头疼的事情和小故障,这个JavaScript试图在浏览器上创建一个来自二十多个web服务调用的页面。纯粹的HTML比其他东西工作更频繁,而PHP是最优化去创建HTML。为何费心在浏览器上用JavaScript呢?在服务器上建立所有操作,避免小手机上的小浏览器重载。

Node赢在何处:与HTML-fat PHP调用相对的瘦服务调用

虽然AJAX-crazy HTML5 Web应用程序有许多移动部件,他们很酷,非常有效。一旦JavaScript代码在浏览器缓存中,新数据沿着线路移动。这没有大量的HTML标记语言,不重复地去下载整个页面。只有数据改变了。如果你愿意投入时间创建一个平滑的浏览器端Web应用程序,这将会有不错的报酬。Node.js是最优化地去传送数据,仅仅只有数据通过Web服务。如果你的应用程序是复杂而又数据丰富的,这将是有效传送的良好基础。

PHP赢在何处:SQL

PHP与MySQL和它的许多变体,比如MariaDB。如果MySQL不全是正确的,还有其他的来自Oracle和Microsoft的伟大的SQL数据库。你的代码用很少的改变就能转换成你的查询。广阔的SQL世界没边界。一些最稳定,成熟的代码与SQL数据库连接,意味着所有力量也能容易地被整合到PHP项目中。它可能不是完美幸福的家庭,但它是大的。

Node.js赢在何处:JSON

如果你必须接入SQL,Node.js的函数库可以做到。但Node.js也有JSON,一个与许多最新NoSQL数据库交互的通用语言。这并不是说你不能为你的PHP栈获得JSON库,但当使用JavaScript时有些流体可使用JSON的简单性去处理。这是从浏览器到Web服务器,再到数据库的语法。冒号和花括号在每处的作用相同,这节约了你的时间。

PHP赢在何处:编码速度

对大多数开发者,编写PHP Web应用程序感到更快:没有编译器,没有部署,没有JAR文件或者预处理器——仅仅是你喜欢的编辑器和一些PHP文件目录。你的进度会不同,但就一起迅速确定项目而论,PHP是一个很好用的工具。

Node.js赢在何处:原始速度

编写JavaScript代码的过程中,当你在计算花括号和圆括号时,它有点难,但是编写成功后,你的Node.js代码可以飞。它的回调机制很巧妙,因为能帮你节约运行线程的时间。核心被建好,旨在为你做一切,这不是每个人想要的吗?

英文链接:PHP vs. Node.js: An epic battle for developer mind share

下面的内容更精彩

Ubuntu 14.04下搭建Node.js开发环境  http://www.linuxidc.com/Linux/2014-12/110983.htm

Ubunru 12.04 下Node.js开发环境的安装配置 http://www.linuxidc.com/Linux/2014-05/101418.htm

Node.Js入门[PDF+相关代码] http://www.linuxidc.com/Linux/2013-06/85462.htm

Node.js开发指南 高清PDF中文版 +源码 http://www.linuxidc.com/Linux/2014-09/106494.htm

Node.js入门开发指南中文版 http://www.linuxidc.com/Linux/2012-11/73363.htm

Node.js安装与配置 http://www.linuxidc.com/Linux/2013-05/84836.htm

Ubuntu 编译安装Node.js http://www.linuxidc.com/Linux/2013-10/91321.htm

Node.js 的详细介绍请点这里
Node.js 的下载地址请点这

ie css hack

问题 浏览器 DEMO 解决方法 Hacking Rules:

property:all-ie\9; property:gte-ie8\0;*property:lte-ie7; +property:ie7; _property:ie6;

1 input[button | submit] 不能用 margin:0 auto; 居中 IE8 bug | fixed 为input添加width 2 body{overflow:hidden;}没有去掉滚动条 IE6/7 bug | fixed 设置html{overflow:hidden;} 3 hasLayout的标签拥有高度 IE6/7 bug | fixed *height:0;
_overflow:hidden; 4 form>[hasLayout]元素有margin-left时,子元素中的[input | textarea] 出现2×margin-left IE6/7 bug | fixed form > [hasLayout 元素]{margin-left:宽度;}
form div{*margin-left:宽度÷2;} 5 当border-width有1条<边3条时被设置成dotted时,1px的边dotted显示成dashed IE7 bug | fixed 不在同一个元素上使用不同宽度的 dotted 6 当子元素有position:relative的时候,父元素设置overflow:[hidden|auto]相当于给子元素设置了position:visible; IE6/7 bug | fixed 给父元素设置position:relative; 7 :hover伪类不能改变有position:absolute的子级元素的left/top值 IE7 bug | fixed 把top/left的值设置成除0%外的所有百分值;或添加一个margin-[所有方向]除0外的所有值,包括0% 8 :focus + selector {} 选择器失效 IE8 bug | fixed 在失效选择器后面添加一个空选择器, :focus{} 9 列表中混乱的浮动:在list中浮动图片时,图片出现溢出正常位置;或没有list-style IE8 bug | fixed 用背景图片替换list-style 10 th 不会自动继承上级元素的 text-align IE8 bug | fixed 给th添加text-align:inherit; 11 样式(包括link/style/@import(link)) 最多允许个为是:32 IE6-8 ─ 常识 99.99%的情况下,不会遇到 12 :hover 时若background-color为#fff, 失效 IE7 bug | fixed 把background-color改成background。或者,非#fff || #ffffff 13 忽略’>’后有注释的选择器:selector> /**/ selector{} IE7 bug | fixed 官方DEMO有误 14 * html IE6 ─ HACK 只对IE6有效 15 PNG图片中的颜色和背景颜色的值相同,但显示不同 IE6-7 bug | fixed 利用 pngcrush 去除图片中的 Gamma profiles 16 margin:0 auto; 不能让block元素水平居中 IE6-8 bug | fixed 给block元素添加一个width 17 使用伪类 :first-line | :first-letter, 属性的值中出现!important 会使属性失效 IE8 bug | fixed !important is evil, don’t use it anymore 18 :first-letter 失效 IE6 bug | fixed 把 :first-letter 移到离{}最近的地方,如 h1, p:first-letter{},而非 p:first-letter h1{} 19 Position:absolute元素中,a display:block, 在非:hover时只有文本可点击 IE6/7 bug | fixed 给a添加background, 如果背景透明,使用background:url(‘任何页面中已经缓存的文件链接’),不推荐background:url(#)[官方的解决方法],因为会增加一下HTTP请求 20 float列表元素不水平对齐:li不设置float,a设置display:block;float:[方向],li不水平对齐 IE6/7 bug | fixed 给li设置display:inline 或 float:[方向] 21 dt, dd, li 背景失效 IE6 bug | fixed dt, dd, li{position:relative;} 22

iframe 兼容(转)

通常我们用 js 脚本创建 iframe 时,会这样写:

var iframe = document.createElement('iframe');

之后我们可能会定义 id、name、border 等属性,这些看似简单,其实 IE 与非 IE 浏览器之间、IE 和 IE 高版本之间的迥异,使得 iframe 的相关兼容性操作非常地有文章。

牛A:frameborder

现象:使用 (iframe.frameBorder = 数值) 或(iframe.setAttribute(‘frameborder’,数值)) 在 IE 浏览器下无效
原因:IE 浏览器区分属性名称大小写
解决方法:iframe.setAttribute(‘frameBorder’,’0′) Or iframe.setAttribute(‘frameborder’,’0′,0),兼容所有浏览器。

注:经测试,IE8已经修复此问题

牛B:动态将Form target到iframe

背景:假设现在我们要让一个 Form 表单结果提交到一个 HTML 结构中已存在的 iframe,会这样做:

OK,什么问题也没有,再假设我们需要提交到脚本动态生成的 iframe 中,会这样做:

去 IE 浏览器里试试,你会发现 Form 会在新窗口显示提交结果,Why?
原因:
我为此尝试了很久,结果是IE此前版本不能通过(iframe.name=)这种方式给 iframe 设置 name 值,也就是说生成的 iframe 是没有 name 值的,但却可以 alert 出来,这很诡异;当然,这也并不是没有解决办法。
解决方法,为此我们得为 IE 单独写一行代码:

  /*only for ie */ 
    var iframe = document.createElement(''); 

看到这行代码,我们笑了,这是天大的杯具(喜剧?)~~不管IE有多么搓的问题,他总会有自己一套解决之……
而且这行代码会在其他非 IE 浏览器抛出异常,所以我们可以利用这点来做最终版:

    var iframe; 
    try{ 
        iframe = document.createElement(''); 
    }catch(e){ 
        iframe = document.createElement('iframe'); 
    } 
    iframe.name = 'iframeNB'; 
    ... 
    someParent.appendChild(iframe); 
    ... 

[2009-12-9]补充:最佳实践 – YUI 是如何 creat iframe 的

    /** 
    * @description Creates an iframe to be used for form file uploads.  It is remove from the 
    * document upon completion of the upload transaction. 
    * @method createFrame 
    * @private 
    * @static 
    * @param {string} optional qualified path of iframe resource for SSL in IE. 
    * @return {void} 
    */ 
    function _createFrame(secureUri){ 
    // IE does not allow the setting of id and name attributes as object 
    // properties via createElement().  A different iframe creation 
    // pattern is required for IE. 
    var frameId = 'yuiIO' + this._transaction_id,io; 
    if(YAHOO.env.ua.ie){ 
        io = document.createElement(''); 
        // IE will throw a security exception in an SSL environment if the 
        // iframe source is undefined. 
        if(typeof secureUri == 'boolean'){ 
            io.src = 'javascript:false'; 
        } 
    }else{ 
        io = document.createElement('iframe'); 
        io.id = frameId; 
        io.name = frameId; 
    } 
    io.style.position = 'absolute'; 
    io.style.top = '-1000px'; 
    io.style.left = '-1000px'; 
    document.body.appendChild(io); 
    YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection'); 
    } 

这里需要额外注意到的一点是:

// IE will throw a security exception in an SSL environment if the
// iframe source is undefined.
if(typeof secureUri == 'boolean'){
io.src = 'javascript:false';
}

姑且算是牛D吧 =.=!

牛C:iframe.onload

关于 onload 这点大家可以参考怿飞师父的文章:判断 iframe 是否加载完成的完美方法,在此纯引用一次代码:

var iframe = document.createElement("iframe"); 
iframe.src = "http://www.planabc.net"; 
if (iframe.attachEvent) { 
    iframe.attachEvent("onload", function () { 
        alert("Local iframe is now loaded."); 
    }); 
} else { 
    iframe.onload = function () { 
        alert("Local iframe is now loaded."); 
    }; 

document.body.appendChild(iframe); 

需要注意到的是:

  • IE8也不支持iframe.onload
  • Opera两者均可,所以使用此方法会绑定前者
  • 即使我们不预设iframe.src = some urls,也会默认执行一次onload事件,可以通过分析 src 规避。

怎么写好兼容性好的iframe

通常我们用 js 脚本创建 iframe 时,会这样写:

var iframe = document.createElement('iframe');

之后我们可能会定义 id、name、border 等属性,这些看似简单,其实 IE 与非 IE 浏览器之间、IE 和 IE 高版本之间的迥异,使得 iframe 的相关兼容性操作非常地有文章。

牛A:frameborder

现象:使用 (iframe.frameBorder = 数值) 或(iframe.setAttribute(‘frameborder’,数值)) 在 IE 浏览器下无效
原因:IE 浏览器区分属性名称大小写
解决方法:iframe.setAttribute(‘frameBorder’,’0′) Or iframe.setAttribute(‘frameborder’,’0′,0),兼容所有浏览器。

注:经测试,IE8已经修复此问题

牛B:动态将Form target到iframe

背景:假设现在我们要让一个 Form 表单结果提交到一个 HTML 结构中已存在的 iframe,会这样做:

OK,什么问题也没有,再假设我们需要提交到脚本动态生成的 iframe 中,会这样做:

去 IE 浏览器里试试,你会发现 Form 会在新窗口显示提交结果,Why?
原因:
我为此尝试了很久,结果是IE此前版本不能通过(iframe.name=)这种方式给 iframe 设置 name 值,也就是说生成的 iframe 是没有 name 值的,但却可以 alert 出来,这很诡异;当然,这也并不是没有解决办法。
解决方法,为此我们得为 IE 单独写一行代码:

  /*only for ie */ 
    var iframe = document.createElement(''); 

看到这行代码,我们笑了,这是天大的杯具(喜剧?)~~不管IE有多么搓的问题,他总会有自己一套解决之……
而且这行代码会在其他非 IE 浏览器抛出异常,所以我们可以利用这点来做最终版:

    var iframe; 
    try{ 
        iframe = document.createElement(''); 
    }catch(e){ 
        iframe = document.createElement('iframe'); 
    } 
    iframe.name = 'iframeNB'; 
    ... 
    someParent.appendChild(iframe); 
    ... 

[2009-12-9]补充:最佳实践 – YUI 是如何 creat iframe 的

    /** 
    * @description Creates an iframe to be used for form file uploads.  It is remove from the 
    * document upon completion of the upload transaction. 
    * @method createFrame 
    * @private 
    * @static 
    * @param {string} optional qualified path of iframe resource for SSL in IE. 
    * @return {void} 
    */ 
    function _createFrame(secureUri){ 
    // IE does not allow the setting of id and name attributes as object 
    // properties via createElement().  A different iframe creation 
    // pattern is required for IE. 
    var frameId = 'yuiIO' + this._transaction_id,io; 
    if(YAHOO.env.ua.ie){ 
        io = document.createElement(''); 
        // IE will throw a security exception in an SSL environment if the 
        // iframe source is undefined. 
        if(typeof secureUri == 'boolean'){ 
            io.src = 'javascript:false'; 
        } 
    }else{ 
        io = document.createElement('iframe'); 
        io.id = frameId; 
        io.name = frameId; 
    } 
    io.style.position = 'absolute'; 
    io.style.top = '-1000px'; 
    io.style.left = '-1000px'; 
    document.body.appendChild(io); 
    YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection'); 
    } 

这里需要额外注意到的一点是:

// IE will throw a security exception in an SSL environment if the
// iframe source is undefined.
if(typeof secureUri == 'boolean'){
io.src = 'javascript:false';
}

姑且算是牛D吧 =.=!

牛C:iframe.onload

关于 onload 这点大家可以参考怿飞师父的文章:判断 iframe 是否加载完成的完美方法,在此纯引用一次代码:

var iframe = document.createElement("iframe"); 
iframe.src = "http://www.planabc.net"; 
if (iframe.attachEvent) { 
    iframe.attachEvent("onload", function () { 
        alert("Local iframe is now loaded."); 
    }); 
} else { 
    iframe.onload = function () { 
        alert("Local iframe is now loaded."); 
    }; 

document.body.appendChild(iframe); 

需要注意到的是:

  • IE8也不支持iframe.onload
  • Opera两者均可,所以使用此方法会绑定前者
  • 即使我们不预设iframe.src = some urls,也会默认执行一次onload事件,可以通过分析 src 规避。

JavaScript代码模块化的正规方法

RequireJS-CommonJS-AMD-ES6 Import/Export详解

为什么起了一个这个抽象的名字呢,一下子提了四个名词分别是:RequireJS,CommonJS,AMD,ES6,答案是因为现实很骨感,我们必须很勇敢才能正视这一段悲催的往事。如今的JavaScript平台正值如日中天,大家可能会忽略他的过去和弊端,这些弊端中一直被人诟病的就是JavaScript的包管理,比如类似Java中的import,其实理论上来讲这种基本元素的缺失大大的阻碍了人们对一种语言的认可,认为他难以担当大任,其实这么多年来JavaScript平台的发展主要还是他存在的位置比较有利,在浏览器中,有标准的支持和约束,跨平台等等,但是这种先天不足就没办法了,只能后天努力,这样从ES3-ES6不断地加入新的功能终于使JavaScript这门语言逐渐完备,这个漫长的过程让我们逐渐的明白了一个道理:社会的需求胜过十驾马车的力量可以催生一项技术不断的完善,进步。

正如前面提到的JavaScript没有包管理,不适合构建复杂应用,但是现实是就需要用JavaScript来构建复杂应用,因为随着社会的进步,人们对web应用的期许提高了,这都难不倒工程师,不是语言不提供么,我们有work around。先来说说CommonJS,

CommonJS的出发点是让JavaScript这门语言写出的代码可以跨前后端,(当然这里面指的是逻辑代码,不包含DOM, BOM操作)也就是可以在不同的宿主上跑,不如同一段代码可以跑在NodeJS也可以跑在Nashorn或者浏览器,但是事实上对CommonJS标准应用最多的是NodeJS平台,也就是NodeJS中的Require, 那么CommonJS Require为什么没有在浏览器里流行呢,主要原因是这个Require是同步的,这个浏览器接受不了,用户体验差,下面我们来说说浏览器中的AMD。

// sum.js
module.exports = {
  sum: function(a, b) { return a + b; }
};

// app.js
var assert = require(‘assert’);
var cal = require(‘./sum’);
assert.equal(3, cal.sum(1, 2));

CommonJS在浏览器中不行我们再找一个方式,总会有适合的,下面我们来说说AMD (Asynchronous Module Definition) 对CommonJS稍加改变,构造一个异步的变种就得到了AMD,示例代码如下,这下变成异步的了,终于可以在浏览器中使用了

// sum.js
define(“sum”, function() {
  return {
    sum: function(a, b) { return a + b; }
  };
});

// app.js
define(“app”, [“sum”], function(cal) {
  console.log(cal.sum(1, 2)); // => 3
});

但是以上的代码直接写是没办法运行的,如果想在浏览器中直接运行,需要知道define是个什么鬼,所以需要先把RequireJS引入,这就是RequireJS的作用,在浏览器中实现define, 引入依赖包。

// main.js
requirejs.config({ baseUrl: ‘/scripts’ });
requirejs([‘app’]);

看着这种不一致的痛苦ECMAScript 6终于忍不了了,加入了import/export标准来统一JavaScript世界,这就是标准的力量,但是从语法上来看还是同步的加载,还是没有办法支持浏览器,不知道这块ECMAScript 6是怎么考量的。

// sum.js
export function sum(a, b) { return a + b; }

// app.js
import * as cal from ‘sum’;

console.log(cal.sum(1, 2)); // => 3

综合以上的分析,在ES6还没有实现完成的今天如果想写一段同时支持前后台,支持AMD, CommonJS的代码要想下面这个样子。

;(function (root, factory, undef) {
    if (typeof exports === “object”) {
        // CommonJS
        module.exports = exports = factory(require(“./core”), require(“./cipher-core”));
    }
    else if (typeof define === “function” && define.amd) {
        // AMD
        define([“./core”, “./cipher-core”], factory);
    }
    else {
        // Global (browser)
        factory(root.CryptoJS);
    }
}(this, function (CryptoJS) {

    return CryptoJS.pad.Pkcs7;

}));

总结

本文总结了RequireJS,CommonJS,AMD,ES6 import/export的前世今生,并且对每个部分给出了完整的代码样例,希望对大家有所帮助。

转载自演道,想查看更及时的互联网产品技术热点文章请点击http://go2live.cn

非IE浏览器下Flash Player的Cookie/Session丢失Bug (转载 )

览器下Flash Player的Cookie/Session丢失Bug

这个bug,我整整折腾了2两天,目前为止还没找到一个好的解决方案。
好多人都遇到过,包括圣叹KingLongVSky 看来好多人都被这个该死的Bug QJ过了。
普遍的解决方法是使用JS获取FireFox中的Cookie,然后设置URLRequest中的data属性作为post方式传递过去,服务器读取Request对象中的POST的数据(不同的语言处理方式各不相同)进行校验,但是淘宝的校验只能使用Cookie验证,用POST传过去识别不了。而为了一个Flash改动验证系统基本不可能。

设想是使用一个代理页。

Flash通过post方式把cookie的数据传过去,代理页再模拟提交一次。这样开发说会遇到安全问题。遂罢!

至今无解,求解……

———————2009年9月18日 Update-———————

这个问题通过Flash本身解决好像已经基本无望了。

想更改URLRequestHeader因为安全问题,被罢掉。

还有另外一种方法是,当用户的浏览器为非IE时,在Flash的上层覆盖一个HTML的标签,通过HTML的上传机制解决,可非常无奈的是,我的Flash要输入中文,必定使得wmode要为window,所以想要在Flash上层覆盖一个标签 这种方案也被排除了。起初还想到另外一个方案就是通过代码模拟点击一个隐藏的标签,非常郁闷的是,因为安全限制,这个也不可能。

因此,目前来说还没找到一个更好的方法去解决或者绕过这个Bug

select ie6 浮层

今天发现 在ie6下。浮层不能遮盖select。

在网上搜索了下。结果如下。

原因为在ie6中。是把select当成一个窗口的。

解决这个问题就是在div上再加上iframe.

浮层

要注意 的iframe的z-index得为负数。如-1