预知加载控件 (predict load)

时髦说法,这个叫做“预知加载”或者是“柔性前端”。

传统的说,就是将已经知道的异步接口在系统空闲时自动加载。

功能描述:
当页面载入完成时,利用空闲的时间加载这些异步的对象。
如果点击时这个对象已经加载完成,则直接使用,如果还没有加载,则直接加载。

使用方法:
$elem.asynload( event, url, callback );

–Event: 事件类型( click hover mouseover mouseout …)
–URL:数据接口对应的URL,目前只支持JSON
–Callback: 回调函数
—-Data: 回调函数返回的接口对象

DEMO:http://www.zhangjingwei.com/demo/predload/

/**
* @author jingweiz
* Predict load JSON V1.0
* Syntax: $elem.asynload( event, url, callback );
*/
 
(function(){	
 
	// 初始化HASH
	var hashKey = window.predictload || {},
	    autoLoadHashKey = window.predictloadProcess || {};
 
    // 将URL转换为对应的KEY值
    function getHashKey( url ){
		return escape( url );
	}
 
	// 检查KEY是否存在于HASH表中
	function checkHashKey( key ){
		var result = hashKey[key];
		if(result){
			return result;
		}else{
			return false;
		}
	}
 
	// 将指定的键值写入到HASH表中 
	function setHASH( key, val ){
		hashKey[key] = val;
	}
 
	// 主动载入指定JSON URL,并将返回的对象写入到HASH表中
	function predictLoadJSON( url, callback ){
		var key = getHashKey( url );
 
		// 检查是否已经开始自动载入,如果开始则将进行宕掉
		if(checkAutoLoadJSON(key)){
			stopAutoLoadJSON(key);
		}
 
		$.getJSON(url,function(data){
			hashKey[key] = data;
			window.predictload = hashKey;
			callback.call(window, data);
		});
	}
 
	// 自动载入JSON URL(调用函数10秒+后自动载入)
	function autoLoadJSON( url ){
		var key = getHashKey( url );
 
		// 如果还没有开始自动载入,则开始
		if( !checkAutoLoadJSON(key) ){
			autoLoadHashKey[key] = setTimeout(function(){
	            $.getJSON(url,function( data ){
	                setHASH( key, data );
	            });
	        },10000 + 100*parseInt(10*Math.random())););
			// 通过全局变量进行调度
			window.predictloadProcess = autoLoadHashKey;
		}
	}
 
	// 检查与此URL对应的KEY是否在自动载入队列中
	function checkAutoLoadJSON( key ){
		return autoLoadHashKey[key] != undefined;
	}
 
	// 停止对应KEY的自动载入
	function stopAutoLoadJSON( key ){
		clearTimeout( autoLoadHashKey[key] );
	}
 
	$.fn.predload = function( evt, url, callback ){
		var $self = this;
 
		$self.bind(evt,function(){
			var data = checkHashKey(getHashKey(url));
			if( data ){
				callback.call($self,data);
			}else{
				predictLoadJSON( url, function( data ){
				    callback.call($self, data);
				});
			}
		});
 
		// 调用时候将URL压入自动执行的序列
		autoLoadJSON( url );
	}
 
})(jQuery);

原文链接(19 views)|暂无评论(赶紧抢沙发)

jQuery Select

TextMate下的中文看起来实在是费劲,所以就都去掉了。

使用很简单,select还是按照原来的BOM去写,然后构造对应DOM的jQuery对象,再调用selectinput方法即可。

BTW:下拉菜单的样式需要自己去写一下,对应的样式参数在conf.css这个对象下。

/*
 * Select zhangjingwei
 * Released under the MIT, BSD, and GPL Licenses.
 */
