从零开始,学习web前端之js特效

我们在平时浏览网页的时候,一般都会看到一些网页效果,比如弹窗,轮播图,点击回到顶部和动画等等。一般我们都是通过操作dom的left和top属性的值来实现。要实现这些功能我们要熟悉offset,scroll,client这三大系列的知识,了解动画的基本原理,掌握事件的处理方式。

三大系列

  1. offset
  2. scroll
  3. client

offset系列
offset本身有偏移,补偿的意思。在js中我们可以理解为偏移量。
offset系列常用的5个属性:

  1. offsetWidth 获取元素本身的宽
  2. offsetHeight 获取元素本身的高
  3. offsetLeft 获取距离有定位的父盒子的左边的距离
  4. offsetTop 获取距离有定位的父盒子的上边的距离
  5. offsetParent 获取最近父元素中带有定位的节点

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style>
        html, body {
            padding: 0px;
            margin: 0px;
        }

        .parentBox {
            position: absolute;
            padding: 20px;
            border: 10px solid black;
        }

        p {
            width: 100px;
            height: 100px;
            background: red;
            margin-left: 30px;
        }
    </style>

    <script>

        window.onload = function () {
            var divNode = document.getElementsByTagName("p")[0];
            console.log(divNode.offsetParent.nodeName);
            console.log("元素left:" + divNode.offsetLeft);
            console.log("元素top:" + divNode.offsetTop);
            console.log("元素宽:" + divNode.offsetWidth);
            console.log("元素高:" + divNode.offsetHeight);
        }
    </script>
</head>
<body>
<div class="parentBox">
    <p></p>
</div>
</body>
</html>

这里写图片描述


scroll系列

  1. scrollWidth 获取元素中内容的宽度
  2. scrollHeight 获取元素中内容的高度
  3. scrollTop 网页被卷去的高
  4. scrollLeft 网页被卷去的左

示例:
scrollWidth 、scrollHeight

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div {
            height: 100px;
            width: 50px;
            margin: 10px;
            padding: 10px;
            border: 1px solid red;
        }
    </style>
    <script>
        window.onload = function () {
            var div = document.getElementsByTagName("div")[0];
            console.log("scrollWigth:"+div.scrollWidth);
            console.log("scrollHeight:"+div.scrollHeight);
        }
    </script>
</head>
<body>
<div>
    qweqweqqaaaaaaaaaa
    qwewqe
    qwewqe
    qweqwe
    qweqwe
    qweqweq
    qwewqew
    qwewqeqwe
    qweqweqww
    qweqweqw
    qwewqe
    qwewqeqwe
    qweqweqw

</div>
</body>
</html>

这里写图片描述

scrollTop、scrollLeft

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        body {
            height: 5000px;
            width: 5000px;
        }
    </style>
</head>
<body>
<script>
    window.onscroll = function () {
//        console.log(document.body.scrollTop);
        //document.body.scrollTop:网页被卷去的头部
        document.title = document.body.scrollTop + "   " + document.body.scrollLeft;
    }
</script>
</body>
</html>

scrollTop和scrollLeft有兼容性问题:

一、未声明 DTD(谷歌只认识他)
document.body.scrollTop
二、已经声明DTD(IE678只认识他)
document.documentElement.scrollTop
三、火狐/谷歌/ie9+以上支持的
window.pageYOffset

兼容性写法:

<script>
    window.onscroll = function () {
       document.title = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
    }
</script>

scrollTop和scrollLeft方法的封装

<script>
    window.onscroll = function () {
        console.log("left:" + scroll().left + ",right:" + scroll().top);
    }
    function scroll() {
        /*返回json数据*/
        return {
            "top": window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop,
            "left": window.pageXOffset || document.body.scrollLeft || document.documentElement.scrollLeft
        }
    }
</script>

client系列

  1. clientWidth :可视区域的宽
  2. clientHeight:可视区域的高
  3. clientX : 鼠标距离可视区域左侧距离(event调用)
  4. clientY :鼠标距离可视区域上侧距离(event调用)
  5. clientTop 元素的上border
  6. clientLeft 元素的左border

调用者不同,意义不同:
盒子调用:盒子本身的可视区域。
body/html调用:网页可视区域大小。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div {
            width: 100px;
            height: 100px;
            border: 10px solid red;
            padding: 20px;
            margin: 20px;
            background: blue;
        }
    </style>
</head>
<body>
<div></div>
</body>
<script>
    var div = document.getElementsByTagName("div")[0];
    console.log("clientWidth:" + div.clientWidth);
    console.log("clientHeight:" + div.clientHeight);
    console.log("clientTop:" + div.clientTop);
    console.log("clientLeft:" + div.clientLeft);
    div.onclick = function (event) {
        event = event || window.event;
        console.log("clientX:"+event.clientX);
        console.log("clientY:"+event.clientY);
    }
</script>
</html>

这里写图片描述

获取浏览器可视区域宽高:
存在兼容性问题:
IE9以上的版本:window.innerWidth/innerHeight

有DTD:(document.compatMode === “CSS1Compat”)
document.documentElement.clientWidth
document.documentElement.clientHeight

没有DTD:
document.body.clientWidth
document.body.clientHeight

封装(解决兼容性问题)

function client(){
    if(window.innerWidth){
        return {
            "width":window.innerWidth,
            "height":window.innerHeight
        };
    }else if(document.compatMode === "CSS1Compat"){
        return {
            "width":document.documentElement.clientWidth,
            "height":document.documentElement.clientHeight
        };
    }else{
        return {
            "width":document.body.clientWidth,
            "height":document.body.clientHeight
        };
    }
}

示例:

  window.onresize=function () {
      console.log(client().width);
  }

    function client(){
        //判断:如果浏览器支持window.innerWidth,直接用这个方法。不支持再用其他两个方法
        if(window.innerWidth){
            return {
                "width":window.innerWidth,
                "height":window.innerHeight
            };
        }else if(document.compatMode === "CSS1Compat"){
            return {
                "width":document.documentElement.clientWidth,
                "height":document.documentElement.clientHeight
            };
        }else{
            return {
                "width":document.body.clientWidth,
                "height":document.body.clientHeight
            };
        }
    }

这里写图片描述


三大系列总结


width和height

clientWidth  = width  + padding
clientHeight  = height + padding
offsetWidth  = width  + padding + border
offsetHeight  = height + padding + border
scrollWidth   = 内容宽度(不包含border)
scrollHeight  = 内容高度(不包含border)

top和left

offsetTop/offsetLeft :
    调用者:任意元素。(盒子为主)
    距离父系盒子中带有定位的距离。
scrollTop/scrollLeft:(盒子也可以调用,必须有滚动条)
    调用者:document.body.scrollTop/.....(window)
    浏览器无法显示的部分(被卷去的部分)。
clientY/clientX:(clientTop/clientLeft 值的是border值宽度)
    调用者:event.clientX(event)
    鼠标距离浏览器可视区域的距离(左、上)。

动画


js种动画一般分为3种
1. 闪动动画
2. 匀速动画
3. 缓动动画

动画的原理:元素本身的位置+步长;
步长:每次移动的距离


闪动动画
瞬间到达指定位置
示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .box{
            width: 100px;
            height:100px;
            background: red;
            position: absolute;
        }
    </style>
    <script>
        window.onload=function () {
            var box=document.getElementsByClassName("box")[0];
            var btn=document.getElementsByTagName("button")[0];
            btn.onclick=function () {
               box.style.left="200px";//向右移动200px
            }
        }
    </script>
</head>
<body>

<button>闪动动画</button>
<div class="box"></div>
</body>
</html>

闪动动画


匀速动画
每次移动固定距离

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .box{
            width: 100px;
            height:100px;
            background: red;
            position: absolute;
        }
    </style>
    <script>
        window.onload=function () {
            var box=document.getElementsByClassName("box")[0];
            var btn=document.getElementsByTagName("button")[0];
            btn.onclick=function () {
                ani(box)
            }
        }
        function ani(ele) {
            clearInterval(ele.ani);
            ele.ani=setInterval(function () {
                var speed=10;//步长
                ele.style.left=ele.offsetLeft+speed+"px";
            },20);
        }
    </script>
</head>
<body>
<button>匀速动画</button>
<div class="box"></div>
</body>
</html>

匀速动画


缓动动画
开始移动较快,距离终点越近,移动越慢。类似于电梯,刹车。
该动画用的较多,比较符合人类的审美。
公式:
元素位置 = 元素本身位置+(目标位置-元素本身位置)/ 10;

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style>
        div {
            position: absolute;
            width: 100px;
            height: 100px;
            background: pink;
        }
    </style>
</head>
<body>


<button>运动到200</button>
<button>运动到400</button>


<div></div>
</body>


<script>

    var div = document.getElementsByTagName("div")[0];
    var btn = document.getElementsByTagName("button");
    btn[0].onclick = function () {
        ani(div, 200);
    };
    btn[1].onclick = function () {
        ani(div, 400);
    };

    function ani(ele, target) {
        clearInterval(ele.timer);//使用定时器之前先清除
        ele.timer = setInterval(function () {
            var speed = (target - ele.offsetLeft) / 10;//步长
            speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
            ele.style.left = ele.offsetLeft + speed + "px";
            if (Math.abs(target - ele.offsetLeft) <= Math.abs(speed)) {
                //处理小数赋值
                ele.style.left = target + "px";
                clearInterval(timer);
            }
        }, 30);
    }

</script>

</html>

这里写图片描述

事件对象(event)


在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。所有浏览器都支持event对象,但支持的方式不同。
普通浏览器支持 event(带参,任意参数)
ie 678 支持 window.event(无参,内置)
总结:他是一个事件中的内置对象。内部装了很多关于鼠标和事件本身的信息。

事件对象的获取
兼容写法:

 //参数名可以是别的
document.onclick = function (event){
 event = event || window.event; //兼容写法;
console.log(event);
}

事件对象的属性:

    <script>
        document.onclick = function (event) {
            //兼容性写法:
            event = event || window.event; //兼容写法;
            console.log(event.timeStamp);     //返回事件生成的日期和时间。(页面加载完毕后开始计算)
            console.log(event.bubbles);     //返回布尔值,指示事件是否是起泡事件类型。
            console.log(event.button);     //返回当事件被触发时,哪个鼠标按钮被点击。
            console.log(event.pageX);     //光标相对于该网页的水平位置(ie无)
            console.log(event.pageY);     //光标相对于该网页的垂直位置(ie无)
            console.log(event.screenX);     //光标相对于该屏幕的水平位置
            console.log(event.screenY);     //光标相对于该屏幕的垂直位置
            console.log(event.target);     //该事件被传送到的对象
            console.log(event.type);     //事件的类型
            console.log(event.clientX);     //光标相对于该网页的水平位置 (当前可见区域)
            console.log(event.clientY);     //光标相对于该网页的垂直位置

        }
    </script>

这里写图片描述

event常用属:

event.clientX/event.clientY——触发事件时,鼠标的X轴和Y轴坐标(以可视区左上角开始计算)
event.target ——在鼠标事件触发时,指向触发该事件的目标元素
event.keyCode ——当前按下按键的键值
event.ctrlKey——事件触发时,ctrl键是否被按下,true按下,false未按下
event.shiftKey——事件触发时,shift键是否被按下,true按下,false未按下
event.altKey——事件触发时,alt键是否被按下,true按下,false未按下

