百度前端技術(shù)學(xué)院(IFE)2015春task練習(xí)記錄02

所有代碼可以在我的Github中找到,記錄從task002開(kāi)始移剪。

DOM操作

要求

// 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Query
function $(selector) {
    
}
// 可以通過(guò)id獲取DOM對(duì)象,通過(guò)#標(biāo)示,例如
$("#adom"); // 返回id為adom的DOM對(duì)象

// 可以通過(guò)tagName獲取DOM對(duì)象忿危,例如
$("a"); // 返回第一個(gè)<a>對(duì)象

// 可以通過(guò)樣式名稱(chēng)獲取DOM對(duì)象,例如
$(".classa"); // 返回第一個(gè)樣式定義包含classa的對(duì)象

// 可以通過(guò)attribute匹配獲取DOM對(duì)象毒嫡,例如
$("[data-log]"); // 返回第一個(gè)包含屬性data-log的對(duì)象

$("[data-time=2015]"); // 返回第一個(gè)包含屬性data-time且值為2015的對(duì)象

// 可以通過(guò)簡(jiǎn)單的組合提高查詢(xún)便利性癌蚁,例如
$("#adom .classa"); // 返回id為adom的DOM所包含的所有子節(jié)點(diǎn)中幻梯,第一個(gè)樣式定義包含classa的對(duì)象

思路

這一題花費(fèi)的時(shí)間比較久。

  1. 第一種思路是直接在$()中判斷是否有空格努释,然后再分情況查詢(xún)碘梢。單獨(dú)查詢(xún)的話(huà)比較好實(shí)現(xiàn),但在組合查詢(xún)中遇到了麻煩伐蒂。直接寫(xiě)的話(huà)比較麻煩幾乎是把幾種情況都再寫(xiě)了一遍煞躬;使用遞歸的話(huà)因?yàn)榉祷氐闹挡皇菙?shù)組,效果并不理想逸邦。于是放棄恩沛。

  2. 第二種思路是不再判斷是否包含空格,而是直接使用split(" ")分成數(shù)組缕减,使用for循環(huán)挨個(gè)查詢(xún)雷客。但在組合查詢(xún)這一情況時(shí)想不到好的解決辦法,還是放棄了桥狡。

最后搜索了一下別人的答案搅裙,綜合了一下各種思路,個(gè)人感覺(jué)這種最好理解實(shí)現(xiàn)起來(lái)也比較方便:
首先實(shí)現(xiàn)domQuery函數(shù)裹芝,這個(gè)函數(shù)直接返回查詢(xún)到的結(jié)果部逮,而不是數(shù)組中的第一個(gè)對(duì)象,然后再$()中再查詢(xún)到第一個(gè)對(duì)象嫂易。
domQuery(selector,root)中有兩個(gè)參數(shù)兄朋,其中root就是考慮到組合查詢(xún)的情況,在傳入的selector有兩個(gè)的情況下怜械,第一個(gè)selector查詢(xún)到的元素作為第二個(gè)子selector的root來(lái)進(jìn)行查詢(xún)颅和。

實(shí)現(xiàn)

  1. domQuery函數(shù)
function domQuery(selector, root) {
    var text;
    var elements = [];
    //if root is not defined, root = document
    if (!root) {
        root = document;
    }
    if (selector.charAt(0) === "#") {
        text = selector.replace(/^\#/, "");
        elements = document.getElementById(text);
    } else if (selector.charAt(0) === ".") {
        text = selector.replace(/^\./, "");
        elements = root.getElementsByClassName(text);
    } else if ((selector.charAt(0) === "[") && (selector.charAt(selector.length - 1) === "]")) {
        //get all the elements
        var eles = root.getElementsByTagName("*");
        //delete "[" and "]"
        selector = selector.replace(/^\[/, "");
        selector = selector.replace(/\]$/, "");

        var texts = selector.split("=");
        var attr = texts[0];
        var value = texts[1];
        //有屬性值的情況
        if (texts[1]) {
            for (var i = 0, length1 = eles.length; i < length1; i++) {
                if (eles[i].hasAttribute(attr)) {
                    if (eles[i].getAttribute(attr) === value) {
                        elements = eles[i];
                    }
                }
            }
        }
        //沒(méi)有屬性值
        else {
            for (var i = 0, length1 = eles.length; i < length1; i++) {
                if (eles[i].hasAttribute(attr)) {
                    elements = eles[i];
                }
            }
        }
    } else {
        elements = root.getElementsByTagName(selector);
    }
    return elements;
}

2.$() 函數(shù)

function $(selector) {
    //multiple queries
    var result = [];
    if (selector.indexOf(" ") !== -1) {
        //split selector by space
        var selectors = selector.split(" ");
        parents = domQuery(selectors[0]);
        for (var i = 1, length1 = selectors.length; i < length1; i++) {
            if (parents.length) {
                parents = domQuery(selectors[i], parents[0]);
            } else {
                parents = domQuery(selectors[i], parents);
            }
        }
        result = parents;
    }
    //single query
    else {
        var result = domQuery(selector, document);

    }
    if (result.length) {
        return result[0];
    } else {
        return result;
    }
}

補(bǔ)充

代碼邏輯

重點(diǎn)說(shuō)明一下$()中的組合查詢(xún)的邏輯

    if (selector.indexOf(" ") !== -1) {
        //split selector by space
        var selectors = selector.split(" ");
        parents = domQuery(selectors[0]);
        for (var i = 1, length1 = selectors.length; i < length1; i++) {
            if (parents.length) {
                parents = domQuery(selectors[i], parents[0]);
            } else {
                parents = domQuery(selectors[i], parents);
            }
        }
        result = parents;
    }
  1. parents = domQuery(selectors[0])獲得最開(kāi)始的root根節(jié)點(diǎn),然后開(kāi)始for循環(huán)宫盔,每一次循環(huán)domQuery得到的值都作為下一次循環(huán)的根節(jié)點(diǎn)融虽,從而達(dá)到組合查詢(xún)的目的;
  2. 這里有個(gè)問(wèn)題是getElementByIdgetElementsByClassName灼芭、getElementsByTagName等方法不同在于getElementById返回單個(gè)元素有额,其他方法返回的則是數(shù)組,這就造成了處理上的困難彼绷;
  3. if (parents.length)就用于判斷當(dāng)前得到的結(jié)果是否為數(shù)組巍佑,如果是,則只取數(shù)組的第一個(gè)元素寄悯;
  4. 但這樣的查詢(xún)其實(shí)是不全面的萤衰,只能查詢(xún)到返回?cái)?shù)組的第一個(gè)中是否包含所查詢(xún)?cè)兀绻堑诙€(gè)或者第三個(gè)包含猜旬,那么是查詢(xún)不到的脆栋。
  5. 現(xiàn)在所能做到的倦卖,要么查詢(xún)傳進(jìn)來(lái)的參數(shù)只有2個(gè);若要查詢(xún)多個(gè)椿争,則像上面所說(shuō)的那樣無(wú)法查詢(xún)除第一個(gè)以外的元素是否包含怕膛。

如何改進(jìn)還在摸索中

補(bǔ)充發(fā)現(xiàn)

如果組合中第二個(gè)selector為id,即類(lèi)似$(".a #b")這種情況是不行的秦踪。會(huì)報(bào)root.getElementById is not a function錯(cuò)誤褐捻。
在Chrome控制臺(tái)也實(shí)驗(yàn)了一下,getElementById方法只能用于document椅邓。

猜測(cè)了一下柠逞,大概是因?yàn)閕d是唯一的,并不需要多一個(gè)子集去篩選景馁?

DOM事件

要求

  1. ?
// 給一個(gè)element綁定一個(gè)針對(duì)event事件的響應(yīng)
//響應(yīng)函數(shù)為listener
function addEvent(element, event, listener) {
    // your implement
}

// 移除element對(duì)象對(duì)于event事件發(fā)生時(shí)執(zhí)行l(wèi)istener的響應(yīng)
function removeEvent(element, event, listener) {
    // your implement
}

// 實(shí)現(xiàn)對(duì)click事件的綁定
function addClickEvent(element, listener) {
    // your implement
}

// 實(shí)現(xiàn)對(duì)于按Enter鍵時(shí)的事件綁定
function addEnterEvent(element, listener) {
    // your implement
}
  1. ?
// 事件代理
function delegateEvent(element, tag, eventName, listener) {
    // your implement
}

$.delegate = delegateEvent;

// 使用示例
// 還是上面那段HTML板壮,實(shí)現(xiàn)對(duì)list這個(gè)ul里面所有l(wèi)i的click事件進(jìn)行響應(yīng)
$.delegate($("#list"), "li", "click", clickHandle);
  1. ?
//函數(shù)封裝
$.on(selector, event, listener) {
    // your implement
}

$.click(selector, listener) {
    // your implement
}

$.un(selector, event, listener) {
    // your implement
}

$.delegate(selector, tag, event, listener) {
    // your implement
}

// 使用示例:
$.click("[data-log]", logListener);
$.delegate('#list', "li", "click", liClicker);

