代码改变世界

淘宝Kissy框架分析【七】

2010-06-20 18:39  BlueDream  阅读(1917)  评论(0编辑  收藏  举报

今天开始就正式进入了DOM文件夹部分. DOMAPI算是比较难搞的部分.KISSY也在不断完善中.所以现在实现的不是很全面.这篇我们主要看下

dom.js和dom-class.js

dom.js只定义了个命名空间.代码还没有具体实现

J1616.add('dom'function(J) {
    J.DOM = {
        _isElementNode: function(elem) {
            
return elem && elem.nodeType === 1;
        }
    };
});

 

但由于DOM方法都是扩展在J.DOM命名空间下.所以这个文件是必须的.

dom-class.js是对元素的class进行了控制.

【程序源码】

J1616.add('dom-class'function(J, undefined) {
    
var SPACE = ' ',
        DOM = J.DOM,
        REG_SPLIT = /[\.\s]\s*\.?/,
        REG_CLASS = /[\n\t]/g;

    J.mix(DOM, {
        
// selector是否存在指定的class
        hasClass: function(selector, value) {
            
return batch(selector, value, function(elem, classNames, cl) {
                
var elemClass = elem.className;
                
if (elemClass) {
                    
var className = SPACE + elemClass + SPACE, j = 0, ret = true;
                    
for (; j < cl; ++j) {
                        
if (className.indexOf(SPACE + classNames[j] + SPACE) < 0) {
                            ret = false;
                            
break;
                        } 
                    }
                    
if (ret) return true
                } 
            }, true);
        },
        
// 为selector 添加class
        addClass: function(selector, value) {
            batch(selector, value, function(elem, classNames, cl) {
                
var elemClass = elem.className;
                
if (!elemClass) {
                    elem.className = value;
                } 
                
else {
                    
var className = SPACE + elemClass + SPACE, setClass = elemClass, j = 0;
                    
for (; j < cl; ++j) {
                        
if (className.indexOf(SPACE + classNames[j] + SPACE) < 0) {
                            setClass += SPACE + classNames[j];
                        }
                    }
                    elem.className = J.trim(setClass);
                }
            });
        },
        
// 为指定的selector删除class
        removeClass: function(selector, value) {
            batch(selector, value, function(elem, classNames, cl) {
                
var elemClass = elem.className;
                
if (elemClass) {
                    
if (!cl) {
                        elem.className = '';
                    } 
                    
else {
                        
var className = (SPACE + elemClass + SPACE).replace(REG_CLASS, SPACE), j = 0;
                        
for (; j < cl; j++) {
                            className = className.replace(SPACE + classNames[j] + SPACE, SPACE);
                        }
                        elem.className = J.trim(className);
                    }
                } 
            });
        },
        
// 用新class替换旧的class
        replaceClass: function(selector, oldClassName, newClassName) {
            DOM.removeClass(selector, oldClassName);
            DOM.addClass(selector, newClassName);
        },
        
// 切换指定的class. state是强制删除或者添加
        toggleClass: function(selector, value, state) {
            
var isBool = J.isBoolean(state), has;

            batch(selector, value, function(elem, classNames, cl) {
                
var j = 0, className;
                
for (; j < cl; ++j) {
                    className = classNames[j];
                    has = isBool ? !state : DOM.hasClass(elem, className);
                    DOM[has ? 'removeClass' : 'addClass'](elem, className);
                }
            });
        }
    });

    
function batch(selector, value, fn, resultIsBool) {
        
if (!(value = J.trim(value))) return resultIsBool ? false : undefined;
        
        
var elems = J.query(selector),
            i = 0, len = elems.length,
            classNames = value.split(REG_SPLIT),
            elem, ret;
        
for (; i < len; ++i) {
            elem = elems[i];
            
if (elem.nodeType === 1) {
                ret = fn(elem, classNames, classNames.length);
                
if (ret !== undefined) return ret; 
            } 
        }
        
if (resultIsBool) return false
    }
});

1. batch方法

这个方法是批量元素处理的核心方法.总共4个参数:

1) selector[选择器] 这个会通过J.query通过选择器选择出所有符合条件的元素. J.query会在下节讲解.

2) value要进行操作的样式名称.支持(acls bclas) (acls.bcls) (acls    .bcls)等宽松模式.

3) fn 回调函数 选择器选出的NodeList  value传入的classNames, classNames的长度会循环并作为参数传入回调函数.

4) resultIsBool 如果为true那么返回值为true或false, 否则为undefined.

 

2.addClass方法.

作用: 为selector筛选出的元素都追加value指定的class 

我们下面测试的所有HTML都需要引入这些文件

<style type="text/css">
.red {color:red}
.blue {background-color: blue}
</style>
<script src="../j1616/j1616.js"></script>
<script src="../j1616/j1616-ua.js"></script>
<script src="../j1616/j1616-lang.js"></script>
<script src="dom.js"></script>
<script src="dom-class.js"></script>
<script src="selector.js"></script>
</head>
<body>
<div id="odiv">div</div>
<div id="odiv2">div2</div>

测试用例

J.DOM.addClass('#odiv2, #odiv''red blue');

这样我们就为id为odiv2, odiv的元素都追加了red和blue的class ==> 字体变红,背景色变蓝.  

3.hasClass方法

作用:判断选择器筛选出的元素是否含有value指定的class. 只要有一个元素符合那么就为true. 如果所有的元素都不匹配value那么就为false.

测试用例

J.DOM.addClass('#odiv2''red blue'); // 事先为odiv2 添加red和blue样式
J.log(J.DOM.hasClass('#odiv, #odiv2''red blue')); // 只有odiv2符合 那么就返回true

 

4.removeClass方法

作用:为选择器筛选的元素删除value给定的class.

测试用例

J.DOM.addClass('#odiv2''red blue'); // 事先为odiv2 添加red和blue样式
J.log(J.DOM.hasClass('#odiv, #odiv2''red blue')); // 只有odiv2符合 那么就返回true
J.DOM.removeClass('#odiv2''blue'); // 删除了blue样式
J.log(J.DOM.hasClass('#odiv, #odiv2''red blue')); // 此时blue样式已被删除 所以返回false

 

5.replaceClass方法

作用:用一个新的class替换一个class

测试用例

J.DOM.addClass('#odiv2''red blue'); // 事先为odiv2 添加red和blue样式
J.log(J.DOM.hasClass('#odiv, #odiv2''red blue')); // 只有odiv2符合 那么就返回true
J.DOM.removeClass('#odiv2''blue'); // 删除了blue样式
J.log(J.DOM.hasClass('#odiv, #odiv2''red blue')); // 此时blue样式已被删除 所以返回false
J.DOM.replaceClass('#odiv2''red''blue'); // div元素的背景色变蓝 因为用blue替换了red

 

6.toggleClass方法

作用:切换一个指定的class. 如果第一次样式存在 那么就删除 第二次就又追加上 以此类推.

测试用例:

J.DOM.addClass('#odiv2''red blue'); // 事先为odiv2 添加red和blue样式
J.log(J.DOM.hasClass('#odiv, #odiv2''red blue')); // 只有odiv2符合 那么就返回true
J.DOM.removeClass('#odiv2''blue'); // 删除了blue样式
J.log(J.DOM.hasClass('#odiv, #odiv2''red blue')); // 此时blue样式已被删除 所以返回false
J.DOM.replaceClass('#odiv2''red''blue'); // div元素的背景色变蓝 因为用blue替换了red
J.DOM.toggleClass('#odiv2''blue'); // 刚才blue样式存在,那么这次就将其移除
J.DOM.toggleClass('#odiv2''blue'); // 刚才blue样式被移除了.那么这次就添加上

 

这个方法还支持第三个参数state.这个参数可以强制指定是删除还是添加样式.如果true添加,如果false删除 

J.DOM.toggleClass('#odiv2''blue'false); // 这样就强制要删除blue样式

 

【总结】

整个实现没有什么难度.流程就是. 通过batch去获得selector的所有元素.和所有的样式classNames.然后循环所有元素,依次将元素和所有样式数组传入回调方法中去执行addClass.removeClass等一系列处理后.然后返回. batch再返回这些返回值就可以了.

 

下节我们将要讲解选择器selector.js