JavaScript DOM高级程序设计1.2-循序最佳实践--我要坚持到底!

我这人,最大的毛病就是浮躁。

下面开始我再一次的学习之旅,希望我能坚持到最后。记笔记除了分享以外,更重要的是让自己看见自己学习之路。

先把ADS库贴出来http://vdisk.weibo.com/s/DaX18

把行为从结构中分离出来

全部脚本,都使用外部源文件,就当其他方式没有了解过。

昔日的javascript:前缀。(相对合理的写法。)

<script type="text/javascript">
        function popup(url) {
            window.open(url);
            //do not return anything!
        }
</script>
<a href="http://advanceddomscripting.com" onclick="popup(this.href); return false;">

但是可以通过在文档中包含popupLoadEvent.js这样的脚本文件来应用与嵌入式脚本相同的逻辑(ADS库,稍后创建。先有这种思想。)

//添加载入事件来修改页面
ADS.addEvent(window,'load',function(W3CEvent) {
    
    //查找文档中带popup类的所有锚的标签
    var popups = ADS.getElementsByClassName('popup', 'a');
    for(var i=0 ; i<popups.length ; i++ ) {
        //为每个锚添加单击事件侦听器
        ADS.addEvent(popups[i],'click',function(W3CEvent) {
            
            //使用href属性打开窗口
            window.open(this.href); 
            
            //取消默认事件
            ADS.eventPreventDefault(W3CEvent);
        });
    }
});

然后在class属性中加上popup类标记出相应的锚:<a href="http://advanceddomscripting.com" class="popup">

另外一个好处就是,通过相同的类名添加独特的样式

.popup {
    padding-right: 25px;
    background: transparent url(images/popup.png) no-repeat right center;
}View Code

不要版本检测

使用能力检测

使用版本检测的范例:

if(pitcher.screwball){
    pitcher.screwball.throw();      
}else if (pitcher.fastball){
    pitcher.fastball.throw();  
}else{
     alert('Sorry,you can't throw the ball.');   
}

使用能力检测,指的是在执行代码之前检测某个脚本对象或者方法是否存在,而不是依赖于你对哪个浏览器具有那些特性的了解:

if (pitcher.screwball)
{
    pitcher.screwball.throw();
}
else if (pitcher.fastball)
{
    pitcher.fastball.throw();
}
else
{
    alert("Sorry,you can't throw the ball.");
}

类是的,如果你代码里需要document.body,你就应该想下面这样进行检测

if(documen.body)
{
    //依赖document.body的代码
}

当然不是所有的函数和方法都要检测,你只要在脚本开始处对你打算使用的对象和方法进行检测:

var W3CDOM = document.createElement&&document.getElementsByTagName;
function exampleFunctionThatRequiresW3CMethods()
{
    if (!W3CDOM)
    {
        return;
    }
    //使用document.createElement()和document.getElementsByTagName()的代码
    
}

通过平稳退化保证可访问性

为重用命名空间而进行规划

保持唯一性

不共享

(function()
{
    function $(id)
    {
        return document.getElementById(id);
    }
    function alertNodeName(id)
    {
        alert($(id).nodeName);
    }
    window['myNamespace']={};
    window['myNamespace']['showNodeName']=alertNodeName;
}
)();

这样就可调用:myNaespace.showNodeName('example');

通过可重用的对象把事情简化(本书是通过创建ADS库贯穿的)

(function()
{
    //ADS命名空间
    if (!window.ADS)
    {
        window['ADS']={};
    }
}
//确定当前类库是否与整个浏览器兼容
function isCompatible(other)
{
    //使用能力检测来检查必要条件
    if (other==false
        ||!Array.prototype.push
        ||!Object.hasOwnProperty
        ||!document.createElement
        ||!document.getElementsByTagName)
    {
        return false;
    }
    return true;
}
window['ADS']['isCompatible']=isCompatible;

/*
if(ADS.isCompatible())
{
    //使用ADS库的代码
}
*/

function $()
{
    var elements=new Array();
    //查找作为参数提供的所有元素
    for (var i  = 0;i<arguments.length ;i++ )
    {
        var element=arguments[i];
        //如果该参数是一个字符串那假设他是一个id
        if(typeof element="string")
        {
            element=document.getElementById(element);
        }
        //如果只提供一个参数,则立即返回这个元素
        if (arguments.length==1)
        {
            return element;
        }
        //否则将他添加到数组中
        elements.push(element);
    }
    //返回包含多个被请求的数组
    return elements;
};
window['ADS']['$']=$;

/*
var element=ADS.$('example');
*/
/*
var elements = ADS.$('a','b','c','d')
for(e in elements)
{
    //执行某些操作
}
*/

function addEvent(node,type,listener)
{
    //使用前方法检查兼容性以保证平稳退化
    if (!isCompatible())
    {
        return false;
    }
    if (!(node=$(node)))
    {
        return false;
    }
    if (node.addEventListener)
    {
        //W3C的方法
        node.addEventListener(type,listener,false);
        return true;
    }
    else if (node.attachEvent)
    {
        //MSIE的方法
        node['e'+type+listener]=listener;
        node[type+lisener]= function()
        {
            node['e'+type+listener](window.event);
        }
        node.attachEvent('on'+type,node[type+listener]);
        return true;
    }
    //若两种方法都不具备则返回false;
    return false;
};
window['ADS']['addEvent']=addEvent;

/*实例
ADS.addEvent(window,'load',function(W3CEvent))
{
    //查找文档中所有带popup类的锚标签
    var popup=ADS.getElementsByClassName('popup','a');
    for(var i= 0;i<popups.length;i++)
    {
        //给每个锚添加一个事件侦听器
        ADS.addEvent(popup[i],'click',function(W3CEvent))
        {
            //使用href属性打开窗口
            window.open(this.href);
            //取消默认事件
            ADS.eventPreventDefault(W3CEvent);
        });
    }
});
//甚至可以添加多个事件
function sayHello(){alert('Hello');
}
ADS.addEvent(window,'load',sayHello);//注意 ,不包含on

function sayGoodBye()
{
    alert('GoodBye!');
}
ADS.addEvent(window,'load',sayGoodBye)
*/
function removeEvent(node,type,listener)
{
    if (!(node=$(node)))
    {
        return false;
    }
    if (node.removeEventListener)
    {
        //W3C的方法
        node.removeEventListener(type,listener,false);
        return true;
    }
    else if (node.detachEvent)
    {
        //MSIE的方法
        node.detachEvent('on'+type,node[type+listener]);
        node[type+listener]=null;
        return true;
    }
    //若两种方法都不具备则返回false;
    return false;
};
window['ADS']['removeEvent']=removeEvent;

function getElementByClassName(className,tag,parent)
{
    parent=parent||document;
    if (!(parent=$(parent)))
    {
        return false;
    }
    //查找所有匹配的标签
    var allTags=(tag=="*"&&parent.all)?parent.all:parent.getElementsByTagName(tag);
    var matchingElements=new Array();

    //创建一个正则表达式。来判断className是否正确。
    className=className.replace(/\-/g,"\\-");
    var regex=new RegExp("(^|\\s)"+className+"(\\s|$)");

    var element;
    //检查每个元素
    for (var i=0; i<allTags.length;i++ )
    {
        elemetn=allTags[i];
        if (regex.test(element.className))
        {
            matchingElements.push(element);
        }
    }
    //返回任何匹配的元素
    return matchingElements;
};
window['ADS']['getElementByClassName']=getElementByClassName;
/*范例
...
<p class="findme"> This is just an <em calss="findme">example</em><p>
<div >
    <h2 class="findme">A list
    </h2>
    <ol>
        <li class="findme">foo
        </li>
        <li class="findme">bar
        </li>
    <ol>
</div>
*/
//切换显示
function toggleDisplay(node,value)
{
    if (!(node=$(node)))
    {
        return false;
    }
    if (node.style.display!='none')
    {
        node.style.display='none';
    }
    else{
        node.style.display=value||'';
    }
    return true;
};
window['ADS']['toggleDisplay']=toggleDisplay;
/*实例
ADS.toggleDisplay(ADS.$('example'));
*/

function insertAfter(node,refereceNode)
{
    if (!(node=$(node)))
    {
        return false;
    }
    if(!(referenceNode=$(referenceNode))) return false;
    return referenceNode.parentNode.insertBefore(
        node,referenceNode.nextSibling    
    );
};
/*实例
ADS.insertAfter(ADS.$('example'),domNode);
比下面的容易多:
ADS.$('example').parentNode.insertBefore(ADS.$('example'),domNode);
*/
window['ADS']['insertAfter']=insertAfter;

function removeChildren(parent)
{
    if (!(parent=$(parent)))
    {
        return false;
    }
    //当存在子节点是删除该子节点
    while(parent.firstChild)
    {
        parent.firstChild.parentNode.removeChild(parent.firstChild)
    }
    return parent;
};
window['ADS']['removeChildren']=removeChildren;

//prepend追加在前
function prependChild(parent,newChild)
{
    if (!(parent=$(parent)))
    {
        return false;
    }
    if (parent.firstChild)
    {
        //如果存在一个子节点,则在这个子节点之前插入
        parent.insertBefore(newChild.parent.firstChild);
    }
    else{
        parent.appendChild(newChild);

    }
    return parent;
};
window['ADS']['prependChild']=prependChild;
)();

一定要自己动手写代码