思路

  1. 一開(kāi)始其實(shí)沒(méi)太懂這個(gè)要求,嘗試寫(xiě)了一下也不盡人意合住,于是搜索了一下其他人的方法个束,才發(fā)現(xiàn)其實(shí)是很簡(jiǎn)單的一個(gè)問(wèn)題自己想復(fù)雜了,直接使用js中提供的addEventListener方法就可以實(shí)現(xiàn)聊疲,接下來(lái)的幾個(gè)方法同理
  2. 弄懂了事件代理的原理后就很簡(jiǎn)單,將事件綁定到元素上一級(jí)的element中沪悲,在點(diǎn)擊時(shí)判斷是否節(jié)點(diǎn)名nodeName等于tag获洲,是的話(huà)就執(zhí)行l(wèi)istener函數(shù)。
  3. 封裝沒(méi)什么好說(shuō)的殿如,不過(guò)element換成了selector贡珊,那么利用之前實(shí)現(xiàn)的$()把element變成$(selector)就沒(méi)問(wèn)題了。

實(shí)現(xiàn)

  1. ?
// 給一個(gè)element綁定一個(gè)針對(duì)event事件的響應(yīng)涉馁,響應(yīng)函數(shù)為listener
function addEvent(element, event, listener) {
    if (element.addEventListener) {
        element.addEventListener(event, listener, false)
    }
}

// 移除element對(duì)象對(duì)于event事件發(fā)生時(shí)執(zhí)行l(wèi)istener的響應(yīng)
function removeEvent(element, event, listener) {
    if (element.removeEventListener) { //標(biāo)準(zhǔn)
        element.removeEventListener(event, listener, false);
    }
}
// 實(shí)現(xiàn)對(duì)click事件的綁定
function addClickEvent(element, listener) {
    addEvent(element, 'click', listener);
}

// 實(shí)現(xiàn)對(duì)于按Enter鍵時(shí)的事件綁定
function addEnterEvent(element, listener) {
    addEvent(element, "keydown", function(e) {
        if (e.keyCode === 13) {
            listener();
        }
    });
}
  1. ?
function delegateEvent(element, tag, eventName, listener) {
    $.eventName(element, function(e) {
        var e = e || window.event;    
        var target = e.target || e.srcElement;    
        if (target.nodeName.toLowerCase() === tag) {
            //?????
            listener.call(target, e);    
        }
    });
}
  1. ?
//函數(shù)封裝
$.on = function(selector, event, listener) {
    return addEvent($(selector), event, listener);
};

$.un = function(selector, event, listener) {
    return removeEvent($(selector), event, listener);
};

$.click = function(selector, listener) {
    return addClickEvent($(selector), listener);
};

$.enter = function(selector, listener) {
    return addEnterEvent($(selector), listener);
};

$.delegate = function(selector, tag, event, listener) {
    return delegateEvent($(selector), tag, eventName, listener);
};

補(bǔ)充

暫無(wú)

BOM

要求

// 判斷是否為IE瀏覽器门岔,返回-1或者版本號(hào)
function isIE() {
    // your implement
}

// 設(shè)置cookie
function setCookie(cookieName, cookieValue, expiredays) {
    // your implement
}

// 獲取cookie值
function getCookie(cookieName) {
    // your implement
}

思路

  1. 本來(lái)想用navigator判斷瀏覽器是否為IE的,但是看到說(shuō)navigator的信息有誤導(dǎo)性烤送,然后搜了一下發(fā)現(xiàn)還有用ActiveXObject檢測(cè)的寒随。MSDN里面這么描述的:
    此對(duì)象為 Microsoft 擴(kuò)展,僅在 Internet Explorer 中受支持帮坚,在 Windows 8.x 應(yīng)用商店應(yīng)用中不受支持妻往。
    那么只要檢測(cè)是否存在ActiveXObject對(duì)象就可以知道是否為IE瀏覽器。
    接著是檢查版本试和,在自己電腦上試了一下讯泣,IE版本是11,userAgent信息:
    "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; rv:11.0) like Gecko"
    而IE10(不包括)之前的IE的userAgent信息格式:
    Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0)
    分兩種情況阅悍,一個(gè)正則式就可以搞定好渠。

  2. 設(shè)置cookie和獲取cookie在W3C里直接就給了方法了昨稼,也沒(méi)啥難理解的點(diǎn),就了解一下cookie了拳锚。

實(shí)現(xiàn)

  1. ?
function isIE() {
    if (!!window.ActiveXObject || "ActiveXObject" in window) {
        var version = getIEVersion();
        return version;
    } else {
        return -1;
    }
}

function getIEVersion () {
    var reg = /(Trident.*rv\:|MSIE\s)((\d+)\.0)/;
    var uaString = navigator.userAgent;
    var versionMatch = uaString.match(reg);
    if (versionMatch) {
        return versionMatch[3];
    }
}
  1. ?
function setCookie(c_name,value,expiredays)
{
var exdate=new Date()
exdate.setDate(exdate.getDate()+expiredays)
document.cookie=c_name+ "=" +escape(value)+
((expiredays==null) ? "" : ";expires="+exdate.toGMTString())
}