(function ($) {
 
    $.tools = $.tools || {
        version: '1.3'
    };
 
    var instances = [],
    tool = $.tools.selectinput = {
        conf: {
            offset: 0, // 弹出菜单偏移量
            trigger: false, // 默认触发
            css: {
                // ids
                root: 0,
                head: 0,
 
                // classnames
                list: 0,    // liststyle ?
                off: 0,     // 鼠标移动上的样式
                focus: 0,   // 获取焦点样式
                disabled: 0, // 禁止选择样式
                trigger: 0, // 触发后的样式
                current: 0, // 节点被选中的样式
                mouseon: 0  // 鼠标移动触发样式
            }
        }
    }
 
    function Selects(select, conf, i) {
        var self = this,
        css = conf.css,
        hid = css.head || "selhead_jQuery" + i,
        rid = css.root || "selroot_jQuery" + i,
        root = $("#" + rid),
        head = $("#" + hid),
        title,
        index,
        currentClass = css.current,
        opened,
        selstyle = select.offset(),
        fire = select.add(self);
        // 容灾处理
        if (!root.length && !head.length) {
            var body = $("body");
            index = getSelectIndex(), title = getSelectText();
 
            root = $('<ul />').css(selstyle).css({ "position": "absolute", "height": "auto" }).addClass(css.list).attr("id", rid).hide();
 
            select.find("option").each(function (i, n) {
                var val = n.value, text = n.firstChild.nodeValue || n.innerText;
                root.append("<li data-value='" + val + "' data-index='" + i + "'><a href='#'>" + text + "</a></li>")
            });
            root.find("li").eq(index).addClass(currentClass);
 
            head = $("<a />").attr("href", "#").html(title).css(selstyle).css({ "position": "absolute" }).addClass(css.off).attr("id", hid).click(function (e) {
                self.show();
                return e.preventDefault();
            }).appendTo(body);
 
            body.append(root);
 
            select.css("visibility", "hidden");
 
			$(window).resize(function () {
                var pos = select.offset();
                head.css(pos);
            });
        }
 
        if (conf.trigger) {
            self.show();
        }
 
        function onShow(ev) {
            ev.type = "onShow";
            fire.trigger(ev);
 
            // click outside select
            $(document).bind("click.sel", function (e) {
                var el = e.target;
 
                if (el != head[0]) {
                    self.hide(e);
                }
            });
        }
 
        // 选择函数
        function selected(index, e) {
            var elem = root.find("li"),
			currentElem = elem.eq(index),
			currentText = currentElem.text();
 
            elem.removeClass(css.current);
            currentElem.addClass(css.current);
            head.html(currentText);
            setSelected(index);
 
            // change
            e = e || $.Event("api");
            e.type = "change";
 
            fire.trigger(e, index);
            if (e.isDefaultPrevented()) {
                return;
            }
 
            self.hide(e);
        }
 
        /*
        * 设置selectindex
        */
        function setSelected(index) {
            select[0].selectedIndex = index;
        }
 
        /*
        * 获取选中项值
        */
        function getSelectVal() {
            return select.find("option:selected").val();
        }
 
        /*
        * 获取选中项文本
        */
        function getSelectText() {
            return select.find("option:selected").text();
        }
 
        /*
        * 获取selectindex
        */
        function getSelectIndex() {
            return select[0].selectedIndex;
        }
 
        $.extend(self, {
            show: function (e) {
                if (select.attr("disabled") || opened) {
                    return;
                }
                // onBeforeShow
                e = e || $.Event();
                e.type = "onBeforeShow";
                fire.trigger(e);
                if (e.isDefaultPrevented()) {
                    return;
                }
 
                // 关闭所有已打开select
                $.each(instances, function () {
                    this.hide();
                });
                opened = true;
 
                root.find("li").unbind("click mouseenter mouseleave").click(function (e) {
                    self.setValue($(this).index(), e);
                    return false;
                }).hover(
                    function () {
                        $(this).addClass(css.mouseon);
                    },
                    function () {
                        $(this).removeClass(css.mouseon);
                    }
                );
 
                // show select
                var pos = select.offset();
 
                // iPad position fix
                if (/iPad/i.test(navigator.userAgent)) {
                    pos.top -= $(window).scrollTop();
                }
 
                if (conf.offset) {
                    root.css({
                        top: pos.top + conf.offset[0],
                        left: pos.left + conf.offset[1]
                    });
                }
 
                root.show();
                onShow(e);
 
                return self;
            },
            hide: function (e, slis) {
                if (opened) {
                    // onHide
                    e = $.Event();
                    e.type = "onHide";
                    fire.trigger(e);
 
                    $(document).unbind("click.sel").unbind("keydown.sel");
 
                    // cancelled ?
                    if (e.isDefaultPrevented()) {
                        return;
                    }
 
                    // do the hide
                    root.hide();
                    root.find("li").unbind("click");
                    opened = false;
                }
 
                return self;
            },
            setValue: function (index, evt) {
                evt = evt || $.Event("api");
                selected(index, evt, conf);
                return self;
            },
            reflow: function () {
                var pos = select.offset(),
				headelem = select.data("selectinput");
 
                if (headelem) {
                    head.css({ top: pos.top, left: pos.left });
                }
                return self;
            },
            getConf: function () {
                return conf;
            },
            getRoot: function () {
                return root;
            },
            getHead: function () {
                return head;
            },
            getSelect: function () {
                return select;
            },
            isOpen: function () {
                return opened;
            }
        });
 
        // callbacks
        $.each(['onBeforeShow', 'onShow', 'change', 'onHide'], function (i, name) {
 
            // configuration
            if ($.isFunction(conf[name])) {
                $(self).bind(name, conf[name]);
            }
 
            // API methods
            self[name] = function (fn) {
                if (fn) {
                    $(self).bind(name, fn);
                }
                return self;
            };
        });
    }
 
    $.fn.selectinput = function (conf) {
 
        // 单例
        if (this.data("selectinput")) {
            return this;
        }
 
        //
        conf = $.extend(true, {}, tool.conf, conf);
 
        var els;
 
        this.each(function (key) {
            var el = new Selects($(this), conf, $.now() + key);
            instances.push(el);
            var sel = el.getSelect().data("selectinput", el);
            els = els ? els.add(sel) : sel;
        });
        return els ? els : this;
    };
})(jQuery);

