摘要:調用函數,判斷是否含有該指定樣式,若含有的話刪除該。分不同的情況來調用函數,并返回對象。慕課網探索之基礎詳解篇慕課網事件探秘。參考資料事件代理委托事件代理實現如下事件代理需要進行事件代理的父元素。
DOM 添加class、移除class、是否同級元素、獲取元素位置轉載自我的個人博客
歡迎大家批評指正
先來一些簡單的,在你的util.js中完成以下任務:
// 為element增加一個樣式名為newClassName的新樣式 function addClass(element, newClassName) { // your implement } // 移除element中的樣式oldClassName function removeClass(element, oldClassName) { // your implement } // 判斷siblingNode和element是否為同一個父元素下的同一級的元素,返回bool值 function isSiblingNode(element, siblingNode) { // your implement } // 獲取element相對于瀏覽器窗口的位置,返回一個對象{x, y} function getPosition(element) { // your implement } // your implement思路:
其實這里可以先定義一個hasClass函數。用來判斷該節點是否含有某個className。
addClass添加樣式。調用hasClass函數,判斷element是否含有待添加的新className,若沒有則添加,否則什么都不做。
removeClass刪除樣式。調用hasClass函數,判斷element是否含有該指定樣式,若含有的話刪除該className。沒有的話什么都不做。
判斷siblingNode和element是否為同一個父元素下的同一級的元素。這里直接判斷parentNode就可以了吧
獲取element相對于瀏覽器窗口的位置,返回一個對象{x, y}。
這個題應該是這幾個中比較復雜的一個了。因為不能直接使用offsetLeft/Top。offsetLeft/Top所獲取的是其相對父元素的相對位置。當多層定位嵌套時想要獲取到當前元素相對網頁的位置就會不對。
并且由于在表格和iframe中,offsetParent對象未必等于父容器,所以也不能直接利用該元素的parent來獲取位置,因為其對于表格和iframe中的元素不適用。
通過查詢知道有一個Element.getBoundingClientRect()方法。它返回一個對象,其中包含了left、right、top、bottom四個屬性,分別對應了該元素的左上角和右下角相對于瀏覽器窗口(viewport)左上角的距離。
但是用該方法獲取到的是元素的相對位置,在出現滾動時,距離會發生改變,要獲得絕對位置時,還需要加上滾動的距離。因為Firefox或Chrome的不兼容問題需要進行兼容性處理,參考document.body.scrollTop or document.documentElement.scrollTop
最終根據兩個值,得到絕對位置。
//其實也簡單,只需要獲取到兩個值,取其中的最大值即可。 var scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft); var scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);實現:
//判斷element中是否含有className為sClass。 function hasClass(element, sClass) { return element.className.match(new RegExp("(s|^)" + sClass + "(s|$)")); } // 為element增加一個樣式名為newClassName的新樣式 function addClass(element, newClassName) { if (!hasClass(element, newClassName)) { element.className += " " + newClassName; } } // 移除element中的樣式oldClassName function removeClass(element, oldClassName) { if (hasClass(element, oldClassName)) { var reg = new RegExp("(s|^)" + oldClassName + "(s|$)"); element.className = element.className.replace(reg, ""); } } // 判斷siblingNode和element是否為同一個父元素下的同一級的元素,返回bool值 function isSiblingNode(element, siblingNode) { return element.parentNode === siblingNode.parentNode } // 獲取element相對于瀏覽器窗口的位置,返回一個對象{x, y} function getPosition(element) { var position = {}; position.x = element.getBoundingClientRect().left + Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);//獲取相對位置+滾動距離=絕對位置. position.y = element.getBoundingClientRect().top + Math.max(document.documentElement.scrollTop, document.body.scrollTop); return position; }
參考資料:(還沒看完)
阮一峰用Javascript獲取頁面元素的位置
博客園JavaScript獲取DOM元素位置和尺寸大小
博客園js中的各種寬高以及位置總結
挑戰mini $接下來挑戰一個mini $,它和之前的$是不兼容的,它應該是document.querySelector的功能子集,在不直接使用document.querySelector的情況下,在你的util.js中完成以下任務:
// 實現一個簡單的Query function $(selector) { } // 可以通過id獲取DOM對象,通過#標示,例如 $("#adom"); // 返回id為adom的DOM對象 // 可以通過tagName獲取DOM對象,例如 $("a"); // 返回第一個對象 // 可以通過樣式名稱獲取DOM對象,例如 $(".classa"); // 返回第一個樣式定義包含classa的對象 // 可以通過attribute匹配獲取DOM對象,例如 $("[data-log]"); // 返回第一個包含屬性data-log的對象 $("[data-time=2015]"); // 返回第一個包含屬性data-time且值為2015的對象 // 可以通過簡單的組合提高查詢便利性,例如 $("#adom .classa"); // 返回id為adom的DOM所包含的所有子節點中,第一個樣式定義包含classa的對象
實現思路:
嗯,這個題思考了很久,網上找了很多資料但還是不怎么會,還達不到想要的效果,有點鉆牛角尖了。盡量來寫一下吧。(我果然是個弱雞)。感謝秒味課堂的免費課程。
題目要求獲取到所有的節點中的第一個,所以不需要用數組來儲存獲取到的節點。
額。。想了半天,還是使用函數包裝來實現后代選擇器比較好,所以VQuery函數返回是獲取到的完整節點對象數組,$函數用來達到題目要求。
所以在VQuery函數中就不需要考慮空格了,直接使用switch分支,來判定不同的情況。#、.、[、 [=]。
在$函數中,判斷字符串中是否含有空格,有空格的話需要分割成數組,數組的前一項是為父選擇符,后一項為子選擇符。分不同的情況來調用VQuery函數,并返回對象。
/** * $函數的依賴函數,選擇器函數 * @param {string} selector CSS方式的選擇器 * @param {object} root 可選參數,selector的父對象。不存在時,為document * @returns {Array} 返回獲取到的節點數組,需要注意的是使用ID選擇器返的也是數組 */ function VQuery(selector, root) { //用來保存選擇的元素 var elements = []; //保存結果節點數組 var allChildren = null; //用來保存獲取到的臨時節點數組 root = root || document; //若沒有給root,賦值document switch (selector.charAt(0)) { case "#": //id選擇器 elements.push(root.getElementById(selector.substring(1))); break; case ".": //class選擇器 if (root.getElementsByClassName) { //標準 elements = root.getElementsByClassName(selector.substring(1)); } else { //兼容低版本瀏覽器 var reg = new RegExp("" + selector.substring(1) + ""); allChildren = root.getElementsByTagName("*"); for (var i = 0, len = allChildren.length; i < len; i++) { if (reg.test(allChildren[i].className)) { elements.push(allChildren[i]); } } } break; case "[": //屬性選擇器 if (selector.indexOf("=") === -1) { //只有屬性沒有值的情況 allChildren = root.getElementsByTagName("*"); for (var i = 0, len = allChildren.length; i < len; i++) { if (allChildren[i].getAttribute(selector.slice(1, -1)) !== null) { elements.push(allChildren[i]); } } } else { //既有屬性又有值的情況 var index = selector.indexOf("="); //緩存=出現的索引位置。 allChildren = root.getElementsByTagName("*"); for (var i = 0, len = allChildren.length; i < len; i++) { if (allChildren[i].getAttribute(selector.slice(1, index)) === selector.slice(index + 1, -1)) { elements.push(allChildren[i]); } } } break; default: //tagName elements = root.getElementsByTagName(selector); } return elements } /** * 模仿jQuery的迷你$選擇符。 * @param {string} selector CSS方式的選擇器,支持簡單的后代選擇器(只支持一級) * @returns {object} 返回獲取到的第一個節點對象,后代選擇器時,返回第一個對象中的第一個符合條件的對象 */ function $(selector) { //這里trim處理輸入時兩端出現空格的情況,支持ie9+。但是這個函數實現起來也特別簡單,可以參考我task0002(-)前面有trim函數的實現。稍微修改一下,這樣就沒兼容性問題了。 if (selector == document) { return document; } selector = selector.trim(); //存在空格時,使用后代選擇器 if (selector.indexOf(" ") !== -1) { var selectorArr = selector.split(/s+/); //分割成數組,第一項為parent,第二項為chlid。 //這里沒去考慮特別多的情況了,只是簡單的把參數傳入。 return VQuery(selectorArr[1], VQuery(selectorArr[0])[0])[0]; } else { //普通情況,只返回獲取到的第一個對象 return VQuery(selector,document)[0]; } }事件 事件綁定、事件移除
我們來繼續用封裝自己的小jQuery庫來實現我們對于JavaScript事件的學習,還是在你的util.js,實現以下函數
// 給一個element綁定一個針對event事件的響應,響應函數為listener function addEvent(element, event, listener) { // your implement } // 例如: function clicklistener(event) { ... } addEvent($("#doma"), "click", a); // 移除element對象對于event事件發生時執行listener的響應 function removeEvent(element, event, listener) { // your implement }
這里慕課網的視頻講的特別清楚,就不贅述了。
慕課網 DOM探索之基礎詳解篇
慕課網 DOM事件探秘。這一部分,主要看這個。
/** * 事件添加函數 * @param {object} element 需要綁定事件的對象 * @param {string} event 事件類型 * @param {function} listener 事件觸發執行的函數 */ function addEvent(element, event, listener) { if (element.addEventListener) { //標準 element.addEventListener(event, listener, false); } else if (element.attachEvent) { //低版本ie element.attachEvent("on" + event, listener); } else { //都不行的情況 element["on" + event] = listener; } } /** * 事件移除函數 * @param {object} element 需要移除事件的對象 * @param {string} event 事件類型 * @param {function} listener 需要被移除事件函數 */ function removeEvent(element, event, listener) { // your implement if (element.removeEventListener) { //標準 element.removeEventListener(event, listener, false); } else if (element.detachEvent) { //低版本ie element.detachEvent("on" + event, listener); } else { //都不行的情況 element["on" + event] = null; } }click事件、Enter事件
利用上面寫好的事件綁定函數就很簡單了。
click事件,這個簡單,直接函數封裝一層就行。
Enter事件,這里主要考察的鍵盤的事件的觸發。
keydown事件:在鍵盤按下時觸發.
keyup事件:在按鍵釋放時觸發,也就是你按下鍵盤起來后的事件
keypress事件:在敲擊按鍵時觸發,我們可以理解為按下并抬起同一個按鍵
keyCode屬性:在鍵盤事件觸發時,按下的鍵的值。值=13時,為Enter鍵。(需進行兼容處理)
// 實現對click事件的綁定 function addClickEvent(element, listener) { addEvent(element, "click", listener); } // 實現對于按Enter鍵時的事件綁定 function addEnterEvent(element, listener) { // your implement addEvent(element, "keydown", function (ev) { //兼容性處理。 var oEvent = ev || window.event; if (oEvent.keyCode === 13) { listener(); } }); }
接下來我們把上面幾個函數和$做一下結合,把他們變成$對象的一些方法
addEvent(element, event, listener) -> $.on(element, event, listener);
removeEvent(element, event, listener) -> $.un(element, event, listener);
addClickEvent(element, listener) -> $.click(element, listener);
addEnterEvent(element, listener) -> $.enter(element, listener);
//在js中萬物皆對象(原諒我這么淺顯的說),所以實現就特別簡單了 $.on = function (element, type, listener) { return addEvent(element, type, listener); }; $.un = function (element, type, listener) { return removeEvent(element, type, listener); }; $.click = function (element, listener) { return addClickEvent(element, listener); } $.enter = function (element, listener) { $.enter addEnterEvent(element, listener); };事件代理
接下來考慮這樣一個場景,我們需要對一個列表里所有的增加點擊事件的監聽
我們通過自己寫的函數,取到id為list這個ul里面的所有li,然后通過遍歷給他們綁定事件。這樣我們就不需要一個一個去綁定了。但是看看以下代碼:
function renderList() { $("#list").innerHTML = "
我們增加了一個按鈕,當點擊按鈕時,改變list里面的項目,這個時候你再點擊一下li,綁定事件不再生效了。那是不是我們每次改變了DOM結構或者內容后,都需要重新綁定事件呢?當然不會這么笨,接下來學習一下事件代理,然后實現下面新的方法:
// 先簡單一些 function delegateEvent(element, tag, eventName, listener) { // your implement } $.delegate = delegateEvent; // 使用示例 // 還是上面那段HTML,實現對list這個ul里面所有li的click事件進行響應 $.delegate($("#list"), "li", "click", clickHandle);實現思路:
寫到這里,剛好前幾天CSS魔法寫的《前端進階之路:點擊事件綁定》有提到“事件代理/委托”,不過是直接使用jQuery來實現的。所以地址有興趣的自己搜索吧-_-。
“事件代理” 的本質是利用了事件冒泡的特性。當一個元素上的事件被觸發的時候,比如說鼠標點擊了一個按鈕,同樣的事件將會在那個元素的所有祖先元素中被觸發。這一過程被稱為事件冒泡;
這個事件從原始元素開始一直冒泡到DOM樹的最上層。任何一個事件的目標元素都是最開始的那個元素,在我們的這個例子中也就是按鈕,并且它在我們的元素對象中以屬性的形式出現。使用事件代理,我們可以把事件處理器添加到一個元素上,等待一個事件從它的子級元素里冒泡上來,并且可以得知這個事件是從哪個元素開始的。
這里就不細說事件冒泡與事件捕獲了(阻止默認行為也會用到,有興趣去網上找找看),但是要理解事件代理就必須先知道它們。下面這張圖可以先看看。(圖片來自網絡,侵刪)
理解了這個之后就沒那么難了,只需要進行一點兼容性處理。
參考資料
javascript事件代理(委托)
JavaScript事件代理
實現如下:/** * 事件代理 * @param {HTMLElement} element 需要進行事件代理的父元素。 * @param {string} tag 需要觸發事件的標簽名 * @param {string} eventName 觸發的事件類型 * @param {function} listener 事件執行的函數 * @returns {[[Type]]} [[Description]] */ function delegateEvent(element, tag, eventName, listener) { // your implement return addEvent(element, eventName, function (ev) { var oEvent = ev || event; //兼容處理 var target = oEvent.target || oEvent.srcElement; //兼容處理 if (target.tagName.toLocaleLowerCase() === tag) { listener.call(target, oEvent); //使用call方法修改執行函數中的this指向,現在this指向觸發了事件的HTML節點(可直接使用this.innerHTML返回該節點內容) } }) } $.delegate = function (element, tag, eventName, listener) { return delegateEvent(element, tag, eventName, listener); };封裝改變
估計有同學已經開始吐槽了,函數里面一堆$看著暈啊,那么接下來把我們的事件函數做如下:(這里應該是把前面的$.on、$.click、$.un、$.delegate都改寫一下。比較簡單,就拿一個出來作例子吧。)
//和上面的函數一樣,原來第一個參數是傳入獲取到的父HTMLElement對象,現在直接傳入選擇器名稱就行 $.delegate = function (selector, tag, event, listener) { //這里的`$(selector)`,是用的自己封裝的選擇器函數,愿意的話可以換成標準支持的`document.querySelector()` return delegateEvent($(selector), tag, event, listener); }; // 使用示例: $.delegate("#list", "li", "click", liClicker);
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91576.html
摘要:獲取下一個元素節點,存在的話,取消現有選中狀態,設置下一個元素節點為選擇中,調用運動框架實現動畫,添加定時器,調用該函數,實現自動播放。移出時,開啟定時器,繼續輪播。輪播間隔時間單位為毫秒,默認為,在內部,以下部分進行修改或添加。 轉載自我的個人博客 歡迎大家批評指正 包括5部分: 小練習1-處理用戶輸入 小練習2-日期對象的使用 小練習3:輪播圖 小練習4:輸入提示框 小練習...
摘要:獲取下一個元素節點,存在的話,取消現有選中狀態,設置下一個元素節點為選擇中,調用運動框架實現動畫,添加定時器,調用該函數,實現自動播放。移出時,開啟定時器,繼續輪播。輪播間隔時間單位為毫秒,默認為,在內部,以下部分進行修改或添加。 轉載自我的個人博客 歡迎大家批評指正 包括5部分: 小練習1-處理用戶輸入 小練習2-日期對象的使用 小練習3:輪播圖 小練習4:輸入提示框 小練習...
摘要:不過讓流行起來的原因應該是是目前所有主流瀏覽器上唯一支持的腳本語言。經過測試,數字字符串布爾日期可以直接賦值,修改不會產生影響。再考慮對象類型為或者的情況。對于結果聲明其類型。判斷對象的類型是還是,結果類型更改。 轉載自我的個人博客 歡迎大家批評指正 1. 第一個頁面交互 這里最需要學習的老師的代碼中,每一部分功能都由函數控制,沒有創建一個全部變量。且最后有一個函數來控制執行代碼...
摘要:可以傳遞三個參數表示一個或多個事件類型,比如。表示綁定到指定元素的處理函數。我們稱它為簡寫事件。必須在中,并且使用作為事件觸發元素,不然無效。和表示鼠標移入和移出的時候觸發。按下返回按下返回和分別表示光標激活和丟失,事件觸發時機是當前元素。 轉自個人博客 在JavaScript 有一個非常重要的功能,就是事件驅動。如果你的網頁需要與用戶進行交互的話,就不可能不用到事件。它在頁面完全加...
摘要:小練習輪播圖組件任務描述在和上一任務同一目錄下面創建一個文件,在目錄中創建,并在其中編碼,實現一個輪播圖的功能。實現思路考察對節點,定時器,事件的處理。 小練習3:輪播圖組件 任務描述在和上一任務同一目錄下面創建一個task0002_3.html文件,在js目錄中創建task0002_3.js,并在其中編碼,實現一個輪播圖的功能。 圖片數量及URL均在HTML中寫好 可以配置輪播的順...
閱讀 1774·2021-10-19 13:30
閱讀 1344·2021-10-14 09:48
閱讀 1538·2021-09-22 15:17
閱讀 2011·2019-08-30 15:52
閱讀 3278·2019-08-30 11:23
閱讀 1990·2019-08-29 15:27
閱讀 896·2019-08-29 13:55
閱讀 755·2019-08-26 14:05