前端面试之事件

本文详细讲解了JavaScript事件监听函数的实现,包括clickFn和addEvent/removeEvent函数,以及事件冒泡和捕获的区别。重点介绍了事件委托技术,如何通过减少事件处理程序数量提高性能,以及在移动开发、前端布局和数据加载中的应用实例。
摘要由CSDN通过智能技术生成

事件监听函数

<div id="box">123</div>
<script type="text/javascript">
    //获得此元素
    var box = document.getElementById("box");
    /*
     * 函数名:clickFn
     * 功能:一个普通的函数,实现打印功能
     */
     function clickFn(){
        console.log( box.innerHTML );
     }
    //事件监听函数
    /*
     * 函数名: addEvent( obj,type,fn,capture)
     * 参数
     * obj: 目标元素
     * type: 事件类型
     * fn: 回调函数
     * capture 是否异步
     * 功能:主要实现事件监听
     */
    function addEvent( obj,type,fn,capture ){
        //console.log("aa");
        if(obj.addEventListener){
            obj.addEventListener("click",clickFn,true);
        }else{
            obj.attachEvent("click",clickFn,true);
        }
    }
    //添加事件
    addEvent(box,"click",clickFn,true);
    //移除事件
    /*
     * 函数名:removeEvent( obj,type,fn,capture )
     * 参数:
     * obj 目标元素
     * type 事件类型
     * fn  指定事件触发调用的函数
     * capture 是否同步
     */
     function removeEvent( obj,type,fn,capture ){
        if( obj.removeEventListener ){
            obj.removeEventListener(type,clickFn,true);
        }else{
            obj.detachEvent("on"+ type,clickFn,true);
        }
     }
     removeEvent(box,"click",clickFn,true);
</script>

事件冒泡的流程

js事件流(event flow ):
是指从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序,并存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。

事件冒泡和事件捕获的区别
当事件发生时,最先得到通知的
是window,然后是document,由上至下逐级依次而入,直到真正触发事件的那个元素(目标元素)为止,这个过程就是捕获。
接下来,事件会从目标元素开始起泡,由下至上逐级依次传播,直到window对象为止,这个过程就是冒泡。
所以捕获比冒泡先执行。其中DOM3级事件在DOM2的基础之上添加了更多的事件类型。
在这里插入图片描述

无限下拉更新图片

第一步:首先你需要获取所有img标签

var aImg = document.querySelectorAll('img');

第二步:获取地理位置信息

var scrollT = $(window).scrollTop();

var winH = $(window).height();

如果当前图片到文档顶部的距离当前浏览器的高度+滚动条距离顶部的距离,我们就加载图片
说到加载图片我们首先把图片的地址存在data-src中,加载的时候把data-src的属性赋值给src

  if (aImg[i].offsetTop < scrollT + winH) {
       aImg[i].src = aImg[i].getAttribute('data-src');
 }复制代码
那就是这样

    function loadImg() {
        var scrollT = $(window).scrollTop();
        var winH = $(window).height();
        var aImg = document.querySelectorAll('img');
        var len = aImg.length;
        for (var i = 0; i < len; i++) {
            if (aImg[i].offsetTop < scrollT + winH) {
                aImg[i].src = aImg[i].getAttribute('data-src');
            }
        }
    }复制代码
如果想实现下拉,加载接口下一页的数据,可以下面的方法实现
var URL = 'moubao.com/goods?page=…'

题外:下拉加载下一页的数据

  function loadPage() {
        var n = 0;
        var len = vm.array.length;
        var pageH = $(document.body).height();
        var scrollT = $(window).scrollTop();
        var winH = $(window).height();
        var aa = (pageH - winH - scrollT) / winH;
        if (aa < 0.5) {
            getData(i);
        }
        flag = false;
    }
 
     注:getData()函数
     function getData(pagenumber){
     i++
     $.ajax({
          type: 'get',
          url: URL,
          data: { page: pagenumber, size: gPageSize },
          dataType: 'json',
          success: function(ajaxData) {
              console.log(ajaxData);
          },
      });
    }

不过在调用loadImg()的时候,别直接写loading(),放在例如
$(‘window’).scroll(functin(){
loagImg();
loadPage();
});
因为,两个函数都要实时获取到

$(document.body).height();
$(window).scrollTop();
$(window).height();

事件绑定

首先,我先来介绍我们平时绑定事件的三种方法。
1.嵌入dom

<button onclick="open()">按钮</button>

<script>
function open(){
	alert(1)
}
</script>

2.直接绑定

<button id="btn">按钮</button>
<script>
document.getElementById('btn').onclick = function(){
	alert(1)
}

3.事件监听

<button id="btn">按钮</button>
<script>
document.getElementById('btn').addEventListener('click',function(){
	alert(1)
})
//兼容IE
document.getElementById('btn').attachEvent('click',function(){
	alert(1)
})

事件委托

对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只制定一个事件处理程序,就可以管理某一类型的所有事件。例如click事件一直会冒泡到document层。也就是我们可以只指定onclick事件处理程序,而不必给每个事件分别添加处理程序。
样式以及DOM结构

 <style>
   * {
     padding: 0;
     margin: 0;
   }
   
   .head, li div {
     display: inline-block;
     width: 70px;
     text-align: center;
   }

   li .id, li .sex, .id, .sex {
     width: 15px;
   }

   li .name, .name {
     width: 40px;
   }

   li .tel, .tel {
     width: 90px;
   }

   li .del, .del {
     width: 15px;
   }

   ul {
     list-style: none;
   }

   .user-delete {
     cursor: pointer;
   }

 </style>
</head>

<body>
<div id="J_container">
	<div class="record-head">
	  <div class="head id">序号</div><div class="head name">姓名</div><div class="head sex">性别</div><div class="head tel">电话号码</div><div class="head province">省份</div><div class="head">操作</div>
	</div>
   <ul id="J_List">
     <li><div class="id">1</div><div class="name">张三</div><div class="sex"></div><div class="tel">13788888888</div><div class="province">浙江</div><div class="user-delete">删除</div></li>
     <li><div class="id">2</div><div class="name">李四</div><div class="sex"></div><div class="tel">13788887777</div><div class="province">四川</div><div class="user-delete">删除</div></li>
     <li><div class="id">3</div><div class="name">王二</div><div class="sex"></div><div class="tel">13788889999</div><div class="province">广东</div><div class="user-delete">删除</div></li>
   </ul>
 </div>
 </body>

不用事件委托。而这种方法造成的代价是,性能的大量浪费。如果是成千上万条数据,页面将会严重卡顿,甚至崩溃。

function Contact(){
    this.init();
}
	

Contact.prototype.init = function(){
	var userdel = document.querySelectorAll('.user-delete');
	for(var i=0;i<lis.length;i++){
		(function(j){
			userdel[j].onclick = function(){
	userdel[j].parentNode.parentNode.removeChild(userdel[j].parentNode);
			}
		})(i);
	}	
}

new Contact();

使用事件委托,只绑定一次事件,大大减少了性能的损耗。也是在需要大量事件处理程序中一种非常好的解决方式。

function Contact(){
    this.init();
}
	

Contact.prototype.init = function(){
	var lis = document.querySelector('#J_List');
	lis.addEventListener('click', function(e){
		var target = e.target || e.srcElement;
		if (!!target && target.className.toLowerCase()==='user-delete') {				target.parentNode.parentNode.removeChild(target.parentNode);
		}
	})
}

new Contact(

);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只小 Ziyi.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值