function getCookie(c_name)
{
if (document.cookie.length>0)
  {
  c_start=document.cookie.indexOf(c_name + "=")
  if (c_start!=-1)
    { 
    c_start=c_start + c_name.length+1 
    c_end=document.cookie.indexOf(";",c_start)
    if (c_end==-1) c_end=document.cookie.length
    return unescape(document.cookie.substring(c_start,c_end))
    } 
  }
return "";
}

補(bǔ)充

暫無(wú)

AJAX

要求

function ajax(url, options) {
    // your implement
}

// 使用示例:
ajax(
    'http://localhost:8080/server/ajaxtest', 
    {
        data: {
            name: 'simon',
            password: '123456'
        },
        onsuccess: function (responseText, xhr) {
            console.log(responseText);
        }
    }
);

options是一個(gè)對(duì)象假栓,里面可以包括的參數(shù)為:

  • type: post或者get,可以有一個(gè)默認(rèn)值
  • data: 發(fā)送的數(shù)據(jù)晌畅,為一個(gè)鍵值對(duì)象或者為一個(gè)用&連接的賦值字符串
  • onsuccess: 成功時(shí)的調(diào)用函數(shù)
  • onfail: 失敗時(shí)的調(diào)用函數(shù)

思路

這個(gè)也沒(méi)啥好說(shuō)的但指,了解一下xhr對(duì)象就能寫(xiě)了。

實(shí)現(xiàn)

function ajax(url, options) {
    //新建一個(gè)XHR對(duì)象
    var xmlhttp;
    if (window.XMLHttpRequest) {
        // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    } else {
        // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    //若沒(méi)有設(shè)置type抗楔,則默認(rèn)為get

    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        options.onsuccess();
    } else {
        options.onfail();
    }
    type = options.type || get;
    xmlhttp.open(type, url, true);
    if (type === "get") {
        xmlhttp.send();
    } else {
        xmlhttp.send(options.data);
    }
}

補(bǔ)充

這里補(bǔ)充一下readyState和status的幾種狀態(tài)

屬性 描述
readyState 0: 請(qǐng)求未初始化
1: 服務(wù)器連接已建立
2: 請(qǐng)求已接收
3: 請(qǐng)求處理中
4: 請(qǐng)求已完成棋凳,且響應(yīng)已就緒
status 200: "OK"
404: 未找到頁(yè)面
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市连躏,隨后出現(xiàn)的幾起案子剩岳,更是在濱河造成了極大的恐慌,老刑警劉巖入热,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拍棕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡勺良,警方通過(guò)查閱死者的電腦和手機(jī)绰播,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)尚困,“玉大人蠢箩,你說(shuō)我怎么就攤上這事∈绿穑” “怎么了谬泌?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)逻谦。 經(jīng)常有香客問(wèn)我掌实,道長(zhǎng),這世上最難降的妖魔是什么邦马? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任贱鼻,我火速辦了婚禮,結(jié)果婚禮上勇婴,老公的妹妹穿的比我還像新娘忱嘹。我一直安慰自己,他們只是感情好耕渴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布拘悦。 她就那樣靜靜地躺著,像睡著了一般橱脸。 火紅的嫁衣襯著肌膚如雪础米。 梳的紋絲不亂的頭發(fā)上分苇,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音屁桑,去河邊找鬼医寿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蘑斧,可吹牛的內(nèi)容都是我干的靖秩。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼竖瘾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼沟突!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起捕传,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤惠拭,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后庸论,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體职辅,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年聂示,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了域携。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鱼喉,死狀恐怖涵亏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蒲凶,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布拆内,位于F島的核電站旋圆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏麸恍。R本人自食惡果不足惜灵巧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抹沪。 院中可真熱鬧刻肄,春花似錦、人聲如沸融欧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)噪馏。三九已至麦到,卻和暖如春绿饵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓶颠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工拟赊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人粹淋。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓吸祟,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親桃移。 傳聞我的和親對(duì)象是個(gè)殘疾皇子屋匕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,715評(píng)論 0 9
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法谴轮,類(lèi)相關(guān)的語(yǔ)法炒瘟,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法第步,異常的語(yǔ)法疮装,線(xiàn)程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,631評(píng)論 18 399
  • 前言 個(gè)人覺(jué)得IFE的練習(xí)非常不錯(cuò),學(xué)習(xí)前端不久粘都,看完幾本Head First廓推,JS編程藝術(shù)等等后,我就拿來(lái)當(dāng)練習(xí)...
    franose閱讀 1,588評(píng)論 0 1
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,112評(píng)論 25 707
  • 文/丹頂鶴的日記本 學(xué)習(xí)筆記注:本文所說(shuō)的表單(Form)翩隧,是網(wǎng)頁(yè)或者移動(dòng)應(yīng)用表單樊展。 一) 表單的作用 表單的主要...
    丹頂鶴的日記本閱讀 1,653評(píng)論 2 20