• 中高级前端应该必会,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

  • 相关阅读:
    Windows Terminal 配色方案说明
    Windows Terminal 美化简记
    家庭组网启用 NAS
    Eclipse使用Git检出项目
    SVN clean失败解决方法
    httpClient closeableHttpClient
    JSON字符串与Map互转
    httpclient用getStatusCode
    同一台电脑同时装jdk1.8和jdk1.7
    PL/SQL连接远程oracle数据库配置
  • 原文地址:https://www.cnblogs.com/jiebba/p/9663268.html
Copyright © 2020-2023  润新知