js-高级dom操作

4次阅读

共计 4420 个字符,预计需要花费 12 分钟才能阅读完成。

css 和 html 代码

<!doctype html>
<html lang="en">
 <head>
      <meta charset="UTF-8">
      <meta name="Keywords" content="">
      <meta name="Description" content="">
      <title>document</title>
      <style type="text/css">
            *{
                padding:0;
                margin:0
            }
            img{vertical-align:middle;}
            #box{
                width:1250px;
                height:360px;
                margin:100px auto;
                font-family:'Microsoft yahei';
            }
            #box ul li{
                list-style:none;
                float:left;
                margin:0 10px;
                position:relative;
                overflow:hidden;
            }
            #box ul li a{
                width:230px;
                height:360px;
                position:absolute;
                left: 0;
                top: 360px;
                background:url("images/new-bg.png");
                text-decoration:none;
            }
            #box ul li a p{
                color:#fff;
                font-size:14px;
                text-align:center;
            }
            #box ul li a p.p1{padding-top:160px;}
        </style>
 </head>
        <body>
            <div id='box'>
                <ul id="list">
                    <li>
                        <img src='images/1.jpg'/>
                        <a href='#'>
                            <p class='p1'> 秋冬上新 领券立减 20</p>
                            <p> 点击进入 </p>
                        </a>
                    </li>
                    <li>
                        <img src='images/2.jpg'/>
                        <a href='#'>
                            <p class='p1'> 钜惠满 138 减 15</p>
                            <p> 点击进入 </p>
                        </a>
                    </li>
                    <li>
                        <img src='images/3.jpg'/>
                        <a href='#'>
                            <p class='p1'> 冬装尖品 强势登陆 </p>
                            <p> 点击进入 </p>
                        </a>
                    </li>
                    <li>
                        <img src='images/4.jpg'/>
                        <a href='#'>
                            <p class='p1'> 十一国庆除出游季 </p>
                            <p> 购新衣才够【型】</p>
                        </a>
                    </li>
                    <li>
                        <img src='images/5.jpg'/>
                        <a href='#'>
                            <p class='p1'> 秋上新 </p>
                            <p> 点击进入 </p>
                        </a>
                    </li>
                </ul>
            </div>
</html>

js 实现思路

  • 什么是 js 语言?js 语言是基于原型的动态解释性语言,其基本操作分为 css 样式操作和 dom 节点操作。基于原型:存在对象、声明,就有原型。动态解释性:语言可以在任何环境下运行,没有限制。js 不仅仅能够用于特效,插件框架开发、机器学习、数据分析、人工智能,都可以通过 js 实现
  • 实现简单的鼠标划入操作思路:

(1)获取 dom 元素

(2)考虑两个事件:mouseenter、mouseleave,注册事件实现移入移出操作。

元素获取

  • 获取元素有三种方法:原生 js 方法(get 方法)、$ 方法、query 方法。其中 get 方法由 js 原生提供,获取速度最优,$ 和 query 方法都是由 get 系列封装而成。不同在于 $ 是 jQuery 提供,性能最差;query 由 html5 提供,而且经过了优化,获取速度仅次于 get 原生方法。
  • 在这里我们使用原生 js 方法实现:
<script>
                var oBox=document.getElementById('box');
                var aLi=oBox.getElementsByTagName('li');
 </script>

使用 for 循环进行事件注册

  • for 循环可以给每个 li 绑定一个事件,从而实现了事件注册
// 使用 for 循环进行事件注册
                for(var i=0,aLiLen=aLi.length;i<aLiLen;i++){// 这样较 for(var i=0;i<aLi.length;i++) 性能更优,因为不必每次计算 aLi.length
                    aLi[i].onmouseenter=function(){console.log(1);
                    }
                }
  • 首先注意的是,由于 box 有多个 li 子元素,所以 aLi 是一个伪数组。即具有数组的属性(下标、长度),而没有数组的方法(foreach、push、sort)。其次注意,enter、leave、over、out 的区别:enter、leave 在不冒泡条件下进行,由外到里;out、over 在冒泡条件下进行,由里到外。冒泡:事件的执行顺序由子集向父集发出,即由里到外。
  • 但是,一般情况下,我们不采用 for 循环进行事件注册。原因:

(1)当事件绑定特别多时,容易造成事件覆盖。即只执行后边的事件,前边事件不执行

(2)性能特别差,进行循环遍历为每个 li 绑定事件;但是鼠标不进入的话,就不会触发事件。这样会造成浏览器加载资源的浪费(当一万个事件时 …)

因此,我们通常采用事件代理(事件委托)实现事件注册。事件代理基于事件监听实现,不必给每个 li 进行绑定

基于事件监听的事件代理

  • 在实现特效时,首先要学会观察,不要着急一上来就干。思考此特效的实现过程:鼠标移入 -》获取鼠标坐标 -》获取元素宽高,进而得到元素距离浏览器各边的大小 -》计算鼠标坐标和四条边的距离 -》哪边的绝对值最小,就说明从哪边移入(移入瞬间,差值接近 0)
  • 若有两个的绝对值是相等的,我们执行哪个事件呢?当然是后边的,因为事件覆盖嘛。
  • 在计算得到四个绝对值中的最小值后,我们加以 val 的判断,就能得到鼠标是从哪个方向移入或者移出了。但是后边的动画怎么实现呢?我们分两步完成,假设鼠标从上边移入,我们先瞬间令背景图移动到最上边,然后缓慢的移下来。这个动画的实现过程我们使用链式操作实现。链式操作的原理很简单,就是每次方法执行完后返回 this 对象,这样后面的方法就可以继续在 this 环境下执行。
       // 获取元素
                var oBox=document.getElementById('box');
                var aLi=oBox.getElementsByTagName('li');

                // // 使用 for 循环进行事件注册
                // for(var i=0,aLiLen=aLi.length;i<aLiLen;i++){//     // 这样较 for(var i=0;i<aLi.length;i++) 性能更优,因为不必每次计算 aLi.length
                //     aLi[i].onmouseenter=function(){//         console.log(1);
                //     }
                // }

                // 基于事件监听的事件代理
                oBox.addEventListener('mouseenter',function(e){
                    // 检验和调试
                    // 最后的 false\true 参数表示是否冒泡。默认为 false,表示冒泡阶段
                    //console.log(1);// 参数为 true 一次打印多个 1;false 一次打印一个 1
                    //console.log(e);//true 一次会触发多个事件,是我们想要的
                    //console.log(e.target.tagName);// 确认真的没错

                    // 代码优化
                    var target=e.target;

                    if(target.tagName.toLowerCase()=='li'){
                        // 得到鼠标移入 li 瞬间的鼠标坐标
                        var x=e.clientX;
                        var y=e.clientY;

                        // 得到 li 四条边距离浏览器左部和顶部的距离
                        var oT=target.offsetTop;
                        var oB=oT+target.offsetHeight;
                        var oL=target.offsetLeft;
                        var oR=oL+target.offsetWidth;

                        // 计算鼠标坐标和四条边的距离,取绝对值
                        var diffT=Math.abs(y-oT);
                        var diffB=Math.abs(y-oB);
                        var diffL=Math.abs(x-oL);
                        var diffR=Math.abs(x-oR);

                        // 取最小值为方向
                        var direction=Math.min(diffT,diffB,diffL,diffR);

                        // 判断是鼠标移入还是移出
                        var val=e.type.toLowerCase();

                        //console.log(diffT,diffB,diffL,diffR);// 检验一下

                        //switch 语句选择方向
                        switch(direction){
                            // 方法是一样的,只是方向不一样。我们只要封装函数即可
                            case diffT:
                                moveTo('top',val,target);
                                //console.log('从上移入');
                                break;
                            case diffB:
                                moveTo('bottom',val,target);
                                //console.log('从下移入');
                                break;
                            case diffL:
                                moveTo('left',val,target);
                                //console.log('从左移入');
                                break;
                            case diffR:
                                moveTo('right',val,target);
                                //console.log('从右移入');
                                break;
                        }
                    }
                },true);

                function moveTo(aspect,mouse,aim){
                    //aspect 表示鼠标移入方向;// mouse 表示鼠标
                    // aim 表示操作的对象
                    // from 瞬间移动的距离
                    // to 后来的距离,默认为 0
                        if(mouse=='mouseenter'){aim.children[1].css(aspect).enter(aspect);
                        }else{}}

                Node.prototype.css=function(aspect){if(aspect=='top'){this.style[aspect]=-360+'px';
                        this.style.left=0;
                    }

                    return this;
                }

                Node.prototype.enter=function(aspect){setTimeout(function(){this.style[aspect]=0+'px';
                        this.style.transition='.3s';
                    }.bind(this),0)
                    //this 在此处默认指向 windows(因为 settimeout 是 windows 调用的函数),我们使用 bind 强制事件绑定,使其指向当前对象

                    // this.style[aspect]=to+'px';
                    // this.style.transition='.3s';
                    // 若不使用 setTimeOut 伪异步操作的话,会发生事件覆盖,即前边的 css 被后边的 enter 覆盖

                    return this;
                }

问题

浏览器打开后,特效有时从上边出来,有时从下边出来,不知道为啥

正文完
 0