screenX、pageX和clientX的区别

pageY/pageX: 鼠标位于整个网页页面的顶部和左侧部分的距离。(页面)
screenY/screenX: 鼠标位于屏幕的上方和左侧的距离。(屏幕)
clientX/clientY: 鼠标位于浏览器的左侧和顶部的距离。(浏览器大小和位置)

    <script>
        document.onclick = function (event) {
            //兼容性写法:
            event = event || window.event; //兼容写法;
            console.log("time:" + event.timeStamp);     //返回事件生成的日期和时间。(页面加载完毕后开始计算)
            console.log("冒泡:" + event.bubbles);     //返回布尔值,指示事件是否是起泡事件类型。
            console.log("鼠标键" + event.button);     //返回当事件被触发时,哪个鼠标按钮被点击。
            console.log("pageX:"+event.pageX);     //光标相对于该网页的水平位置(ie无)
            console.log("pageY:" + event.pageY);     //光标相对于该网页的垂直位置(ie无)
            console.log("screenX:" + event.screenX);     //光标相对于该屏幕的水平位置
            console.log("screenY:" + event.screenY);     //光标相对于该屏幕的垂直位置
            console.log("target:" + event.target);     //该事件被传送到的对象
            console.log("type:" + event.type);     //事件的类型
            console.log("clientX:" + event.clientX);     //光标相对于该网页的水平位置 (当前可见区域)
            console.log("clientY:" + event.clientY);     //光标相对于该网页的垂直位置
        }
    </script>

这里写图片描述

鼠标距离整个页面的距离、和距离可视区的距离有时候是相等的
当页面有被卷去的头部或者左侧的时候,这两个值就不相等了。
由此,我们可以得出:
鼠标位于整个页面的距离(pageY/X) = 鼠标位于可视区域的距离(clientY/X) + 页面被卷去的头部或者左侧的距离(scrollTop/Left)

pageX/pageY低版本浏览器(IE67)不支持,下面是兼容写法:

document.onclick = function (event) {
    //获取事件对象
    event = event || window.event;

    //鼠标位于整个页面的坐标,兼容IE678
    var pagex = event.pageX || event.clientX + scroll().left;
    var pageY = event.pageY || event.clientY +scroll().top;

    console.log(pagex); //值不带px
    console.log(pagey);
}

事件的冒泡和捕获

任何发生在w3c事件模型中的事件,首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段 。

事件捕获阶段:事件从最上一级标签开始往下查找,直到捕获到事件目标(target)。
事件冒泡阶段:事件从事件目标(target)开始,往上冒泡直到页面的最上一级标签。

传统的事件绑定方法是
element1.onclick = doSomething2;
默认被视为在绑定于冒泡阶段
示例:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        .box1 {
            width: 500px;
            height: 500px;
            background-color: pink;
        }

        .box2 {
            width: 300px;
            height: 300px;
            background-color: yellow;
        }

        .box3 {
            width: 100px;
            height: 100px;
            background-color: blue;
        }


    </style>
</head>
<body>

<div class="box1" id="box1">
    <div class="box2">
        <div class="box3"></div>
    </div>
</div>

<script>

    var box1 = document.getElementById("box1");
    var box2 = box1.children[0];
    var box3 = box2.children[0];
    box1.onclick = function () {
        alert("我是box1");
    }
    box2.onclick = function () {
        alert("我是box2");
    }

    box3.onclick = function () {
        alert("我是box3");
    }

    document.onclick = function () {
        alert("我是document");
    }
</script>

</body>
</html>

事件冒泡

如果使用element.addEventListener()这种方式绑定事件的话,我们可以通过设置第三个参数来控制是冒泡还是捕获。
addEventListener第三个参数默认值是false。
false:冒泡
true:捕获

示例:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        .box1 {
            width: 500px;
            height: 500px;
            background-color: pink;
        }

        .box2 {
            width: 300px;
            height: 300px;
            background-color: yellow;
        }

        .box3 {
            width: 100px;
            height: 100px;
            background-color: blue;
        }


    </style>
