中高級前端應該必會,js實現事件委托代理、切換樣式、元素獲取相對於文檔位置等


1、介紹

  隨着組件開發大流行,現在三大框架已經基本占領了整個前端。

  這時候,我們要是引入一個 jq 是不是先得你的項目非常臃腫,jq 也很不適合。

  這個時候,你就需要來增加你 js 的功底。

 

2、各種操作

  

  1、事件委托

  案例分析:

<ul id= "list">
    <li>1</li>
    <li>2</li>    
    <li>3</li>    
    <li>4</li>    
    <li>5</li>    
</ul>

  如上面的頁面機構,我們需要個每一個 li 添加同一個事件。

  常規操作:

  選擇出所有的 li 標簽,然后為所有的標簽都添加這個事件。

var liList = document.querySelectorAll('#list li')
liList.foreach(function(item,index)=>{
  item.addEventListener('click',doSomething)
})

  

  很簡單,也是非常好的。

  但是當這里的 li 標簽多了之后,那么你獲取所有的 li 標簽並綁定事件就會變慢,也就是說性能就會不好了。

  這個時候該如何處理呢?

 

  事件委托:

  解釋下事件委托吧,可能新手不知道。

  就是把子元素想要綁定的事件,綁定到子元素的父元素上面。

  然后當事件觸發的時候,通過事件冒泡來獲取到當前事件源對應的的元素。(事件冒泡和捕獲如果不知道還是需要補習下的)

  代碼展示:

var liList = document.querySelectorAll('#list')
liList.addEventListener('click',function(e)=>{ 
    if(e.target && e.target.nodeName.toUpperCase == 'LI'){
    console.log('你點擊了'+e.target.innerText )
  }
})

  

  給一個比較完整的例子,沒有驗證...

function delegate(element, eventName, name, func) {
	element.addEventListener(eventName, function (e) {
		var target = e.target, parent = target;
		while (target && parent != element) {
			if (parent.nodeName.toLowerCase() == name) {
				e.target = parent
				func.apply(parent,e);
				break;
			}
			parent = parent.parentNode;
		}
	});
}

  

  上面的例子,name 字段可以是 類命,id 的值,也可以是 標簽。

  自行修改,更靈活。。

 

  總結:

  事件代理委托主要是通過給父元素綁定事件。

  通過事件的冒泡來確定當前的事件源。

  確定事件源,並執行具柄。

  

  

 

  2、es5 的元素獲取、class 的操作

  

  es5 的元素獲取

 

  在之前我一直都是使用的 es3 做元素獲取的,如:

 

document.getElementById(id)
document.getElementsByClassName(class)

  上面的相信是大家以前最熟悉的 js 獲取方法。

  但是在 es5 出來后,你會驚奇的覺得 Jquery 選擇器可以被替代了

 

document.querySelector(selector)
document.querySelectorAll(selector)
// 例如
document.querySelector('.classs p')  // 獲取 class 類下面的 p 標簽
// 可以看到和 jquery 選擇器差不多,只是功能精簡了

  

  上面很清楚的可以知道:

  querySelector 是獲取單個元素

  querySelectorAll 是獲取多個匹配元素

  最大的變化就是 selector。

  它可以是 .className  、  #id   、也可以是多級選擇  .className p

 

 

  class 類的一些 es5 操作 

 

  Dom 的 classList 屬性:

<div id = "test" class = "red big hot"></div>

  

  獲取樣式類列表

  document.querySelector('test').classList

  這里會返回一個 TokenList 也就是是個類數組:

  

{
  0:red,
  1:big,
  2:hot,
  length:3,
  value:'red big hot'
}

  

  添加類名

  document.querySelector('test').classList.add('good','new')

  添加類 good , new 。如果類名已經存在,則不添加

 

  移除某類

  document.querySelector('test').classList.remove('good','new')  

  移除 good , new 類。移除不存在的類,會報錯

 

  切換類

  document.querySelector('test').classList.toggle('good')

  切換 good 類。如果 good 存在返回true,否則false

 

  判斷是否存在某類

  document.querySelector('test').classList.contains('good')

  返回 boolean 值。

 

  

  3、獲取元素在父元素中第幾個

 

  其實這個在現在的組件模式中很容易實現。

  但是 js 中是如是實現的呢 ?

 

 <ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
</ul>

  

   獲取方法及其封裝:

 

function index(parent,son) {
       return [].indexOf.call(parent.children,son);
   }

  

  如上面:

  parent 是父元素,son 很顯然是子元素

 

 

 

  4、元素相對於文檔 / 窗口視圖的位置 

 

   相對於文檔的位置

  

  在 jquery 中我們實現的方法是 $(s).offset() 來回去相對於文檔的位置。

  那 js 中如何實現的呢?

 

  代碼:

const getDocPosition = (element) => {
    let eleCom = element;
    if (typeof element === 'string') eleCom = document.querySelector(eleCom);
    let x = eleCom.offsetLeft;
    let y = eleCom.offsetTop;
    let parent = eleCom.offsetParent;
    while (parent) {
        x += parent.offsetLeft;
        y += parent.offsetTop;
        parent = parent.offsetParent;
    }
    return {
        x,
        y,
    };
};

  

  代碼很簡單:

  可以看出,通過不斷的獲取 offsetLeft / offsetTop ,並且與它的父元素相加。

  直到相加到頂級元素為止。 

 

   

  相對於窗口視圖位置

   

  getBoundingClientRect用於獲取某個元素相對於視窗的位置集合。集合中有top, right, bottom, left等屬性。

 

  

 

rectObject = object.getBoundingClientRect();

  

   rectObject.top:元素上邊到視窗上邊的距離;

   rectObject.right:元素右邊到視窗左邊的距離;

   rectObject.bottom:元素下邊到視窗上邊的距離;

   rectObject.left:元素左邊到視窗左邊的距離;

 

  如果你看過 lazyImg 圖片的懶加載,你們就會發現,他的實現原理就是這個。

  當它圖片出現在窗口的視圖中,就會加載真的圖片資源。 

 

 

  后續繼續添加常用的、容易忘的一些 js 功能。

 

  https://www.cnblogs.com/jiebba/p/9663268.html 

   我的博客 :  XiaoLong's Blog

   博客園小結巴巴: https://www.cnblogs.com/jiebba

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM