zoukankan      html  css  js  c++  java
  • QWrap简介之:NodeW Node包装

    专注于dom的jquery广受欢迎,说明了dom的节点操作在js应用中的沉重份量。
    节点操作需求多样,如果只局限于节点原型扩展,会阻碍重重束手束脚。针对节点的包装“NodeW”的出现,把节点的操作带到了一个没有边际的新天地。
    前文也提到,jquery的实质,就是一个nodelist的包装。

    我们先假设有一个针对Node的Helper:
    var NodeH = {
    setStyle:
    function(el, attribute, value) {
    el.style[attribute]
    = value;
    },
    getStyle:
    function(el, attribute) {
    return el.style[attribute];
    }
    };

    下文讲述NodeW的进化过程:从最简单形式进化成强大成熟易用的NodeW。

    第一阶段:最简形式-----只包装单个元素
    NodeW的最简形式:
    function NodeW(core) {
    this.core=core;
    }

    它有两个对应的原型方法:
    NodeW.prototype.setStyle = function(attribute, value) {
    NodeH.setStyle(
    this.core, attribute, value);
    };
    NodeW.prototype.getStyle
    = function(attribute) {
    return NodeH.getStyle(this.core, attribute);
    };


    那么我们就可以这样用了:
    var w = new NodeW(document.body);
    w.setStyle(
    'color', 'red');

    其效果相当于document.body.style.color='red';
    其中,“var w = new NodeW(document.body)”是一个装箱过程;“w.setStyle('color', 'red')”调用的是箱壳的原型方法,不过可以看到,其代码里操作的是“this.core”,即核。


    第二阶段:支持数组
    很多情况下,我们包装的是一个节点数组。这就得要求:除了要有能力对单个节点包装,还必须要对节点数组包装
    方案有三种:
    yui3方案:单个包装是Node,多个包装是NodeList,两个不同的类。
    jquery方案:jQuery对象反正是一个ArrayLike,包装单个与多个都是以数组的形式来。
    qwrap方案:都是NodeW,不过,它的core核有时是数组,有时是节点。
    对于数组来说,setStyle的意义很明显,是对每一个节点都setStyle;可是,getStyle,也是对每一个元素都getStyle吗?
    yui3的NodeList的做法,是每一个都getStyle,这样可能从理论上要严谨一些,可是,事实上绝大多数获取的结果,我们都希望是一个值,而不是值的数组。
    jquery的做法:getStyle,只对第一个元素进行getStyle,并且返回这个值。叫做“set allget one”策略。
    qwrap因为有了函数变换的概念,能够灵活配置,最后的效果是:“set allget oneget all
    简而言之,就是如下的情况:
    function NodeW(core) {
    this.core=core;
    }
    NodeW.prototype.setStyle
    = function(attribute, value) {
    var core=this.core;
    if(core instanceof Array){
    for(var i=0; i<core.length; i++){
    NodeH.setStyle(core[i], attribute, value);
    }
    }
    else NodeH.setStyle(this.core, attribute, value);
    };
    NodeW.prototype.getStyle
    = function(attribute) {
    var core=this.core;
    if(core instanceof Array){
    return NodeH.setStyle(core[0], attribute);
    }
    else return NodeH.getStyle(this.core, attribute);
    };
    NodeW.prototype.getStyleAll
    = function(attribute) {
    var core=this.core;
    if(core instanceof Array){
    var ret=[];
    for(var i=0; i<core.length; i++){
    ret.push(NodeH.getStyle(core[i], attribute);
    }
    return ret;
    }
    };

    会不会觉得代码太多?
    ----那是因为这里没用到函数变换的利器。
    上面的那段代码,可以改成这段:
    function NodeW(core) {
    this.core=core;
    }
    NodeW.prototype.setStyle
    = FunctionH.methodize(FunctionH.mul(NodeH.setStyle), 'core');
    NodeW.prototype.getStyle
    = FunctionH.methodize(FunctionH.mul(NodeH.getStyle,1), 'core');
    NodeW.prototype.getStyleAll
    = FunctionH.methodize(FunctionH.mul(NodeH.getStyle), 'core');

    也就是说,这些原型方法,都是那些静态方法的变种,只需要一些简单的变化就可以得到了。----这些变换在前面的FunctionH里已介绍过。

    第三阶段:支持selector
    在第二阶段的基础上,加上selector的支持就很简单了---只需引用一个Selector的类。
    只需改下NodeW的代码即可,如下:
    function NodeW(core) {
    if(typeof core == 'string') core=Selector.query(core);
    this.core=core;
    }

    例如:
    //<body><div></div><div></div></body>
    var w=new NodeW('div');
    w.setStyle(
    'width', '200px'); //每一个都设置width
    alert(w.getStyle('width')); //显示'200px';
    alert(w.getStyleAll('width')); //数组['200px','200px'];


    第四阶段:支持html
    在第三阶段的础上,希望参数可以是html字符串。例如<p>P1</p><p>P2</p>。
    好的,那也很简单,即:如果是html字符串的话,则自动创建相应的元素就可以了。
    因为selector与html都是字符串,所以,在不添加参数的情况下,需要区分它们。
    QWrap采用的区分方式是:第一个字符是'<'则当作html。对于第一个字符不是'<'还是想把它当html,不可以用这种用法。
    还是很简单,示意代码如下:
    function NodeW(core) {
    if (typeof core == 'string')) {
    if (/^</.test(core)) { //用法:html
    var list = Dom.create(core, true).childNodes,//创建碎片,并得到childNodes
    els = [];
    for (var i = 0, elI; elI = list[i]; i++) {
    els[i]
    = elI;
    }
    core
    =els;
    }
    else { //用法:selector;
    core=Selector.query(core);
    }
    }
    this.core=core;
    }

    之后,我们就可以这样用了:
    var w=new NodeW('<div></div>');
    w.setStyle(
    'width','200px');
    alert(w.getStyle(
    'width'));

    第五阶段:支持链式调用。
    有时候,需要连续几个设置,最后又获取,这种写法可能有点生硬。
    var w=new NodeW('<div></div>');
    w.setStyle(
    'width','200px');
    w.setStyle(
    'color','red');
    alert(w.getStyle(
    'width'));

    自jquery起,就吹起了一种链式调用的风潮:
    var w=new NodeW('<div></div>');
    alert(w.setStyle(
    'width','200px').setStyle('color','red').getStyle('width'));

    之前,静态函数NodeH.setStyle没有返回值,我们这里希望的NodeW.prototype.setStyle需要的是返回this。
    这就牵涉到一个返回值的定制。
    哦哟哟,有点麻烦了!
    不用担心,我们在HelperH里定制了几套看起来有点麻烦的变换。
    因为这个NodeH是个标准的Helper,满足“纯洁、静态、有针对性”三个特性,所以,我们可以直接借助HelperH,其代码就是:
    function NodeW(core) {
    if (typeof core == 'string')) {
    if (/^</.test(core)) { //用法:html
    var list = Dom.create(core, true).childNodes,//创建碎片,并得到childNodes
    els = [];
    for (var i = 0, elI; elI = list[i]; i++) {
    els[i]
    = elI;
    }
    core
    =els;
    }
    else { //用法:selector;
    core=Selector.query(core);
    }
    }
    this.core=core;
    }
    (
    function(){
    var config = {
    getStyle:
    'getter_first_all', //标明这个方法是get first;同时也生成一个getStyleAll的方法,作为get all。
    setStyle: 'operator' //标明这个方法是一个操作方法,操作方法都可以链式。
    };
    var helper = HelperH.mul(NodeH, config); //支持第一个参数为array
    var pro = HelperH.methodize(helper, 'core'); //方法化
    pro = HelperH.rwrap(pro, NodeW, config); //
    ObjectH.mix(NodeW.prototype, pro);
    }());

    好了,我们就可以链式调用了
    var w=new NodeW('div');
    alert(w.setStyle('width','200px').setStyle('color','red').getStyle('width'));
    当然,也可以这样写:
    alert(new NodeW('div').setStyle('width','200px').setStyle('color','red').getStyle('width'));

    第六阶段:去“new ”
    这写法:alert(new NodeW('div').setStyle('width','200px').setStyle('color','red').getStyle('width'));
    可能会有很多同学觉得不爽,为啥还要那个“new ”。
    好的,我们也可以去掉,将代码改成如下即可。
    function NodeW(core) {
    if(!(this instanceof NodeW)) return new NodeW(core);// 静态调用方式,转化成构造器调用方式。
    if (typeof core == 'string')) {
    if (/^</.test(core)) { //用法:html
    var list = Dom.create(core, true).childNodes,//创建碎片,并得到childNodes
    els = [];
    for (var i = 0, elI; elI = list[i]; i++) {
    els[i]
    = elI;
    }
    core
    =els;
    }
    else { //用法:selector;
    core=Selector.query(core);
    }
    }
    this.core=core;
    }


    第七阶段:NodeW就该是ArrayLike,希望用W('div')[0]得到第个div对象。
    第八阶段:数组相关操作,如W('div').first().setStyle('color','red');
    第N阶段:。。。。
    总之,后来NodeW现在进化到现在这个样子了:(以后可能还会进化)
    var NodeW = function(core) {
    if (!core) {//用法:var w=NodeW(null); 返回null
    return null;
    }
    var arg1 = arguments[1];
    if (isString(core)) {
    if (/^</.test(core)) { //用法:var w=NodeW(html);
    var list = create(core, true, arg1).childNodes,
    els
    = [];
    for (var i = 0, elI; elI = list[i]; i++) {
    els[i]
    = elI;
    }
    return new NodeW(els);
    }
    else { //用法:var w=NodeW(sSelector);
    return new NodeW(query(arg1, core));
    }
    }
    else {
    core
    = g(core, arg1);
    if (this instanceof NodeW) {
    this.core = core;
    if (isArray(core)) { //用法:var w=NodeW(elementsArray);
    this.length = 0;
    push.apply(
    this, core);
    }
    else { //用法:var w=new NodeW(element)//不推荐;
    this.length = 1;
    this[0] = core;
    }
    }
    else {//用法:var w=NodeW(element); var w2=NodeW(elementsArray);
    return new NodeW(core);
    }
    }
    };
    更多代码参见:http://dev.qwrap.com/resource/js/dom/node.w.js
    不过,这是他没配装备的样子。以后讲到retouch时,会再次细述如何用NodeH、EventTargetH、JssTargetH、ArrayH等来武装它,让他更健壮强大。
    NodeW的一个静态方法就是为以后的武装作准备的,它的介绍也先按下不提。

    附:QWrap地址:http://www.qwrap.com
  • 相关阅读:
    找零钱「Usaco2006 Dec」
    才艺表演「Usaco2018 Open」
    潜入行动「JSOI2018」
    任务安排「SDOI2012」
    BZOJ2298: [HAOI2011]problem a
    JZOJ 5818
    JZOJ 3493
    JZOJ 3470
    JZOJ 5781
    JZOJ 5778
  • 原文地址:https://www.cnblogs.com/jkisjk/p/qwrap_wrap_NodeW.html
Copyright © 2011-2022 走看看