我瞎逛个啥论坛,发现了一个题目,于是本着练手的心态就开始写起来了,于是各种问题接踵而至,收获不小。
题目是这样的:
Demo: mouseenter与mouseover区别demo
DownLoad:https://github.com/zhangmengxue/Practice/timeCounter.html
刚看上去,没什么特别,心里想了,我就用mouseover和mouseout事件,然后绑个定时器不就行了嘛~.......于是还没开始写呢,就被问到了,那mouseover和mouseenter这两个事件有什么区别的?为什么不用mouseenter呢?
然后我就仔细想了下mouseover和mouseenter之间的区别,下面是书上列出的定义:
->mouseenter:在鼠标光标从元素外部首次移动到元素范围之内时触发,这个事件不冒泡。而且在光标移到它后代元素上时不会触发;
->mouseleave:在位于元素上方的鼠标光标移动到这个元素范围之外时触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发;
->mouseover:在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发。
->mouseout:在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。又移入的一个元素可能是位于前一个元素的外部,也可能是这个元素的子元素。
尝试给下面这段代码分别绑定mouseenter和mouseover事件:
12 <ul id="test"> 13 <li>item 1</li> 14 <li>item 2</li> 15 <li>item 3</li> 16 </ul>
猛戳这里看demo:mouseenter与mouseover区别demo
根据例子可以看出来,虽然事件都是绑定到父元素ul上了,但是mouseover的事件对象其实却是子元素li,而mouseenter的事件对象才是真正的ul元素。
也就是说我的demo因为简单,所以这两个事件的区别在我的demo差别不明显,但是如果我的区块中有子元素的话,那么就会有问题了。
恩,于是遂改mouseenter和mouseleave,多么痛的领悟。
第一个版本的代码:
56 <script type="text/javascript"> 57 var counter = 0, 58 counter1 = 0, 59 counter2 = 0, 60 counter3 = 0; 61 var timer = null; 62 function timerCounter(div,counter,num){ 63 div.addEventListener('mouseenter',function(){ 64 timer = setInterval(count,1000); 65 },false); 66 div.addEventListener('mouseleave',function(){ 67 clearInterval(timer); 68 //这里设置null是很有必要的,为了重复计数 69 timer = null; 70 },false); 71 var span = document.createElement('span'); 72 div.appendChild(span); 73 function count(){ 74 counter++; 75 span.innerHTML = 'STAY:'+counter; 76 console.log('区块'+num+'上停留的时间为:'+counter); 77 } 78 return counter; 79 } 80 var div = document.getElementsByTagName('div'); 81 timerCounter(div[0],counter1,div[0].dataset['spmid']); 82 timerCounter(div[1],counter2,div[1].dataset['spmid']); 83 timerCounter(div[2],counter3,div[2].dataset['spmid']); 84 </script>
看它的运行结果,猛戳这里:区块停留计数器第一个版本
一直在chrome下测试,也没想别的,也没发现什么问题,然后想到好像用Date对象也可以实现,于是没费什么事儿,在我的chrome里,他也可以计数了,唯一不足的就是他要鼠标离开后才显示秒数,不过我没计较,因为潜意识里面意识到了我的代码很乱,但还是先把它实现放上来看看:
56 <script type="text/javascript"> 57 var startTime = 0, 58 totalTime = 0, 59 stayTime = 0, 60 counter1 = 0, 61 counter2 = 0, 62 counter3 = 0; 63 var timer = null; 64 function timerCounter(div,startTime,totalTime,num){ 65 var span = document.createElement('span'); 66 div.addEventListener('mouseenter',function(){
//换成用Date对象 67 startTime = new Date().getTime(); 68 },false); 69 div.addEventListener('mouseleave',function(){ 70 totalTime += new Date().getTime()-startTime; 71 //console.log(totalTime); 72 span.innerHTML = '鼠标离开后才会显示停留时长,stay:'+Math.floor(totalTime/1000); 73 },false); 74 div.appendChild(span); 75 } 76 var div = document.getElementsByClassName('mod-spm'); 77 timerCounter(div[0],startTime,totalTime,div[0].dataset['spmid']); 78 timerCounter(div[1],startTime,totalTime,div[1].dataset['spmid']); 79 timerCounter(div[2],startTime,totalTime,div[2].dataset['spmid']); 80 </script>
看它的运行结果,猛戳:区块停留计数器第二个版本
哎,貌似也可以接受,但是当我看到别人的代码的时候,心里可就不这样想了。我自己写完之后去百度了下看看还有没有别的方法,看别人有没有更好的实现,于是我看到了下面这段代码:
1 function ShowStayTime(obj) {
2 this.obj = obj;
3 this.totalTime = 0;
4 this.enterTime = null;
5 this.divTime= document.createElement('div');
6 }
7 ShowStayTime.prototype = {
8 constructor:ShowStayTime,
9 init: function() {
10 this.showStayTime();
11 this.obj.appendChild(this.divTime);
12 this.beginTime();
13 this.leaveTime();
14 },
15 showStayTime: function() {
16 var message = "";
17 message = "停留时间" + this.totalTime + "ms";
18 this.divTime.innerText = message;
19 },
20 beginTime: function() {
21 this.obj.addEventListener("mouseenter",function() {
22 this.enterTime = new Date();
23 })
24 },
25 leaveTime: function() {
26 var temp = this;
27 this.obj.addEventListener("mouseleave",function() {
28 temp.totalTime += new Date().getTime() - this.enterTime.getTime();
29 temp.showStayTime();
30 })
31 }
32 }
33 var divs = document.getElementsByClassName('mod-spm');
34 var show1 = new ShowStayTime(divs[0]);
35 var show2 = new ShowStayTime(divs[1]);
36 var show3 = new ShowStayTime(divs[2]);
37 show1.init();
38 show2.init();
39 show3.init();
用的也是Date方法,可是人家写的代码比我的 有思想多了。值得我学习呀~~于是我也更意识到了,真的还有很长的路要走,基础不能忘,设计模式这种高端的东西也要搞起来,代码也不能总那么屎下去吧,小胡子跟我说,厉害的人写代码的境界,能用原生的js实现任何他能想到的结果...
于是我又开始看我的代码,写的封装啊什么的很好的那种,我还没有那个能力,那我的代码,我还能做些什么呢?然后我就开始打开浏览器各种试,到IE的时候,我就傻了,它不起作用了~~这会想不改进也不行了,那就做些力所能及的吧~~~
那我第一个版本的实现,问题有哪些呢?实际上:
1. 细心的人应该早就注意到了,IE并不支持getElementsByClassName()这个函数;
2. 事件绑定没有注意跨浏览器的问题;
3. data-*的兼容性问题!!
这有个data-*的兼容性情况:
- Internet Explorer 11+
- Chrome 8+
- Firefox 6.0+
- Opera 11.10+
- Safari 6+
对于第一个问题:本来的做法就可以是,先使用getElementsByTagName("*")取出文档中所有元素,然后进行遍历,使用正则表达式找出匹配的元素放入一个数组返回。
可是,看了正美大神的下面这篇文章: document.getElementsByClassName()的理想实现 我觉得就想用这个方法了。而且心里无比崇拜。
第二个问题:事件绑定的跨浏览器问题,IE低版本根本不支持getElementsByClassName这个方法,哎,不能总自己小打小闹呀,养成好的习惯吧,快快改进。然后又看到正美大神的这篇文章:javascript处理时间的一些兼容写法 总结的很全面的。
第三个问题:由于data-*也存在兼容性问题,所以对于IE的低版本只能用getAttribute()方法获取。
然后改进改进改进:
1 <script type="text/javascript"> 2 var counter = 0, 3 counter1 = 0, 4 counter2 = 0, 5 counter3 = 0; 6 var timer = null; 7 function timerCounter(div,counter,num){ 8 addEvent(div,'mouseenter',function(){ 9 timer = setInterval(count,1000); 10 }); 11 addEvent(div,'mouseleave',function(){ 12 clearInterval(timer); 13 //这里设置null是很有必要的,为了重复计数 14 timer = null; 15 }); 16 var span = document.createElement('span'); 17 div.appendChild(span); 18 function count(){ 19 counter++; 20 span.innerHTML = 'STAY:'+counter; 21 console.log('区块'+num+'上停留的时间为:'+counter); 22 } 23 return counter; 24 } 25 26 //跨浏览器的事件处理函数 27 var addEvent = function( obj, type, fn ) { 28 if (obj.addEventListener) 29 obj.addEventListener( type, fn, false ); 30 else if (obj.attachEvent) { 31 obj["e"+type+fn] = fn; 32 obj.attachEvent( "on"+type, function() { 33 obj["e"+type+fn](); 34 } ); 35 } 36 }; 37 38 //解决getElementsByClassName在低版本ie中不支持的问题 39 var getElementsByClassName = function(searchClass,node,tag) { 40 if(document.getElementsByClassName){ 41 return document.getElementsByClassName(searchClass) 42 }else{ 43 node = node || document; 44 tag = tag || '*'; 45 var returnElements = [] 46 var els = (tag === "*" && node.all)? node.all : node.getElementsByTagName(tag); 47 var i = els.length; 48 searchClass = searchClass.replace(/-/g, "\-"); 49 var pattern = new RegExp("(^|\s)"+searchClass+"(\s|$)"); 50 while(--i >= 0){ 51 if (pattern.test(els[i].className) ) { 52 returnElements.push(els[i]); 53 } 54 } 55 return returnElements; 56 } 57 } 58 59 var div = getElementsByClassName('mod-spm'); 60 var block1 = num(div[0]); 61 var block2 = num(div[1]); 62 var block3 = num(div[2]); 63 timerCounter(div[0],counter1,block1); 64 timerCounter(div[1],counter2,block2); 65 timerCounter(div[2],counter3,block3); 66 //解决data-*的兼容性问题 67 function num(div){ 68 if(div.dataset){ 69 return div.dataset['spmid']; 70 }else{ 71 return div.getAttribute('data-spmid'); 72 } 73 } 74 75 </script>
这会换浏览器也不会出问题啦,各个浏览器下猛戳:跨浏览器的区块停留计时
总结:
1.知识点要分析的准确,比如说像mouseover与mouseenter这样的,这样写代码的时候才不会出现各种各样费解的问题;
2.既然意识到了自己的代码写的不太好有些乱,那么就后面努力在这方面下工夫,努力让它看起来“不错”些;
3.有机会听取别人的意见改进自己是件非常好的事情,欧耶~