作者: admin

  • wordpress禁用无用的功能优化提升速度

    我的wp优化 wordpress 禁用

    wordpress_up

     

    1,禁止wp更新 : open file “wordpress\wp-includes\update.php”.

    add_filter(‘pre_site_transient_update_core’, create_function(‘$a’, ‘return null;’)); // 关闭核心提示

    add_filter(‘pre_site_transient_update_plugins’, create_function(‘$a’, ‘return null;’)); // 关闭插件提示

    add_filter(‘pre_site_transient_update_themes’, create_function(‘$a’, ‘return null;’)); // 关闭主题提示

    remove_action(‘admin_init’, ‘_maybe_update_core’); // 禁止 WordPress 检查更新

    remove_action(‘admin_init’, ‘_maybe_update_plugins’); // 禁止 WordPress 更新插件

    remove_action(‘admin_init’, ‘_maybe_update_themes’); // 禁止 WordPress 更新主题
    2,将下面的代码添加到当前主题的 functions.php 文件,即可禁用所有页面的评论功能:
    function disable_page_comments( $posts ) {
    if ( is_page()) {
    $posts[0]->comment_status = ‘disabled’;
    $posts[0]->ping_status = ‘disabled’;
    }
    return $posts;
    }
    add_filter( ‘the_posts’, ‘disable_page_comments’ );
    3,禁用及删除版本修订历史
    版本修订历史在每一次编辑文章过后,都会自动保留一份,这样的话很容易造成数据的重复储存,占用不必要的资源。
    打开wp-config.php,在末尾添加
    define(‘WP_POST_REVISIONS’, false);
    4,禁用自动保存
    在wp-admin目录,打开post.php、page.php、post-new.php和page-new.php,查找

    wp_enqueue_script(‘autosave’);

    替换为

    //wp_enqueue_script(‘autosave’);

     

     

    5,禁用自动草稿

    在wp-admin/includes目录,打开post.php,查找

    if ( $create_in_db ) {
    $post_id = wp_insert_post( array( ‘post_title’ => __( ‘Auto Draft’ ), ‘post_type’ => $post_type, ‘post_status’ => ‘auto-draft’ ) );
    $post = get_post( $post_id );
    if ( current_theme_supports( ‘post-formats’ ) && post_type_supports( $post->post_type, ‘post-formats’ ) && get_option( ‘default_post_format’ ) )
    set_post_format( $post, get_option( ‘default_post_format’ ) );
    }

    替换为

    if ( $create_in_db ) {
    global $current_user;
    $post = $wpdb->get_row( “SELECT * FROM $wpdb->posts WHERE post_status = ‘auto-draft’ AND post_type = ‘$post_type’ AND post_author = $current_user->ID ORDER BY ID ASC LIMIT 1” );
    if ( !$post ) {
    $post_id = wp_insert_post( array( ‘post_title’ => __( ‘Auto Draft’ ), ‘post_type’ => $post_type, ‘post_status’ => ‘auto-draft’ ) );
    $post = get_post( $post_id );
    }
    if ( current_theme_supports( ‘post-formats’ ) && post_type_supports( $post->post_type, ‘post-formats’ ) && get_option( ‘default_post_format’ ) )
    set_post_format( $post, get_option( ‘default_post_format’ ) );
    }
    WordPress禁止版本修订历史、自动保存和自动草稿

  • Node.js http模块 使用详解

    直接通过http对象使用的有:

    一、http.STATUS_CODES

    二、http.createServer

    三、http.request(http.ClientRequest)

    四、http.get

    五、http.globalAgent

    六、http.IcomingMessage

    作为回调参数使用的对象有:

    1.http.serverRequest

    2.http.serverResponse

    3.http.Agent

     

    一、http.STATUS_CODES

    众所周知,http服务器就是一个状态服务器,可以根据状态码来确定服务器是处于请求的什么状态。如下列出Node.js status code的全部状态对于的解释。

    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    http: {
        STATUS_CODES: {
            '100''Continue',
                '101''Switching Protocols',
                '102''Processing',
                '200''OK',
                '201''Created',
                '202''Accepted',
                '203''Non-Authoritative Information',
                '204''No Content',
                '205''Reset Content',
                '206''Partial Content',
                '207''Multi-Status',
                '300''Multiple Choices',
                '301''Moved Permanently',
                '302''Moved Temporarily',
                '303''See Other',
                '304''Not Modified',
                '305''Use Proxy',
                '307''Temporary Redirect',
                '400''Bad Request',
                '401''Unauthorized',
                '402''Payment Required',
                '403''Forbidden',
                '404''Not Found',
                '405''Method Not Allowed',
                '406''Not Acceptable',
                '407''Proxy Authentication Required',
                '408''Request Time-out',
                '409''Conflict',
                '410''Gone',
                '411''Length Required',
                '412''Precondition Failed',
                '413''Request Entity Too Large',
                '414''Request-URI Too Large',
                '415''Unsupported Media Type',
                '416''Requested Range Not Satisfiable',
                '417''Expectation Failed',
                '418''I\'m a teapot',
                '422''Unprocessable Entity',
                '423''Locked',
                '424''Failed Dependency',
                '425''Unordered Collection',
                '426''Upgrade Required',
                '428''Precondition Required',
                '429''Too Many Requests',
                '431''Request Header Fields Too Large',
                '500''Internal Server Error',
                '501''Not Implemented',
                '502''Bad Gateway',
                '503''Service Unavailable',
                '504''Gateway Time-out',
                '505''HTTP Version Not Supported',
                '506''Variant Also Negotiates',
                '507''Insufficient Storage',
                '509''Bandwidth Limit Exceeded',
                '510''Not Extended',
                '511''Network Authentication Required'
        }
    }

     

    测试用例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var http = require('http');
    http.createServer(function(req,res){
       var status = req.url.substr(1);
        if( ! http.STATUS_CODES[status])
        {
            status = '404';
        }
        res.writeHeader(status,{'Content-Type':'text/plain'});
        res.end(http.STATUS_CODES[status]);
    }).listen(3000);

     

    测试连接:http://localhost:3000/500  结果输出 Internal Server Error

    二、http.createServer

    http.createServer是创建一台web服务器的关键所在,是处理请求和回应的主函数出口和出口,我们把http.createServer创建的服务对象定义为server.代码如下。

    /**
     * Created by Administrator on 14-4-29.
     */
    var http = require('http');
    /**
     * 创建服务器的两种写法,第一种写法如下
     * 由于server已经继承了EventEmitter的事件功能,所以可以使用高级函数编写方式监控事件
     * @param {Function} request event
    */
    var server = http.createServer(function(req,res)
    {
        //这里的req为http.serverRequest
        res.writeHeader(200,{'Content-Type':'text/plain'});
        res.end('hello world');
    });
    /**
     * 说明:创建服务器的第二种写法
     * 有关server对象的事件监听
     * @param {Object} req 是http.IncomingMessag的一个实例,在keep-alive连接中支持多个请求
     * @param {Object} res 是http.ServerResponse的一个实例
     */
    var server = new http.Server();
    server.on('request',function(req,res){
        res.writeHeader(200,{'Content-Type':'text/plain'});
        res.end('hello world');
    });
    /**
     * 说明:新的TCP流建立时出发。 socket是一个net.Socket对象。 通常用户无需处理该事件。
     * 特别注意,协议解析器绑定套接字时采用的方式使套接字不会出发readable事件。 还可以通过request.connection访问socket。
     * @param {Object} socket
     */
    server.on('connection',function(socket){});
    /**
     * 源API: Event: 'close'
     * 说明:关闭服务器时触发
     */
    server.on('close',function(){});
    /**
     * 说明:每当收到Expect: 100-continue的http请求时触发。 如果未监听该事件,服务器会酌情自动发送100 Continue响应。
     * 处理该事件时,如果客户端可以继续发送请求主体则调用response.writeContinue, 如果不能则生成合适的HTTP响应(例如,400 请求无效)
     * 需要注意到, 当这个事件触发并且被处理后, request 事件将不再会触发.
     * @param {Object} req
     * @param {Object} req
     */
    server.on('checkContinue',function(req,res){});
    /**
     * 说明:如果客户端发起connect请求,如果服务器端没有监听,那么于客户端请求的该连接将会被关闭
     * @param {Object} req 是该HTTP请求的参数,与request事件中的相同。
     * @param {Object} socket 是服务端与客户端之间的网络套接字。需要自己写一个data事件监听数据流
     * @param {Object} head 是一个Buffer实例,隧道流的第一个包,该参数可能为空。
     */
    server.on('connect',function(req,socket,head){});
    /**
     * 说明:这个事件主要是对HTTP协议升级为其他协议后的事件监听,如果服务器端没有监听,那么于客户端请求的该连接将会被关闭
     * @param {Object} req 是该HTTP请求的参数,与request事件中的相同。
     * @param {Object} socket 是服务端与客户端之间的网络套接字。需要自己写一个data事件监听数据流
     * @param {Object} head 是一个Buffer实例,升级后流的第一个包,该参数可能为空。
     */
    server.on('upgrade',function(req,socket,head){});
    /**
     * 说明:如果一个客户端连接触发了一个 'error' 事件, 它就会转发到这里
     * @param {Object} exception
     * @param {Object} socket
     */
    server.on('clientError',function(exception,socket){});
    /**
     * 源API:server.listen(port, [hostname], [backlog], [callback])
     * 说明:监听一个 unix socket, 需要提供一个文件名而不是端口号和主机名。
     * @param {Number} port 端口
     * @param {String} host 主机
     * @param {Number} backlog 等待队列的最大长度,决定于操作系统平台,默认是511
     * @param {Function} callback 异步回调函数
     */
    //server.listen(3000,'localhost',100,function(){});
    /**
     * 源API:server.listen(path, [callback])
     * 说明:启动一个 UNIX 套接字服务器在所给路径 path 上监听连接。
     * 可能用处:多路径或渠道数据来源监听分隔
     * @param {String} path
     * @param {Function} callback
     */
    //server.listen('path',function(){})
    /**
     * 源API:server.listen(handle, [callback])
     * 说明:Windows 不支持监听一个文件描述符。
     * @param {Object} handle 变量可以被设置为server 或者 socket
     * @param {Function} callback
     */
    //server.listen({},function(){});
    /**
     * 说明:最大请求头数目限制, 默认 1000 个. 如果设置为0, 则代表不做任何限制.
     * @type {number}
     */
    server.maxHeadersCount = 1000;
    /**
     * 源API:server.setTimeout(msecs, callback)
     * 说明:为套接字设定超时值。如果一个超时发生,那么Server对象上会分发一个'timeout'事件,同时将套接字作为参数传递。
     * 设置为0将阻止之后建立的连接的一切自动超时行为
     * @param {Number} msecs
     * @param
     */
    server.setTimeout(1000,function(){});
    /**
     * 说明:一个套接字被判断为超时之前的闲置毫秒数。 默认 120000 (2 分钟)
     * @type {number}
     */
    server.timeout = 120000;
    /**
     * 说明:这里的主机将是本地
     * @param {Number} port 端口
     * @param {Function} callback 异步回调函数
     */
    server.listen(3000,function(){
       console.log('Listen port 3000');
    });

     

     

     

     

    三 、http.request

    http 模块提供了两个函数 http.request 和 http.get,功能是作为客户端向 HTTP服务器发起请求。http.request(options, callback) 发起 HTTP 请求。接受两个参数,option 是一个类似关联数组的对象,表示请求的参数,callback 是请求的回调函数。option常用的参数如下所示。 http.request 返回一个 http.ClientRequest 的实例。

    /**
     * Created by Administrator on 14-4-30.
     */
    var http = require('http');
    var server = http.createServer(function(req,res){
    }).listen(3000);
    /**
     * 参数配置
     * @type {{hostname: string, port: number, method: string, path: string,handers: {}}}
     * host:请求的服务器域名或者IP地址
     * port:端口
     * method:请求方式有POST,GET,INPUT,DELETE,CONNECT,默认为GET
     * path:请求地址,可包含查询字符串以及可能存在的锚点。例如'/index.html?page=12'
     * handers: 一个包含请求头的对象。
     */
    var options =
    {
        hostname : 'www.google.com',
        port : 80,
        method : 'POST',
        path : '/upload',
        handers:{}
    };
    /**
     * 如下特别的消息头应当注意:
     * 发送'Connection: keep-alive'头部将通知Node此连接将保持到下一次请求。
     * 发送'Content-length'头将使默认的分块编码无效。
     * 发送'Expect'头部将引起请求头部立即被发送。
     * 通常情况,当发送'Expect: 100-continue'时,你需要监听continue事件的同时设置超时。参见RFC2616 8.2.3章节以获得更多的信息。
     */
    /**
     * 说明:官方给出的例子
     * 应用场景:模拟客服端请求服务器,是一个HTTP 客户端工具,用于向 HTTP 服务器发起请求。
     * @param {Object} options
     * @param {Function} callback
     */
    var req = http.request(options,function(res){
        console.log(res);
        console.log('STATUS:' + res.statusCode);
        console.log('HEADERS:' + JSON.stringify(res.headers));
        res.setEncoding('utf8');
        res.on('data',function(chunk){
           console.log('BODY' + chunk);
        });
    });
    req.on('response',function(){
    });
    req.on('connect',function(){
    });
    req.on('socket',function(){
    });
    req.on('upgrade',function(){
    });
    req.on('continue',function(){
    })
    //如果在请求过程中出现了错误(可能是DNS解析、TCP的错误、或者HTTP解析错误),返回的请求对象上的'error'的事件将被触发。
    req.on('error',function(e){
       console.log(e.message);
    });
    /**
     * 源API:request.write(chunk, [encoding])
     * 说明:发送正文中的一块。用户可以通过多次调用这个方法将请求正文以流的方式发送到服务器。此种情况建议在建立请求时使用['Transfer-Encoding', 'chunked']请求头。
     * @param {Object or String} chunk 参数chunk应当是一个整数数组或字符串。
     * @param {String} encoding 参数encoding是可选的,仅在chunk为字符串时可用。
     */
    req.write('data\n');
    /**
     * 源API:request.end(chunk, [encoding])
     * 说明:完成本次请求的发送。如果正文中的任何一个部分没有来得及发送,将把他们全部刷新到流中。如果本次请求是分块的,这个函数将发出结束字符'0\r\n\r\n'。如果使用参数data,就等于在调用request.write(data, encoding)之后紧接着调用request.end()。
     * @param {Object or String} chunk 参数chunk应当是一个整数数组或字符串。
     * @param {String} encoding 参数encoding是可选的,仅在chunk为字符串时可用。
     * example: req.end(),req.end('data\n'),req.end('data','utf8'),req.end(chunk)
     */
    req.end();
    /**
     * 阻止一个请求。(v0.3.8中新增的方法。)
     */
    req.abort();
    /**
     * 源API:request.setTimeout(timeout, [callback])
     * 说明:一旦给这个请求分配的是一个socket时此函数会被调用
     * @param {Number} timeout 毫秒
     * @param {Function} callback 回到函数
     */
    req.setTimeout(1000,function(){});
    /**
     * 源API :request.setNoDelay([noDelay])
     * 说明:默认有一定的延迟,设置为0表示无延迟
     * @param {Number} noDelay
     */
    req.setNoDelay(0)
    /**
     * 源API:request.setSocketKeepAlive([enable], [initialDelay])
     *     类似同上
     */

     

     

    四、http.get

    http.get(options, callback) http 模块还提供了一个更加简便的方法用于处理GET请求:http.get。它是 http.request 的简化版,唯一的区别在于http.get自动将请求方法设为了 GET 请求,同时不需要手动调用 req.end()。

    /**
     * Created by Administrator on 14-4-30.
     */
    var http = require('http');
    http.createServer(function(req,res){
    }).listen(3000);
    /**
     * 说明:由于大部分请求是不包含正文的GET请求,Node提供了这个方便的方法。与http.request()唯一的区别是此方法将请求方式设置为GET,并且自动调用req.end()。
     * 应用:服务器端测试客服端请求调试等
     * @param {String} url 有效地址
     * @param {Function} callback
     */
    http.get('http://www.baidu.com/index.html',function(res){
        console.log('get response Code :' + res.statusCode);
    }).on('error',function(e){
            console.log("Got error: " + e.message);
        })

     

     http://my.oschina.net/antianlu/blog/228511

  • nodejs爬虫-cheerio

    nodejs采集

    php采集使用的是phpQuery参考《php采集

    nodejs采集的效率远远高于php推荐模块cheerio。使用方法跟jquery类似就像操作DOM一样。

    安装npm install cheerio

    cheerio 是一个为服务器特别定制的,快速、灵活、封装jQuery核心功能工具包。Cheerio包括了 jQuery核心的子集,从jQuery库中去除了所有DOM不一致性和浏览器不兼容的部分,揭示了它真正优雅的API。Cheerio工作在一个非常简 单,一致的DOM模型之上,解析、操作、渲染都变得难以置信的高效。基础的端到端的基准测试显示Cheerio大约比JSDOM快八倍(8x)。 Cheerio封装了@FB55兼容的htmlparser,几乎能够解析任何的 HTML 和 XML document。

     

    //以下是简单封装
    
    var request=require('request');
    var $ =require('cheerio');
    
    
    function view_data(strurl,fn){
      request(strurl, function (error, response, body) {
         if (!error && response.statusCode == 200) {
             (fn)(error, response, body);
         }
      });
    }
    
    
    
    view_data('https://sdeno.com',function(error, response, body){
       router.get('/',function(req,res){
           res.render('index',{
             title:$(body).find('#menu-item-44').text()
           });
        });
    });
    
    

     

     

     

    这是首选:

    var cheerio =require('cheerio'),
        $ = cheerio.load('<ul id="fruits">...</ul>');

    或者通过传递字符串作为内容来加载HTML:

    $ =require('cheerio');
    $('ul','<ul id="fruits">...</ul>');

    Or as the root:

    $ =require('cheerio');
    $('li','ul','<ul id="fruits">...</ul>');

    你也可以传递一个额外的对象给.load()如果你需要更改任何的默认解析选项的话:

    $ = cheerio.load('<ul id="fruits">...</ul>',{
        ignoreWhitespace:true,
        xmlMode:true});

    这些解析选项都是直接来自htmlparser ,因此任何在htmlparser里有效的选项在Chreeio里也是行得通的。默认的选项如下:

    {
        ignoreWhitespace:false,
        xmlMode:false,
        lowerCaseTags:false}

    想看选项清单和它们都效果,看 这个这个

    ####Selectors

    Cheerio的选择器用起来几乎和jQuery一样,所以API也很相似。

    $(selectior,[context],[root])

    选择器在 Context 范围内搜索,Context又在Root范围内搜索。selector 和context可是是一个字符串表达式,DOM元素,和DOM元素的数组,或者chreeio对象。root 是通常是HTML 文档字符串。

    $('.apple','#fruits').text()//=> Apple
    
    $('ul .pear').attr('class')//=> pear
    
    $('li[class=orange]').html()//=> <li class="orange">Orange</li>

    ####Attributes 获得和修改属性

    .attr(name,value)

    获得和修改属性。在匹配的元素中只能获得第一元素的属性。如果设置一个属性的值为null,则移除这个属性。你也可以传递一对键值,或者一个函数。

    $('ul').attr('id')//=> fruits
    
    $('.apple').attr('id','favorite').html()//=> <li class="apple" id="favorite">Apple</li>

    更多信息请看这里

    value([value])

    获得和修改input,select,textarea的value.注意: 对于传递键值和函数的支持还没有被加进去。

    $('input[type="text"]').val()=> input_text
    
    $('input[type="text"]').val('test').html()=><input type="text" value="test"/>

    .removeAttr(name)

    通过name删除属性

    $('.pear').removeAttr('class').html()//=> <li>Pear</li>

    .hasClass( className )

    检查匹配的元素是否有给出的类名

    $('.pear').hasClass('pear')//=> true
    
    $('apple').hasClass('fruit')//=> false
    
    $('li').hasClass('pear')//=> true

    .addClass(className)

    增加class(es)给所有匹配的elements.也可以传函数。

    $('.pear').addClass('fruit').html()//=> <li class="pear fruit">Pear</li>
    
    $('.apple').addClass('fruit red').html()//=> <li class="apple fruit red">Apple</li>

    更多信息看这里

    .removeClass([className])

    从选择的elements里去除一个或多个有空格分开的class。如果className 没有定义,所有的classes将会被去除,也可以传函数。

    $('.pear').removeClass('pear').html()//=> <li class="">Pear</li>
    
    $('.apple').addClass('red').removeClass().html()//=> <li class="">Apple</li>

    更多信息看这里

    .is.(selector)

    .is(function(index))

    有任何元素匹配selector就返回true。如果使用判定函数,判定函数在选中的元素中执行,所以this指向当前的元素。

    ####Traversing

    .find(selector)

    获得一个在匹配的元素中由选择器滤过的后代。

    $('#fruits').find('li').length
    //=> 3

    .parent([selector])

    获得每个匹配元素的parent,可选择性的通过selector筛选。

    $('.pear').parent().attr('id')//=> fruits

    .parents([selector])

    获得通过选择器筛选匹配的元素的parent集合。

    $('.orange').parents().length
    // => 2
    $('.orange').parents('#fruits').length
    // => 1

    .closest([selector])

    对于每个集合内的元素,通过测试这个元素和DOM层级关系上的祖先元素,获得第一个匹配的元素

    $('.orange').closest()// => []
    $('.orange').closest('.apple')// => []
    $('.orange').closest('li')// => [<li class="orange">Orange</li>]
    $('.orange').closest('#fruits')// => [<ul id="fruits"> ... </ul>]

    .next() 获得第一个本元素之后的同级元素

    $('.apple').next().hasClass('orange')//=> true

    .nextAll()

    获得本元素之后的所有同级元素

    $('.apple').nextAll()//=> [<li class="orange">Orange</li>, <li class="pear">Pear</li>]

    .prev()

    获得本元素之前的第一个同级元素

    $('.orange').prev().hasClass('apple')//=> true

    .preAll()

    $('.pear').prevAll()//=> [<li class="orange">Orange</li>, <li class="apple">Apple</li>]

    获得本元素前的所有同级元素

    .slice(start,[end])

    获得选定范围内的元素

    $('li').slice(1).eq(0).text()//=> 'Orange'
    
    $('li').slice(1,2).length
    //=> 1

    .siblings(selector)

    获得被选择的同级元素,除去自己??

    $('.pear').siblings().length
    //=> 2
    
    $('.pear').siblings('.orange').length
    //=> 1

    .children(selector)

    获被选择元素的子元素

    $('#fruits').children().length
    //=> 3
    
    $('#fruits').children('.pear').text()//=> Pear

    .each(function(index,element))

    迭代一个cheerio对象,为每个匹配元素执行一个函数。When the callback is fired, the function is fired in the context of the DOM element, so this refers to the current element, which is equivalent to the function parameter element.要提早跳出循环,返回false.

    var fruits =[];
    
    $('li').each(function(i, elem){
      fruits[i]= $(this).text();});
    
    fruits.join(', ');//=> Apple, Orange, Pear

    .map(function(index,element))

    迭代一个cheerio对象,为每个匹配元素执行一个函数。Map会返回一个迭代结果的数组。the function is fired in the context of the DOM element, so this refers to the current element, which is equivalent to the function parameter element

    $('li').map(function(i, el){// this === elreturn $(this).attr('class');}).join(', ');//=> apple, orange, pear

    .filter(selector)

    .filter(function(index))

    迭代一个cheerio对象,滤出匹配选择器或者是传进去的函数的元素。如果使用函数方法,这个函数在被选择的元素中执行,所以this指向的手势当前元素。

    Selector:

    $('li').filter('.orange').attr('class');//=> orange

    Function:

    $('li').filter(function(i, el){// this === elreturn $(this).attr('class')==='orange';}).attr('class')//=> orange

    .first()

    会选择chreeio对象的第一个元素

    $('#fruits').children().first().text()//=> Apple

    .last()

    $('#fruits').children().last().text()//=> Pear

    会选择chreeio对象的最后一个元素

    .eq(i)

    通过索引筛选匹配的元素。使用.eq(-i)就从最后一个元素向前数。

    $('li').eq(0).text()//=> Apple
    
    $('li').eq(-1).text()//=> Pear

    ###Manipulation

    改变DOM结构的方法

    .append(content,[content…])

    在每个元素最后插入一个子元素

    $('ul').append('<li class="plum">Plum</li>')
    $.html()//=>  <ul id="fruits">//      <li class="apple">Apple</li>//      <li class="orange">Orange</li>//      <li class="pear">Pear</li>//      <li class="plum">Plum</li>//    </ul>

    .prepend(content,[content,…])

    在每个元素最前插入一个子元素

    $('ul').prepend('<li class="plum">Plum</li>')
    $.html()//=>  <ul id="fruits">//      <li class="plum">Plum</li>//      <li class="apple">Apple</li>//      <li class="orange">Orange</li>//      <li class="pear">Pear</li>//    </ul>

    .after(content,[content,…])

    在每个匹配元素之后插入一个元素

    $('.apple').after('<li class="plum">Plum</li>')
    $.html()//=>  <ul id="fruits">//      <li class="apple">Apple</li>//      <li class="plum">Plum</li>//      <li class="orange">Orange</li>//      <li class="pear">Pear</li>//    </ul>

    .before(content,[content,…])

    在每个匹配的元素之前插入一个元素

    $('.apple').before('<li class="plum">Plum</li>')
    $.html()//=>  <ul id="fruits">//      <li class="plum">Plum</li>//      <li class="apple">Apple</li>//      <li class="orange">Orange</li>//      <li class="pear">Pear</li>//    </ul>

    .remove( [selector] )

    从DOM中去除匹配的元素和它们的子元素。选择器用来筛选要删除的元素。

    $('.pear').remove()
    $.html()//=>  <ul id="fruits">//      <li class="apple">Apple</li>//      <li class="orange">Orange</li>//    </ul>

    .replaceWith( content )

    替换匹配的的元素

    var plum = $('<li class="plum">Plum</li>')
    $('.pear').replaceWith(plum)
    $.html()//=> <ul id="fruits">//     <li class="apple">Apple</li>//     <li class="orange">Orange</li>//     <li class="plum">Plum</li>//   </ul>

    .empty()

    清空一个元素,移除所有的子元素

    $('ul').empty()
    $.html()//=>  <ul id="fruits"></ul>

    .html( [htmlString] )

    获得元素的HTML字符串。如果htmlString有内容的话,将会替代原来的HTML

    $('.orange').html()//=> Orange
    
    $('#fruits').html('<li class="mango">Mango</li>').html()//=> <li class="mango">Mango</li>

    .text( [textString] )

    获得元素的text内容,包括子元素。如果textString被指定的话,每个元素的text内容都会被替换。

    $('.orange').text()//=> Orange
    
    $('ul').text()//=>  Apple//    Orange//    Pear

    ###Rendering

    如果你想呈送document,你能使用html多效用函数。

    $.html()//=>  <ul id="fruits">//      <li class="apple">Apple</li>//      <li class="orange">Orange</li>//      <li class="pear">Pear</li>//    </ul>

    如果你想呈送outerHTML,你可以使用 $.html(selector)

    $.html('.pear')//=> <li class="pear">Pear</li>

    默认的,html会让一些标签保持开标签的状态.有时候你想呈现一个有效的XML文档.例如下面这个:

    $ = cheerio.load('<media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123"/>');

    然后为了呈现这个XML,你需要使用xml这个函数:

    $.xml()//=>  <media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123"/>

    ###Miscellaneous

    不属于其它地方的DOM 元素方法

    .toArray()

    取得所有的在DOM元素,转化为数组、

    $('li').toArray()//=> [ {...}, {...}, {...} ]

    .clone()

    克隆cheerio对象

    var moreFruit = $('#fruits').clone()

    ###Utilities

    $.root 有时候你想找到最上层的root元素,那么$.root()就能获得:

    $.root().append('<ul id="vegetables"></ul>').html();//=> <ul id="fruits">...</ul><ul id="vegetables"></ul>

    $.contains( container, contained )

    查看cotained元素是否是container元素的子元素

    $.parseHTML( data [, context ] [, keepScripts ] )

    将字符串解析为DOM节点数组。context参数对chreeio没有意义,但是用来维护APi的兼容性。

  • jQuery与MooTools库的一些比对

    我上大学那会儿从事的项目用的是jQuery,毕业后工作所从事的项目用的是MooTools。很幸运短期内有机会接触两款不同设计风格的优秀的JavaScript库。今天就我自己的一些认识比对下这两个JS框架,更多的是希望大家能够对MooTools这个JS框架有更多的认识。毕竟,大多数从事web前端的人对上手容易的jQuery更熟悉些。

    一、API设计

    就API的设计上来讲,无论是MooTools,或是其他类似YUI的JS框架都比jQuery略逊一筹。

    API是什么?根据某些著作的回答,API是对所需知识的抽象,它将系统的复杂性隐藏起来。例如汽车的方向盘,电视机上的按钮。一个API设计的好坏可以从下面几个方面评估:可理解性、一致性、预见性、简单性、保护性。

    可理解性

    例如selector(选择器)。随便举个选择器的例子(jQuery):
    $("#jQuery div")

    选择器的写法是与CSS的选择器是一脉相承的。因此对于很多写页面的人来讲,可以很轻松地使用jQuery找到自己想要的那根葱。jQuery后来的版本之所以把XPath干掉,或许就是因为理解性上的问题吧。当然,MooTools也是支持CSS选择器的,只不过,其不是使用一个美元符号$,而是两个$$,貌似是学习prototype框架,返回的是数组。

    $$("#MooTools div")

    如果MooTools只走到这一步,我觉得还好,貌似跟jQuery的可理解性打个小平手。只可惜,MooTools还有一个单个美元符号$的选择器,其中参数只能是元素的id,例如:

    $("MooTools")

    这玩意,选择的貌似是有个MooTools元素扩展方法的对象。如果不存在,应用元素方法的时候(eg: addClass)则会报错。

    也就是说MooTools选择元素,根据用法的不同,有时候返回的可能就是数组,有时候又是元素对象。这难免让对JS熟悉,对CSS较熟悉的人员有了理解和使用上的困难了。不过这不能怪MooTools,设计架构上的不同导致MooTools有时候需要返回元素对象,而不是元素对象数组。

    因此,从理解性上来说,MooTools逊于jQuery了。

    一致性

    JS框架的一致性的主要体现之一就是链式调用,例如(jQuery):
    $("#jQuery").css("color", "red").height(200);

    MooTools也是支持链式调用的,例如(MooTools):

    $$("#MooTools").setStyle("color", "red").setStyle("height", 200);

    在链式调用上,jQuery和MooTools基本上都是很OK的。

    但是,在其他方面的一致性上,MooTools似乎又落于下风了。jQuery这个框架真的很神奇,一个$符号就可以从广州走到北京,真可谓万能密匙啊。
    首先选择器,例如$("#jQuery")肯定是$符号,然后,其相关的其他些方法,例如插件机制之$.fn.extend(object),或者是Ajax请求$.ajax([options]),又或是浏览器检测,数组对象方法等等等等都是$符号横行的。

    但是,MooTools桑中$符号出现在选择器,让人难懂的$A$E,以及一些公共方法命名上,其余时候都回家睡觉觉了。
    继承需要new Class()构造,Ajax请求为new Request([options]),然后浏览器检测又是以Browser开头。数组,字符串等方法又都是当前对象本身打头,如myString.trim()。毫无一致性可言,显然,这个的学习成本和使用难度要比jQuery大多了。

    预见性

    好的API应该考虑到用户的无绪性选择(selective cluelessness)以及预见未来可能发生的一些事情。

    不知是John Resig(jQuery 之父)确实想的很远,还是因为幸运,或是只因为John是个天才,jQuery的设计让其似乎不会与未来发生冲突。
    举个老到啃不动的例子,过滤字符串的前后空格。jQuery的做法是:

    $.trim(myString);

    MooTools做法是:

    myString.trim();

    乍一看,似乎MooTools框架的做法更符合我们的理解 → 字符串对象有个trim方法,返回过滤前后空格的字符串方法。However,随着时间拖移,有些事情就开始发生变数了。

    在ECMAScript 5(ES5)中,字符串是内置trim方法的。我们可以做个小小的测试,如下代码:

    alert((" foo ").trim());

    您可以狠狠地点击这里:ES5 内置trim方法测试

    例如,在我的FireFox 6浏览器下,弹出的就是foo,如下截图:
    FireFox 6 弹出foo

    对于一些有历史价值的浏览器,就不支持,例如IE7模式下:

    同样类似的就是基于Function扩展的bind方法,MooTools中有,但是,ES5中也内置了。只是,比较幸运的是,无论是字符串trim方法,或是函数bind方法,虽然名称冲突了,但是,所实现的功能确是一样的,因此,也算不上冲突了。但是,万一哪天遇到个不幸,MooTools中的某个方法与ES5中的方法同名但不同功能,然后,只能老泪纵横了!

    再举个预见性的例子,选择器选择对象以及DOM对象。jQuery对jQuery对象和原生dom对象进行了分离,例如:

    $("input").bind("focus", function() {
        alert(this.value);	    // dom对象
        alert($(this).val());   // jQuery包装器对象
    });

    但是,在MooTools中,一些方法是在原生DOM上扩展的,MooTools元素对象和原生dom是合体的,例如:

    $$("input").addEvent("focus", function() {
        alert(this.value);           // dom对象
        alert(this.get("value"));    // 扩展后的dom对象
    });

    “合体”的问题在于随着浏览器以及一些规范的发展,原生dom可能会支持其他的一些方法,这些方法有可能就和MooTools插件中DOM扩展方法冲突。好在MooTools的方法命名属于对称命名,且语义明显,这种设计可以有效避免与原生dom方法的冲突。但是,事情没有这简单……下面你可以看到MooTools中DOM元素方法的设计的一些问题(当然,不可否认,这种设计使用上相对灵活些)。

    简单性

    jQuery之所以让开发者恋恋不舍,原因之一就是其简单。jQuery的口号就是”write less, do more.”

    拿dom-style的API举例,MooTools, YUI等框架采用的是传统对称命名的方式(prop为property属性缩写):

    el.setStyle(prop, val);  
    el.getStyle(prop);  
    el.setStyles({ propA: valA, propB: valB });  
    el.getStyles(propA, propB);	  // MooTools支持, 返回是个名-值对象

    在jQuery里,一个CSS就把所有瓷器活都揽了:

    el.css(prop);    // 表示 getStyle  
    el.css(prop, val);    // 表示 setStyle  
    el.css({ propA: valA, propB: valB });    // 表示 setStyles   
    el.css(prop, func);    // func 是一个返回 val 值的函数

    虽然参数类似,但是jQuery只要记一个名字,而MooTools却要N个,且名字也比较长(必须完整且长,否则易出问题)。这也是为什么jQuery更容易上手的原因。而且,jQuery更近一步,还支持func回调,且参数可以mapval可以是函数,暗藏多多surprise啊。

    显然,简单性这块又是jQuery好一些。
    这里,我还想说点其他相关的东西。jQuery框架的短命名设计确实好,于是我就想对MooTools的元素方法进行扩展,使等同于jQuery的命名书写方式,一是省些代码,二是方便熟悉jQuery的新员工上手,拿还是上面dom-style的例子,MooTools如下扩展处理:

    Element.implement({
        //将mootools默认的setStyle以及setStyles方法转化为与jQuery类似的css()形式
        css: function(key, value) {
            if ($type(key) == 'object') {
                for (var p in key) this.css(p, key[p]);
                return this;
            }
            if(!$chk(value)){
                return this.getStyle(key);
            }
            this.setStyle(key, value);
            return this;
        }
    });

    于是,MooTools也支持CSS方法,例如可以直接$("mootools").css({ border: "1px solid #ddd" });。恩,看上去不错,确实,上面的扩展在目前各个浏览器中是没有任何问题的。于是,初尝到了甜头,我们就想模拟其他jQuery包装器方法的扩展,例如width/height方法,如下(width举例):

    Element.implement({
        width: function (val) {
            if ($chk(val)) {
                return this.setStyle("width", val);
            } else {
                return this.getWidth();    
            }
        }
    });

    看上去不错,不是吗?但是,人生不如意事八九,上面MooTools框架对dom进行的width方法扩展是有问题的。我们都知道,<img>元素是有width属性的。正如上面提到的,MooTools框架的元素方法是在DOM上面直接“合体”扩展的。于是乎,对于图片而言,使用上面扩展的width方法是会嗝屁的——原生属性与扩展方法冲突。

    alert($("image").width()); //报错,显示$("image").width不是function

    由此又进一步证实了jQuery在API设计上更能避免一些当下或未来潜在的冲突,更具远见性。

    保护性

    jQuery有个多库共存机制,可以有效地保护其他框架都在争夺的$符号,有效避免了一些兼容性的问题。
    jQuery.noConflict();
    (function($) { 
      $(function() {
        // 使用 $ 作为 jQuery 别名的代码
      });
    })(jQuery);
    // 其他用 $ 作为别名的库的代码

    而MooTools中似乎并无这样的机制。

    总结:就API设计这点来讲,jQuery几乎从各个方面都强于MooTools,这也是jQuery大行其道的主要原因。

    二、性能

    选择器性能

    MooTools框架官方页面提供了选择器性能测试页面:speed/validity selectors test for frameworks

    点击右上角的”start tests”按钮,一段时间后就可以看到各个框架下各个选择器测试结果了。下表为我联系测试三次后的结果记录,可以看到,jQuery选择器的总体性能略比prototype低,比MooTools要强。但是,在我们实际些页面做交互的时候,其中选择器的差异基本上可以忽略不记(YUI在:nth-child选择器上的糟糕表现肯定要提防的)。

    MooTools 1.2 MooTools 1.3.1 JQuery 1.5.1 Prototype 1.7 YUI 2.8.2 Selector Dojo 1.5
    第一次测试总时间 75 67 37 34 685 49
    第二次测试总时间 66 56 28 26 668 48
    第三次测试总时间 67 55 30 30 663 43

    dom操作性能

    本来想从网上找一下MooTools和jQuery框架在dom操作这块的性能对比数据,结果发现,压根就没有,连个沾边的都没有。在这艰难困苦的时候,想起了伟大领袖毛主席的一句话:“自力更生,艰苦创业”。心中的小宇宙顿时爆发了,快刀乱麻,一番折腾后弄出了自己想要的测试页面。

    您可以狠狠地点击这里:MooTools与jQuery一些dom操作性能对比

    下面就是测试结果哈:

    attr MooTools 1.3.1 JQuery 1.5.1
    setStyle/css 79 ms | 1 found 53 ms | 1 found
    setStyles/cssMulti 200 ms | 1 found 109 ms | 1 found
    setProperty/attr 37 ms | 1 found 43 ms | 1 found
    setProperties/attrMulti 51 ms | 1 found 55 ms | 1 found
    addClass 40 ms | 1 found 18 ms | 1 found
    addClassMulti 54 ms | 1 found 25 ms | 1 found
    hasClass 75 ms | 1 found 24 ms | 1 found
    removeClass 118 ms | 1 found 23 ms | 1 found
    removeClassMulti 109 ms | 1 found 10 ms | 1 found
    最终结果(越小越好)  763  360

    可以看到,除了setProperty/attrsetProperties/attrMulti方法MooTools框架性能是略微占优外,其余一些dom相关操作都完败jQuery。

    小小总结:就性能这块。MooTools框架无论是选择器或是其他一些方法性能都逊于jQuery。

    三、MooTools的优势在于?

    根据上面两项的对比,MooTools框架在API方面没有jQuery优秀,一些DOM相关操作性能也没有jQuery好,那我们还有什么理由选择MooTools框架呢?MooTools框架的优势在什么地方呢?

    在讲述MooTools优势之前我想讲点题外话,有位MooTools团队成员曾说如如下让人值得思考的话:

    The MooTools team (of which I am a part) has never really focused on how popular the framework is. We are interested in writing it for our own use and for its own sake, but we don’t really spend much energy trying to convince other people to use it. We don’t consider ourselves adversaries to other frameworks – as I’ve heard it put on numerous recent occassions, we’re at war with the browsers, not each other. In my own posts on the topic, my suggestion to people is to try a couple of options and choose the framework that suits your needs and your styles. You really can’t make a bad choice (so please stop arguing about it!). jQuery, Prototype. YUI, Dojo, MooTools – we’re all doing the same things just using different methods.

    MooTools团队(我也是其中之一)从来没有真正关注过这个框架有 多受欢迎。我们只是对写这个框架感兴趣,为我们自己使用和它本身目的去写,但是我们真的没有花很多精力去让其他人去使用这个框架。我们从不认为其它框架是 我们的竞争对手——因为我曾经在很多场合都听说过这样的话,我们在和浏览器进行斗争,而不是相互斗争。在我的这篇文章中,我给你们的建议是:多尝试一些选择,然后选择适合你的需求和你的风格的框架。你真的不能做一个坏的选择(因此,请停止争吵!)。jQuery、Prototype、YUI、Dojo、 MooTools——我们都只是用不同的方法在做同样的事。

    当初我第一次听史仲冬说MooTools库的时候,心里有嘀咕:这玩意,基本上都没听过,也没有什么人使用,应该是个稀奇古怪,糟糕的框架吧。但是,当我逐渐了解这个JS框架后,越来越喜欢之,其喜欢程度已经超过jQuery,因为它比jQuery更适合当前我所做的项目——项目大,大数据量处理以及很多复杂交互。

    jQuery的因为其出色的API,使得即使不怎么懂JavaScript的人也能写出一些自以为靠谱的代码。再加上jQuery的重心放在了DOM上,这正好讨了热衷于页面效果交互的一些designer和csser的欢心。如果要构建中小型动态Web站点,用jQuery没错。快速、简单、优雅、漂亮。如果我是一个设计者,我也会使用它的。

    但是,如果是有着成百上千页面的大项目,有些大数据量交互与处理的项目,多人合作,多模块化的项目,jQuery往往就显得底气不足,往往需要各类插件补充。要知道,jQuery插件成百上千,但大多都是狗屎。如果没有牛人把控,项目最后也就变成了狗屎!

    MooTools虽然也能用在中小项目上,但是,其潜力的发挥要在大型、需要编写大量JavaScript的应用的网站项目上。这就是MooTools的优势。当然,我说话都是讲证据的,下面我就挑几点说说为何大型网站项目更适合MooTools而不是jQuery。

    更多的对象方法扩展
    虽然说,MooTools框架直接在Array, Function对象上做方法扩展有可能会造成语后来JavaScript规范出现重复或冲突的情况,但是,不可否认的是,这些对象方法的扩展对我们的开发节约了很多的功夫。

    例如字符串方法的扩展。在jQuery中,字符串相关操作的方法貌似就只有一个trim
    但是,在MooTools中,框架自带字符串扩展方法就有14个之多,例如字符串内容检测的contains方法,清除整个字符串中多余的空白字符串的clean方法,转义正则表达式敏感字符的escapeRegExp方法,或是取整toInt()以及rgb颜色和16进制颜色相关转化的字符串方法等等。在大数据量交互的时候,字符串相关处理是很多的,MooTools框架自带的这些字符串扩展方法不可不谓带来N多便捷。

    不仅仅是字符串,MooTools对数值,函数以及数组对象都进行了扩展。尤其数组,除了其原生的方法外,MooTools还对其扩展了近20个方法。这使得偶们在处理数组的时候基本上所向披靡了。总之,MooTools框架在各类JavaScript类型对象上做了新方法的扩展,以便我们可以更轻松更简单地应付各类复杂应用和众多数据处理。这显然与jQuery重在DOM的设计理念不同了。

    数据处理利器之Hash概念
    Hash,俗称哈希,是jQuery中没有而MooTools中有且很赞的一个玩意。Hash是一个重新实现的Object({}), 被专门用于数据的存取,和原来的Object({})的区别是: 它不会在进行存值,取值或迭代的时候处理对象的prototype中的内容。在MooTools中,Hash对象和Array对象(json基本构成啦)联合使用,不是我吹,再TM庞杂的数据,都能轻松应付。这让我想起了我们小秘书餐厅详细页的选菜交互,如果没有Hash这个玩意,我可真不知道该如何下手;或句话说,如果不是使用的MooTools作为框架,而是jQuery;这里的复杂的交互实现估计就是一场梦了。

    面向对象的设计思想
    MooTools是一款面向对象的设计思想框架。讲求继承,模块化与重用性。虽然说其new Class({})的构造有些让人不好理解,使用也颇有些既定规则,但是,实际上,这玩意要是能“挺过去”,还真的很有用的。举个关于半透明遮罩层的例子吧。我们构建一个名叫Overlay的类,然后其相关的代码就如下:

    var Overlay = new Class({
        Implements: [Options, Events],
        getOptions: function() {
            return {
                name:'',
                duration: 200,
                colour: '#000',
                opacity: 0.35,
                zIndex: 99,
                container: document.body,
                onClick: $empty
            };
        },
        initialize: function(options) {
            //......
            return this.position();
        },
        position: function() {
            //......
        },
        show: function() { 
            //......
        },
        hide: function(dispose) {
            //......
        },
        dispose: function() {
            //......
        }
    });

    于是,当我们需要半透明遮罩层的时候,直接:

    var myOverlay = new Overlay();

    Overlay类中的positionhideshow等方法都是外部可见的。我们可是使用类似:

    myOverlay.hide()

    让遮罩层隐藏。当然,我们可以再定义一个新的类,这个类继承或使用Overlay类,例如我们很常用的弹框效果咯,等等。虽然,MooTools这种强制面向对象风格的设计有些淡化了JavaScript语言本身的一些优美特性。但是,当项目庞大,JavaScript代码量巨大的时候,这种面向对象的设计理念还是相当受用的。项目越大,偶们所节省的代码量就越多。

    Cookie的读写
    MooTools框架自带Cookie读写的方法,支持指定域和路径。而jQuery框架中要想实现Cookie的读写,需要借助于专门的cookie插件,额外的插件,显然jQuery就折腾了。HTML5 localStorage本地存储实际应用这篇文章的IE浏览器Cookie的读写就是使用MooTools框架自带的Cookie方法。很简单,很好使用。

    swf文件的载人
    MooTools框架自带Swiff类,可以实现页面上flash文件的载入,而不需要求助google的swfobject方法。

    上面这个钟表flash的效果代码如下:

    var obj = new Swiff('http://www.zhangxinxu.com/study/flash/as3_clock_2.swf', {
        width: 300,
        height: 300,
        container: $("swfBox"),
        params: {
            wmode: 'opaque',
            bgcolor: '#eeeeee'
        }
    });

    更全面的动画效果
    MooTools框架的动画效果实际上要比jQuery的强些,但是,不足在于其使用的API要比jQuery逊色。
    说MooTools框架动画要比jQuery强,其中之一就是MooTools动画内置了贝塞尔运动曲线关键字。如:'linear''quad:in''back:in''bounce:out''elastic:out''sine:in:out'等等(下图为Fx.Transitions方法之expo),而jQuery实现类似缓动效果,还需要借助ease插件。

    form表单序列化提交
    MooTools自身携带HTML表单控件元素数据序列化方法,例如:

    $('myForm').toQueryString(); //返回 "email=bob@bob.com&zipCode=90210"

    表单元素自身携带了ajax提交方法,如下示例:

    $('loginForm').addEvent('submit', function(e){
        e.stop();  //不提交form
        $('loginForm').send({
         onComplete: function(result) {
             $('loginPopup').set('html', result); //显示结果
             (function(){
                 $('loginPopup').hide();
             }.delay(1000)); //一秒钟后隐藏
         }
        });
    });

    而jQuery框架要实现类似的功能,还需要专门的表单序列化插件。我靠,这东一个插件,西一个插件,而且插件质量良莠不齐,搞多了会死人的。

    四、最后的对比总结

    首先,毋庸置疑的是jQuery和MooTools都是非常优秀的轻量级的JavaScript框架。

    jQuery以其出色的API,出色的插件机制,以及在DOM方面的关注使其大受欢迎。然而,在面对大型项目的时候,其在一些功能特性上的缺失往往需要借助插件。如果团队没有有牛人把关的话,插件的滥用,人人都插一手的代码会把项目代码质量逐渐变成狗屎的。一般而言,jQuery更适合与动态的中小站点。

    MooTools插件虽然在API & DOM和上手容易程度上都上不及jQuery,但是,其API以及面向对象的设计思想似乎在实际的大项目中更有价值。

    因此,如果我要折腾我的个人网站,应该会使用jQuery。但是,如果是公司的大的网站项目,我会坚定不移选择MooTools,因为更适合。

    我JS水平尚浅,基本上都是些表象的对比,欢迎吐槽。

     

    http://www.zhangxinxu.com/wordpress/2011/09/jquery与mootools库的一些比对/