minify:css和js的优化合并工具

Minify 是 PHP5 应用程序,它能合并、压缩 js 和 css 文件,并且能通过 HTTP gzip/deflate 及一些相关头,优化客户端缓存。

它会合并多个CSS或者JavaScript文件,移除一些不必要的空格和注释,进行gzip压缩,并且会设置浏览器的缓存头。Minify 在设计上和Yahoo的 Combo Handler Service非常像,不过Minify可以合并任何你想要合并的JavaScript和CSS文件。

下载地址:http://code.google.com/p/minify/

这个工具安装使用也非常简单。下载后放到网站根目录或任意目录,然后访问。

如放网站根目录,访问地址:http://localhost/min/builder/,则看到如下界面

在项目中的使用方法:

把 js 和 css 文件的路径按 Minify 的方式写,就完成了。

如单个css

<link media="screen" type="text/css" href="/min/f=style.css" rel="stylesheet" />

如果有多个,就用“,”隔开,如

<link media="screen" type="text/css" href="/min/f=style1.css,style2.css" rel="stylesheet" />

js也是一样写法

<script type="text/javascript" src="/min/f=script.js,script2.js"></script>

如果不知道路径怎么写,不要急,可以在http://localhost/min/builder/ 输入你需要合并压缩的 js 或 css 路径,按 Update 按钮后,它会给你生成一个完成的代码,你只需要将代码粘帖到文件中即可。

在wordpress下,也有一个插件,核心也是通过minify进行合并压缩,插件名称是wp-minify,
http://wordpress.org/extend/plugins/wp-minify/

我博客也试用了这个插件,呵呵。

win7 64位系统下安装zblog报数据库连接错误的解决方法

今天闲来无事,搭了个zblog玩玩,结果登陆后台管理页面的时候,页面老是报错“错误原因:数据库连接错误”.

估计和自己系统配置有关,因为之前也用过zblog,没出现过这个问题。百度了一下,找到了解决方案。

其实原因是在64位Windows7操作系统中,IIS7应用程序池默认没有启用32位应用程序,而我们连接ACCESS数据库的驱动程序Microsoft.Jet.OLEDB.4.0是32位的,所以就出错了,要想正常运行,只需启用32位应用程序即可。

方法如下:

1、打开IIS信息服务管理器。点击左侧菜单的“应用程序池”。

2、选中网站的程序池之后,点击右侧菜单的“高级设置”。

3、在弹出的设置框里,把“启用32位应用程序” 这个选项设置为“true”。

4、重启程序池即可。

整个步骤可查看下图:

 

解决PHP file_put_contents函数输出文件为UTF-8乱码问题

在做TES项目时,有个奇怪问题,生成html文件是UTF-8编码。而生成的CSS文件却是GBK编码。
代码都是一样,输出的编码类型却不一样。
经过测试,得出以下结论:
1、输出纯英文字符串时,其编码默认是GBK的,因为没有中文字符存在,则无法判断是否是utf-8。
2、有中文存在,则文件输出UTF-8的。

故解决方法如下:

<?php 

$f="Post.txt";
$p=iconv("ASCII","UTF-8","I love you.");
if(is_writable($f)){file_put_contents($f,chr(0xEF).chr(0xBB).chr(0xBF).$p);
}?>

原理很简单,主要是这句代码“chr(0xEF).chr(0xBB).chr(0xBF)”,人工指定输出BOM头即可。
否则的话,需要有UTF8编码的字符,例如中文字符。英文则UTF8和ASCII是一样的。

扩展jquery scroll事件,支持 scroll start 和 scroll stop

javascript里有一个事件是滚动事件,只要拖动滚动条,就会触发事件。

用jquery的话,这个事件scroll 可以查看jquery api :http://api.jquery.com/scroll/

但scroll 事件有一个缺陷,就是只能判断滚动条滚动,而不能监控滚动条停止滚动时的事件。

现用jquery扩展一下scroll 事件,新增

不多说,直接上代码实在点。