</head>
<body>

<div class="box1" id="box1">
    <div class="box2">
        <div class="box3"></div>
    </div>
</div>

<script>

    var box1 = document.getElementById("box1");
    var box2 = box1.children[0];
    var box3 = box2.children[0];

    box1.addEventListener("click", function () {
        alert("我是box1");
    }, true);

    box2.addEventListener("click", function () {
        alert("我是box2");
    }, true);

    box3.addEventListener("click", function () {
        alert("我是box3");
    }, true);

    document.addEventListener("click", function () {
        alert("我是document");
    }, true);


</script>

</body>
</html>

事件捕获

当使用事件捕获时(true),父级元素先触发,子元素后触发
当使用事件冒泡时(false),子级元素先触发,父元素后触发

注意:并不是所有的事件都支持事件冒泡。例如:

阻止事件冒泡
当父元素也有和子元素同样类型的事件,但你在调用子元素事件的时候不想触发父元素事件的时,要阻止冒泡。
w3c的方法是:(火狐、谷歌、IE11)
event.stopPropagation()
IE10以下则是使用:event.cancelBubble = true

兼容写法:

  var event = event || window.event;
 if(event && event.stopPropagation){
            event.stopPropagation();
  }else{
            event.cancelBubble = true;
  }

示例:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        .box1 {
            width: 500px;
            height: 500px;
            background-color: pink;
        }

        .box2 {
            width: 300px;
            height: 300px;
            background-color: yellow;
        }

        .box3 {
            width: 100px;
            height: 100px;
            background-color: blue;
        }


    </style>
</head>
<body>

<div class="box1" id="box1">
    <div class="box2">
        <div class="box3"></div>
    </div>
</div>

<script>

    var box1 = document.getElementById("box1");
    var box2 = box1.children[0];
    var box3 = box2.children[0];

    //    冒泡和捕获
    box1.onclick = function (event) {
        event = event || window.event;
        if (event && event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }

        alert("我是box1");
    }

    box2.onclick = function (event) {
        event = event || window.event;
        if (event && event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
        alert("我是box2");
    }

    box3.onclick = function (event) {
        event = event || window.event;
        if (event && event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
        alert("我是box3");
    }

    document.onclick = function (event) {
        event = event || window.event;
        if (event && event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
        alert("我是document");
    }


</script>

</body>
</html>

阻止冒泡

事件委托
事件委托其实就是利用事件冒泡原理。从点击的元素开始,递归方式的向父元素传播事件,这样做的好处是对于大量要处理的元素,不必为每个元素都绑定事件,只需要在他们的父元素上绑定一次即可,提高性能。 还有一个好处就是可以处理动态插入dom中的元素,直接绑定的方式是不行的。

简单来说就是目标本事不处理事件,而是把事件任务委托给其父元素或祖先元素,当子元素被点击时,通过事件冒泡的特性,其父元素或捕获到该事件,执行相应方法。

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件委托</title>

    <style>

        ul {
            margin: 0;
            list-style: none;
        }

        li {
            margin: 0;
            padding: 0;
            background: lightgray;
            width: 100px;
            line-height: 30px;
        }
    </style>

    <script>
        /*事件委托*/
        window.onload = function () {
            var ul = document.getElementsByTagName("ul")[0];
            ul.onclick = function (event) {
                event = event || window.event;
                var target = event.target || event.srcElement;//获取事件源
                if (target.nodeName.toLowerCase() == "li") {
                    alert(target.innerHTML);
                }
            }
        }
    </script>
</head>
<body>
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
</ul>
</body>
</html>

这里写图片描述

如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可。也可以关注我web前端的博客专栏,我会不定期的更新,如果文中有什么错误的地方,还望指正,谢谢!

©️2020 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值