原文链接(336 views)|评论 (2)

javascript 序列化

类似php中的serialize方法
BTW:当数据类型是null的时候,由于使用typeof 进行验证,所以会出现问题.(typeof null == “object”) // true

function serialize(_obj)
{
   // Let Gecko browsers do this the easy way
   if (typeof _obj.toSource !== 'undefined' && typeof _obj.callee === 'undefined')
   {
      return _obj.toSource();
   }
 
   // Other browsers must do it the hard way
   switch (typeof _obj)
   {
      // numbers, booleans, and functions are trivial:
      // just return the object itself since its default .toString()
      // gives us exactly what we want
      case 'number':
      case 'boolean':
      case 'function':
         return _obj;
         break;
 
      // for JSON format, strings need to be wrapped in quotes
      case 'string':
         return '\'' + _obj + '\'';
         break;
 
      case 'object':
         var str;
         if (_obj.constructor === Array || typeof _obj.callee !== 'undefined')
         {
            str = '[';
            var i, len = _obj.length;
            for (i = 0; i < len-1; i++) { str += serialize(_obj[i]) + ','; }
            str += serialize(_obj[i]) + ']';
         }
         else
         {
            str = '{';
            var key;
            for (key in _obj) { str += key + ':' + serialize(_obj[key]) + ','; }
            str = str.replace(/\,$/, '') + '}';
         }
         return str;
         break;
 
      default:
         return 'UNKNOWN';
         break;
   }
}

来源:http://blog.stchur.com/2007/04/06/serializing-objects-in-javascript/–Serializing Objects in Javascript

原文链接(138 views)|评论 (3)

闲谈 node (初探)

以前编写js的时候,总是在各种浏览器之间纠结,有时纠结兼容性问题,有时纠结性能或效率,很多时候看着后端工程师玩弄着各种数据心里就痒痒,只能感叹,js不给力。

不过在这一切都是浮云的世界,什么都在变,就和打麻将一样,风水轮流转,无论是Python还是Ruby,无论是BigTable或是Dynamo,就连CPU都尼玛从双核到四核,甚至把“显卡”也集成进去了,咱们的JS也应该发光发热了吧?

是的,一切都很给力,node就是这样,它就这样诞生了。

node,一个JS的运行环境,一个放在服务器上的JS运行环境,没错,他不是放在浏览器上,他是能像PHP一样跑在服务器上的运行环境。:)

我看到面前的PHP工程师笑了,我看到各位写C的同学笑了,好吧,正所谓拉车的用马,碾磨的用驴,面对日渐庞大的网络应用环境,面对无数用JS支撑起来的交互效果,面对数以万计想用JS干掉PHP的前端同学,让我们深究一下node究竟给不给力吧。