(function(){

    var special = jQuery.event.special,
        uid1 = 'D' + (+new Date()),
        uid2 = 'D' + (+new Date() + 1);

    special.scrollstart = {
        setup: function() {

            var timer,
                handler =  function(evt) {

                    var _self = this,
                        _args = arguments;

                    if (timer) {
                        clearTimeout(timer);
                    } else {
                        evt.type = 'scrollstart';
                        jQuery.event.handle.apply(_self, _args);
                    }

                    timer = setTimeout( function(){
                        timer = null;
                    }, special.scrollstop.latency);

                };

            jQuery(this).bind('scroll', handler).data(uid1, handler);

        },
        teardown: function(){
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid1) );
        }
    };

    special.scrollstop = {
        latency: 300,
        setup: function() {

            var timer,
                    handler = function(evt) {

                    var _self = this,
                        _args = arguments;

                    if (timer) {
                        clearTimeout(timer);
                    }

                    timer = setTimeout( function(){

                        timer = null;
                        evt.type = 'scrollstop';
                        jQuery.event.handle.apply(_self, _args);

                    }, special.scrollstop.latency);

                };

            jQuery(this).bind('scroll', handler).data(uid2, handler);

        },
        teardown: function() {
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid2) );
        }
    };

})();

可以将上面代码保存到一个文件,这相当于一个插件,呵呵。调用方法如下:

(function(){
	jQuery(window).bind('scrollstart', function(){
		console.log("start");
	});

	jQuery(window).bind('scrollstop', function(e){
		console.log("end");
	});

})();

查看demo:http://james.padolsey.com/demos/scrollevents/

不要滥用div,保持代码的整洁

这篇文章算是很基础的了。旨在介绍如何保证页面代码的整洁、以维护性。使用有语义的页面标签,减少标签的滥用。

1. 移除不必要的<div>标签

嵌套在<form><ul>外面的标签没有必要

例子:

2. 使用有语义的标记

<h1><ul><p>等标签,替代<div>,即便样式表丢失,仍然保证页面的可读性。

3. 尽量少的使用<div>标签

4. 代码缩进格式

5. 在</div>结尾处加上这个<div>块的注释

扩展阅读:http://webdesignerwall.com/tutorials/coding-clean-and-semantic-templates

HTML 5 Notifications api 桌面提醒接口

google chrome 浏览器支持html5 Notifications api ,用这个api 可以创建原生的提示信息,类似像OS X的Growl提示。

需要注意的是,您需要检查用户是否已提供您的站点许可来使用这个 API。如果没有,您必须请求许可,即是:需要用户手动按“允许”按钮。

完整实例:

<!DOCTYPE HTML>
<!-- http://dhtmlexamples.com/2011/01/28/creating-os-notifications-in-html5/ -->
<html>
<head>
    <title>Creating OS notifications in HTML5</title>
</head>
<body>

    <form>
        <input type="button" value="Hey, do you want to show notifications or not?" onclick="init();" />
        <input type="button" value="Send OS notification" onclick="notify();" />
    </form>

    <script type="text/javascript">
        const AUTO_CLOSE_DELAY_SECONDS = 5;

        function init() {
            if (window.webkitNotifications) {
                window.webkitNotifications.requestPermission();
            }
        }

        function notify() {
            var icon = "accept.png";
            var title = "[" + new Date().toLocaleTimeString() + "] This notification will close in " + AUTO_CLOSE_DELAY_SECONDS + " seconds";
            var body =  "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus id magna ut sapien sodales ultricies eget nec metus. Pellentesque molestie nunc nec leo iaculis eu dictum ante porta. Sed adipiscing condimentum sapien a scelerisque. Quisque luctus elit vel odio semper iaculis. Nunc sit amet neque justo. Phasellus ullamcorper dui vel risus varius vitae aliquet purus consectetur. Fusce felis nibh, volutpat ac ornare at, ullamcorper eget lacus. Nunc euismod iaculis porta. In hac habitasse platea dictumst. Proin a sem sed neque tincidunt scelerisque eget in elit. Ut quis felis quis tortor sollicitudin sollicitudin id quis tortor. Nunc porttitor diam id leo lobortis aliquet. Nam scelerisque molestie dolor, placerat hendrerit urna euismod eu. Praesent nec massa enim. Donec nec urna dignissim nunc fringilla luctus. Nunc pretium urna et diam accumsan fermentum. Vivamus condimentum lectus vitae mi vulputate pulvinar. Curabitur adipiscing ultrices arcu. Vestibulum luctus malesuada erat sit amet rutrum. Nam feugiat lectus quis libero adipiscing laoreet.";

            if (window.webkitNotifications) {
                if (window.webkitNotifications.checkPermission() == 0) {
                    var popup = window.webkitNotifications.createNotification(icon, title, body);
                    popup.ondisplay = function(event) {
                        setTimeout(function() {
                            event.currentTarget.cancel();
                        }, AUTO_CLOSE_DELAY_SECONDS * 1000);;
                    }
                    popup.show();
                } else {
                    window.webkitNotifications.requestPermission();
                    return;
                }
            }
        }
    </script>

</body>
</html>

扩展参考:
http://slides.html5rocks.com/#notifications-api
http://www.chromium.org/developers/design-documents/desktop-notifications/api-specification
http://www.html5rocks.com/en/tutorials/notifications/quick/

jquery获取图片真实宽高

var pic_real_width, pic_real_height;
$("<img/>") // Make in memory copy of image to avoid css issues
    .attr("src", $(img).attr("src"))
    .load(function() {
        pic_real_width = this.width;   // Note: $(this).width() will not
        pic_real_height = this.height; // work for in memory images.
    });

即将图片在内存里读取一遍即可。

Jquery利用getScript实现跨域请求数据

假设http://www.otherdomain.com/data.js 这个远程文件data.js内容如下:

testData={
    "rool": [
        {
            "desc": "小鸟_描述",
            "img": "http://t2.qpic.cn/mblogpic/47962be47270d036517c/160",
            "link": "2907109968",
            "title": "小鸟_标题"
        }
    ],
    "blockid": 1,
    "itemid": 1,
    "opt": 0,
    "pageid": 1,
    "tot": 1,
    "tplid": 0,
    "type": "mod_list_pic"
};
jQuery.getScript("http://www.otherdomain.com/data.js", function(){
   var data = testData;
   alert(data["rool"][0]["desc"]);//输出 “小鸟_描述”
});

说明:ajax不能跨域问题,大家应该都清楚。但是script标签能够加载其他域的文件,所以我们可以利用这点,进行跨域get操作。
这种方案要求跨域文件返回的数据必须是合法的JSON格式或者如JS文件的格式。
这种方式比较简单,只需要几行代码即可。如果不用jquery的话,可以通过动态创建script标签,然后设置src值,不过得注意判断script内容加载是否完成。

当然,跨域的方法很多,这里说的只是其中一种。

apache 配置反向代理解决javascript ajax跨域问题

1、打开apache下的http.conf 文件。
找到

#LoadModule proxy_module modules/mod_proxy.so
#LoadModule proxy_connect_module modules/mod_proxy_connect.so
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
#LoadModule proxy_http_module modules/mod_proxy_http.so

把前面的#去掉。(如果不开启这3个的话,ajax post 数据会出现http 500错误)

2、在http.conf文件末尾加上以下代码

ProxyRequests Off

<Proxy *>
Order deny,allow
Allow from all
</Proxy>

ProxyPass /foo/ http://foo.example.com/bar/
ProxyPassReverse /foo/ http://foo.example.com/bar/

说明 /foo/ 是本地服务器根目录下的foo文件夹。 这个文件夹映射到http://foo.example.com/bar/ 这里。

3、重启apache即可!

js就可以实现跨域post了。

$.post("http://localhost/foo/test.php")

实际是post到:http://foo.example.com/bar/test.php

相关参考网址:http://lamp.linux.gov.cn/Apache/ApacheMenu/mod/mod_proxy.html

http://shiningray.cn/proxypass-directive-in-apache.html

http://blog.csdn.net/paulluo0739/archive/2008/04/08/2260137.aspx

jquery扩展的2种方法比较

jQuery.extend = jQuery.fn.extend = function() {
     ...
};

我们可以用$.extend去扩展自定义的对象,如:

var myself = {name:jack};
$.extend(myself, {setName:function)(n){this.name=n;} });
myself.setName("tom");

通过$.extend为对象myself添加了setName方法。但这里主要讨论$.extend如何构建jquery库的。不知注意到上面代码中jQuery.extend和jQuery.fn.extend是同一个函数。我们浏览下jquery库,发现有些方法是通过调用jQuery.extend扩展的,有的则是通过调用jQuery.fn.extend扩展的。下面分别讨论:

1,通过jQuery.extend扩展

我们知道jQuery.extend中的jQuery类型是function,即typeof jQuery值为字符串“function”。如果把jQuery当成一个类,jQuery.extend相当于为该类添加了静态方法extend。静态方法是不需要new一个实例再去调用的,通过“类名+方法名”直接调用。即jQuery.extend(…),jQuery又被赋值给$。因此我们更习惯$.extend(…)。

源码中直接调用jQuery.extend方法,只传一个参数。如下:

jQuery.extend({
noConflict: function( deep ) {
window.$ = _$;
if ( deep )
window.jQuery = _jQuery;
return jQuery;
},
...
});

我们知道extend中如果只传一个参数,那么将执行该句:

target = this;
[/js]

即扩展自己,而这里的this则是function jQuery。也就是说给function jQuery添加了许多静态方法,这些方法都可以直接通过jQuery.xx(或$.xx)方式来调用,而不是先执行(调用)jQuery方法再去调用xx,如$(“#id”).xx。也许下面这个例子更容易理解:

function fun(){}//定义一个类(函数)

//为该类(函数)添加一个静态方法extend
fun.extend=function(obj){
for(var a in obj)
this[a] = obj[a];//注意:这里的tihs即fun
}

//调用extend为该类添加了静态属性name,静态方法method1
fun.extend({name:"fun",method1:function(){}});

//输出name,prototype,extend,method1
console.dir(fun)

因此,jquery中的isFunction, isArray, trim等都是静态方法,只能通过$.isFunction, $.isArray, $.trim来调用。而不能通过$(“…”).isFuction, $(“…”).isArray, $(“…”).trim调用。

2,通过jQuery.fn.extend扩展

jQuery.fn等于jQuery.prototype,也就是说给function jQuery的原型(prototype)上挂了个extend方法。通过调用jQuery.fn.extend(object)来扩展时(注意只传一个参数object),extend函数中仍然会执行

target = this;

而这时的this则是jQuery.prototype(上面则是jQuery函数自身)。即给jQuery.prototype上添加了许多属性,方法。当jQuery函数执行时,如$()或jQuery(),更多时候是$()。该函数会new一个jQuery(见上一篇jquery对象的组成)。这时则把扩展的属性,方法都附加到new生成的对象上了。也许下面这个示例更容易理解:

function fun(){}//定义一个类(函数)

//给该类原型上添加一个方法extned
fun.prototype.extend = function(obj){
	for(var a in obj)
		this[a] = obj[a];//注意:这里的this即是fun.prototype
}			

//调用extend方法给fun.prototype上添加属性,方法
fun.prototype.extend({name:"fun2",method1:function(){}})

//输出name,extend,method1
console.dir(new fun())

因此扩展的属性或方法都添加到jquery对象上了。
如bind, one, unbind等可以通过$(“…”).bind, $(“…”).one, $(“…”).unbind方式调用。却不能通过 $.bind, $.one, $.unbind方式调用。

jquery库与prototype库一样都是通过extend方法扩展出整个库的。相对来说jqueyr的扩展方式更难理解一些。
总结如下:
a,jQuery.extend({…})是给function jQuery添加静态属性或方法
b,jQuery().extend({…})是给jquery对象添加属性或方法。

ps:这里的jQuery即为$。

最后附一个jq1.4 extend源码分析:

/*!
 * jQuery源码分析-extend函数
 * jQuery版本:1.4.2
 * 
 * ----------------------------------------------------------
 * 函数介绍
 * jQuery.extend与jQuery.fn.extend指向同一个函数对象
 * jQuery.extend是jQuery的属性函数(静态方法)
 * jQuery.fn.extend是jQuery函数所构造对象的属性函数(对象方法)
 *
 * ----------------------------------------------------------
 * 使用说明
 * extend函数根据参数和调用者实现功能如下:
 * 1.对象合并:
 * 对象合并不区分调用者,jQuery.extend与jQuery.fn.extend完全一致
 * 也就是说对jQuery对象本身及jQuery所构造的对象没有影响
 * 对象合并根据参数区分,参数中必须包括两个或两个以上对象
 * 如:$.extend({Object}, {Object}) 或 $.extend({Boolean},{Object}, {Object})
 * 对象合并返回最终合并后的对象,支持深度拷贝
 * 
 * 2.为jQuery对象本身增加方法:
 * 这种方式从调用者和参数进行区分
 * 形式为 $.extend({Object})
 * 这种方式等同于 jQuery.{Fnction Name}
 * 
 * 3.原型继承:
 * 原型继承方式可以为jQuery所构造的对象增加方法
 * 这种方式也通过调用者和参数进行区分
 * 形式为 $.fn.extend({Object})
 * 这种方式实际上是将{Object}追加到jQuery.prototype,实现原型继承
 * 
 * ----------------------------------------------------------
 * 
 */
 
// jQuery.fn = jQuery.prototype
// jQuery.fn.extend = jQuery.prototype.extend
jQuery.extend = jQuery.fn.extend = function(){

    //目标对象
    var target = arguments[0] || {},    
    
    //循环变量,它会在循环时指向需要复制的第一个对象的位置,默认为1
    //如果需要进行深度复制,则它指向的位置为2
    i = 1,    
    
    //实参长度
    length = arguments.length,    
    
    //是否进行深度拷贝
    //深度拷贝情况下,会对对象更深层次的属性对象进行合并和覆盖
    deep = false,    
    
    //用于在复制时记录参数对象
    options,    
    
    //用于在复制时记录对象属性名
    name,    
    
    //用于在复制时记录目标对象的属性值
    src,    
    
    //用于在复制时记录参数对象的属性值
    copy;
    
    //只有当第一个实参为true时,即需要进行深度拷贝时,执行以下分支
    if (typeof target === "boolean") {
        //deep = true,进行深度拷贝
        deep = target;
        
        //进行深度拷贝时目标对象为第二个实参,如果没有则默认为空对象
        target = arguments[1] || {};
        
        //因为有了deep深度复制参数,因此i指向的位置为第二个参数
        i = 2;
    }
    
    //当目标对象不是一个Object且不是一个Function时(函数也是对象,因此使用jQuery.isFunction进行检查)
    if (typeof target !== "object" && !jQuery.isFunction(target)) {
        
        //设置目标为空对象
        target = {};
    }
    
    //如果当前参数中只包含一个{Object}
    //如 $.extend({Object}) 或 $.extend({Boolean}, {Object})
    //则将该对象中的属性拷贝到当前jQuery对象或实例中
    //此情况下deep深度复制仍然有效
    if (length === i) {
        
        //target = this;这句代码是整个extend函数的核心
        //在这里目标对象被更改,这里的this指向调用者
        //在 $.extend()方式中表示jQuery对象本身
        //在 $.fn.extend()方式中表示jQuery函数所构造的对象(即jQuery类的实例)
        target = this;
        
        //自减1,便于在后面的拷贝循环中,可以指向需要复制的对象
        --i;
    }
	
	//循环实参,循环从第1个参数开始,如果是深度复制,则从第2个参数开始
    for (; i < length; i++) {
        
        //当前参数不为null,undefined,0,false,空字符串时
        //options表示当前参数对象
        if ((options = arguments[i]) != null) {
            
            //遍历当前参数对象的属性,属性名记录到name
            for (name in options) {
                
                //src用于记录目标对象中的当前属性值
                src = target[name];
                
                //copy用于记录参数对象中的当前属性值
                copy = options[name];
                
                //存在目标对象本身的引用,构成死循环,结束此次遍历
                if (target === copy) {
                    continue;
                }
                
                //如果需要进行深度拷贝,且copy类型为对象或数组
                if (deep && copy && (jQuery.isPlainObject(copy) || jQuery.isArray(copy))) {
                
                    //如果src类型为对象或数组,则clone记录src
                    //否则colne记录与copy类型一致的空值(空数组或空对象)
                    var clone = src && (jQuery.isPlainObject(src) || jQuery.isArray(src)) ? src : jQuery.isArray(copy) ? [] : {};
                    
                    //对copy迭代深度复制
                    target[name] = jQuery.extend(deep, clone, copy);
                    
                    //如果不需要进行深度拷贝
                } else if (copy !== undefined) {
                    
                    //直接将copy复制给目标对象
                    target[name] = copy;
                }
            }
        }
    }
    
    //返回处理后的目标对象
    return target;
};


/**
 * jQuery框架本身对extend函数的使用非常频繁
 * 典型示例为jQuery.ajax
 * 
 */

//使用extend对jQuery对象本身进行扩展,只给了一个参数对象
//该对象中的属性将被追加到jQuery对象中
jQuery.extend({
 
    //jQuery.ajax
    //$.ajax
 
    //这里的origSettings参数是自定义的ajax配置
    //jQuery对象本身有一个ajaxSettings属性,是默认的ajax配置
    ajax: function(origSettings){ 
 
        //这里使用extend对ajax配置项进行合并
        //第一个参数表示进行深度拷贝
        //首先将第3个参数jQuery.ajaxSettings(即jQuery默认ajax配置)复制到第2个参数(一个空对象)
        //然后将第4个参数(自定义配置)复制到配置对象(覆盖默认配置)
        //这里的s就得到了最终的ajax配置项
        var s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings);
  
        //其它相关代码...(省略)
    }
});