言归正传,无论是7天学会PHP还是7天学会C++第一步都是从“Hello World”,哦,不,是从安装环境开始,我们也入乡随俗,从这儿开始。

官方安装说明(https://github.com/joyent/node/wiki/Installation

主要内容如下

git clone https://github.com/joyent/node.git
cd node
export JOBS=2 # optional, sets number of parallel commands.
mkdir ~/local
./configure --prefix=$HOME/local/node
make
make install
export PATH=$HOME/local/node/bin:$PATH

根据中国特色我们需要注意:
1、确认你的系统为Linux,Mac或者Solaris,如果你试图在Windows或者Unix上安装如果你试图在Windows或者Unix(除Mac OS外)上安装,请先尝试安装编译环境,可百度,一定很多。
2、安装libssl-dev和python,通常情况下他们都有。
3、如果是Mac,需要安装Xcode。
4、你也可以通过包管理器进行安装(https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager),看到这里我吐了。。。
5、因为最近墙有问题,所以大部分时候Git都很慢,请耐心等待或者翻墙。

好,现在我们

node -v

看看是否成功了吧!

行了,到这里我们基本上就准备完成了,可以执行国际惯例,HelloWorld了。

console.log('hello world');

前端同学一定惊呼,我x,好熟悉啊,这不是我们经常在firebug里面用的console么?是的,node使用console来输出调试,当然如果你喜欢步进调试,喜欢逆向工程中不断的下断点来调试,你可以尝试Qleelulu这样帅气的debug,虽然我认为这样非常低效。 :-)

好了,现在可以运行也可以调试了,我和同学们都兴奋了,我要写个百度乐居(AD),我要写个新浪微博(AD),我要写个淘宝(AD),我X,我怒吼,不要慌!俗话说得好,工欲善其事,必先利其器,让我们看看nodeJS的wiki上还有什么?

nom(node package manager)
npm 是基于 node 的包管理器,通过npm,我们可以很容易的安装其它基于node的扩展
官网地址:https://github.com/isaacs/npm
安装npm很简单,一句话

curl http://npmjs.org/install.sh | sh

通常情况下这样是可以安装成功,但是我在Mac上这样安装总是失败,如果不幸的你也失败可参考下面的安装方式

git clone http://github.com/isaacs/npm.git
cd npm
sudo make install

Linux下很顺利,一次成功!

备注:
查找npm提供的包有两种方式,第一种是通过”npm find”命令查找,第二种可通过http://search.npmjs.org/查找。

让我们从node 的 modules list页面中选择一个框架(https://github.com/joyent/node/wiki/modules
为了简便开发,通常我们都会选择一个框架,就像Zend或者Rails一样,这里我选择的是Express,因为大家都说好。。。
Express官网:http://expressjs.com/

Express的安装非常简单,借助我们刚才安装的npm,既可直接安装了

npm install express

安装完毕之后,在开发目录下存在一个node_modules的文件夹用来存放这些扩展。
接下来,我们就可以使用express来开发写一个可以运行在浏览器上的Hello World了

var express = require('express');
var app = express.createServer();
 
app.get('/', function(req, res){
    res.send('Hello World');
});
 
app.listen(3000);

然后访问本地http://127.0.0.1:3000/
好了,世界再一次被问好了。

至此,我们的准备工作已经完成,下一篇我们准备写点什么吧!

原文链接(318 views)|评论 (5)

构造函数(constructor)的超类

  function test1( name ){
    this.name = name;
  }
 
  function test2( name ){
    test1.call(this,name);
    this.say = function(){}
  }
 
  test2.prototype = new test1;
 
  var t = new test2("nihao");
 
  console.log(t);
  console.log(t.constructor);

t的constructor说明了t的构造函数是test1,而不是test2。

这是因为t的constructor实际上是test2.prototype的constructor,而test2.prototype = new test1;因此test2test2.prototype的constructor属性就指向到了test1的prototype.constructor上test1.prototype的constructor上,也就是test1。

罗里吧嗦的,这标题起的还挺唬人的~呵呵

原文链接(74 views)|沙发已被占领(1)