javascript- PC端特效(一)

元素偏移量offset

动态的得到该元素的位置、大小等
  • 获取元素距离带有定位的父元素的位置
  • 获取元素自身的大小
<style>
        * {
            margin: 0;
            padding: 0;
        }

        .father {
            width: 200px;
            height: 200px;
            background-color: pink;
            margin: 100px;
            padding: 20px;
        }

        .son {
            width: 100px;
            height: 100px;
            background-color: blue;
            margin: 45px;
        }
    </style>
<div class="father">
        <div class="son"></div>
    </div>
    <script>
        var father = document.querySelector('.father');
        var son = document.querySelector('.son');
        //可以得到元素的偏移 位置 返回的不带单位的数值
        console.log(father.offsetTop);
        //它以带有定位的父亲为准 如果没有父亲或者父亲没有定位 则已body为准
        console.log(son.offsetTop);
        console.log(son.offsetLeft);

        //可以得到元素的大小 宽度高度 包含padding+border+width
        console.log(father.offsetWidth);
        //3.返回带有定位的父亲,否认返回的body
        console.log(son.offsetParent);//父亲必须带有定位才返回
        console.log(son.parentNode);//返回父亲 最近一级的父亲
    </script>
offset和style的区别
offset:
  • 可以得到任意样式表中的样式值
  • 获得的数值没有单位
  • offsetWidth包含padding+border+width
  • offsetWidth等属性是只读属性,只能获取不能赋值
所以我们想要获取元素大小位置,用offset更合适
style:
  • 只能得到行内样式表中的样式值
  • style.width获得的是带有单位的字符串
  • style.width获得不包含padding和border值
  • style.width是可读属性,可以获得也可以赋值
所以,我们想要给元素更改值,则需要用style
 

案例:获取位置

  1. 我们在盒子内点击,想要得到鼠标距离盒子左右的距离
  2. 首先得到鼠标在页面的坐标(e.pageX,e.pageY)
  3. 其次得到盒子在页面中的距离(box.offsetLeft,box.offsetTop)
  4. 用鼠标距离页面的坐标减去盒子在页面中的距离,得到鼠标在盒子内的坐标
 

案例:拖动的模块框

  1. 点击弹出层,模态框和遮挡层就会显示出来display:block;
  2. 点击关闭按钮,模态框和遮挡层就会隐藏起来display:none;
  3. 在页面中拖拽的原理:鼠标按下并且移动,之后松开鼠标
  4. 触发事件是鼠标mousedown,鼠标移动mousemove,鼠标松开mouseup
  5. 拖拽过程:鼠标移动过程中,获得最新的值赋值给模态框的left和top值,这样就可以跟着鼠标走了
  6. 鼠标按下触发的事件源是最上面的一行,就是id为title
  7. 鼠标的坐标减去鼠标在盒子内的坐标,才是模态框真正的位置
  8. 鼠标按下,我们要得到鼠标在盒子的坐标
  9. 鼠标移动,就让模态框的坐标设置为:鼠标坐标减去盒子坐标即可,注意移动事件写到按下事件里面。
  10. 鼠标松开,就停止拖拽,就是可以让鼠标移动事件解除
<style>
        .login-header {
            width: 100%;
            text-align: center;
            height: 30px;
            font-size: 24px;
            line-height: 30px;
        }

        ul,
        li,
        ol,
        dl,
        dt,
        dd,
        div,
        p,
        span,
        h1,
        h2,
        h3,
        h4,
        h5,
        h6,
        a {
            padding: 0px;
            margin: 0px;
        }

        .login {
            display: none;
            width: 512px;
            height: 280px;
            position: fixed;
            border: #ebebeb solid 1px;
            left: 50%;
            top: 50%;
            background: #ffffff;
            box-shadow: 0px 0px 20px #ddd;
            z-index: 9999;
            transform: translate(-50%, -50%);
        }

        .login-title {
            width: 100%;
            margin: 10px 0px 0px 0px;
            text-align: center;
            line-height: 40px;
            height: 40px;
            font-size: 18px;
            position: relative;
            cursor: move;
        }

        .login-input-content {
            margin-top: 20px;
        }

        .login-button {
            width: 50%;
            margin: 30px auto 0px auto;
            line-height: 40px;
            font-size: 14px;
            border: #ebebeb 1px solid;
            text-align: center;
        }

        .login-bg {
            display: none;
            width: 100%;
            height: 100%;
            position: fixed;
            top: 0px;
            left: 0px;
            background: rgba(0, 0, 0, .3);
        }

        a {
            text-decoration: none;
            color: #000000;
        }

        .login-button a {
            display: block;
        }

        .login-input input.list-input {
            float: left;
            line-height: 35px;
            height: 35px;
            width: 350px;
            border: #ebebeb 1px solid;
            text-indent: 5px;
        }

        .login-input {
            overflow: hidden;
            margin: 0px 0px 20px 0px;
        }

        .login-input label {
            float: left;
            width: 90px;
            padding-right: 10px;
            text-align: right;
            line-height: 35px;
            height: 35px;
            font-size: 14px;
        }

        .login-title span {
            position: absolute;
            font-size: 12px;
            right: -20px;
            top: -30px;
            background: #ffffff;
            border: #ebebeb solid 1px;
            width: 40px;
            height: 40px;
            border-radius: 20px;
        }
    </style>   
<div class="login-header"><a id="link" href="javascript:;">点击,弹出登录框</a></div>
    <div id="login" class="login">
        <div id="title" class="login-title">登录会员
            <span><a id="closeBtn" href="javascript:void(0);" class="close-login">关闭</a></span>
        </div>
        <div class="login-input-content">
            <div class="login-input">
                <label>用户名:</label>
                <input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input">
            </div>
            <div class="login-input">
                <label>登录密码:</label>
                <input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="list-input">
            </div>
        </div>
        <div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登录会员</a></div>
    </div>
    <!-- 遮盖层 -->
    <div id="bg" class="login-bg"></div>
    <script>
        //1.获取元素
        var login = document.querySelector('.login');
        var mask = document.querySelector('.login-bg');
        var link = document.querySelector('#link');
        var closeBtn = document.querySelector('#closeBtn');
        var title = document.querySelector('#title');
        //2.添加点击事件让mask和login显示出来
        link.addEventListener('click', function () {
            mask.style.display = 'block';
            login.style.display = 'block';
        });
        //3.点击closeBtn就隐藏,mask和login
        closeBtn.addEventListener('click', function () {
            mask.style.display = 'none';
            login.style.display = 'none';
        });
        //4.开始拖拽
        //(1)当鼠标按下就获得鼠标在盒子内的坐标
        title.addEventListener('mousedown', function (e) {
            var x = e.pageX - login.offsetLeft;
            var y = e.pageY - login.offsetTop;
            //(2)鼠标移动的时候,把鼠标在页面中的坐标减去鼠标在盒子内的坐标就是模态框的left和top
            document.addEventListener('mousemove', move)
            function move(e) {
                login.style.left = e.pageX - x + 'px';
                login.style.top = e.pageY - y + 'px';

            }
            //(3)鼠标弹起,让事件移除
            document.addEventListener('mouseup', function () {
                document.removeEventListener('mousemove', move)
            })
        });
    </script>

元素的可视区client系列

<style>
        div {
            width: 100px;
            height: 100px;
            background-color: pink;
            border: 10px solid red;
        }
    </style>
    <div></div>
    <script>
        var div = document.querySelector('div');
        console.log(div.clientWidth);
    </script>
立即执行函数(function(){})()
主要作用:创建一个独立的作用域
<script>
        //立即执行函数:不需要调用,立马能够自己执行的函数
        function fn() {
            console.log(1);
        }
        fn();
        //2.写法 也可以传递参数进去
        (function (a, b) {
            console.log(a + b);
        })(3, 4); //第二个小括号可以看错是调用函数

        ((function sum(a, b) {
            console.log(a + b);

        })(2, 3))
        //3.立即执行函数最大的作用就是独立创建一个作用域,里面里面的所有变量都是局部变量不会有命名冲突
    </script>

scroll系列 

使用scroll系列的相关属性可以动态的得到该元素的大小、滚动距离
<script>
        var div = document.querySelector('div');
        console.log(div.scrollHeight);
        console.log(div.clientHeight);
        //滚动事件当滚动条发生滚动触发事件
        document.addEventListener('scroll', function () {
            console.log(div.scrollTop);
        });
    </script>

案例:仿淘宝侧边栏

 需要用到页面滚动事件scroll因为是页面滚动,所以事件源是document
滚动到某个位置,就是判断页面被卷去的上部值
页面被卷去的头部:可以通过window.pageYOffset获得 如果是被卷去的左侧 window.pageXOffset
注意,元素被卷去的头部是element.scroll Top
<script>
        //1. 获取元素
        var sliderbar = document.querySelector('.slider-bar');
        var banner = document.querySelector('.banner');
        // banner.offestTop 就是被卷去头部的大小 一定要写到滚动的外面
        var bannerTop = banner.offsetTop
            // 当我们侧边栏固定定位之后应该变化的数值
        var sliderbarTop = sliderbar.offsetTop - bannerTop;
        // 获取main 主体元素
        var main = document.querySelector('.main');
        var goBack = document.querySelector('.goBack');
        var mainTop = main.offsetTop;
        // 2. 页面滚动事件 scroll
        document.addEventListener('scroll', function() {
            // console.log(11);
            // window.pageYOffset 页面被卷去的头部
            // console.log(window.pageYOffset);
            // 3 .当我们页面被卷去的头部大于等于了 172 此时 侧边栏就要改为固定定位
            if (window.pageYOffset >= bannerTop) {
                sliderbar.style.position = 'fixed';
                sliderbar.style.top = sliderbarTop + 'px';
            } else {
                sliderbar.style.position = 'absolute';
                sliderbar.style.top = '300px';
            }
            // 4. 当我们页面滚动到main盒子,就显示 goback模块
            if (window.pageYOffset >= mainTop) {
                goBack.style.display = 'block';
            } else {
                goBack.style.display = 'none';
            }

        })
    </script>

总结:

mouseenter和mouseover的区别
  • 当鼠标移动到元素上时就会触发mouseenter事件
  • 类似mouseover,它们两者之间的差别就是,mouseover鼠标经过自身的盒子会触发,经过子盒子也会触发。mouseenter只会经过自身盒子触发。


动画实现原理

核心原理:通过定时器setInterval()不断移动盒子位置
实现步骤:
    1. 获得盒子当前位置
    2. 让盒子在当前位置加上1个移动距离
    3. 利用定时器不断重复这个操作
    4. 加一个结束定时器
    5. 需要添加定位
 <style>
        div {
            position: absolute;
            left: 0;
            width: 100px;
            height: 100px;
            background-color: pink;
        }
    </style>    <div></div>
    <script>
        var div = document.querySelector('div');
        var timer = setInterval(function () {
            if (div.offsetLeft >= 400) {
                //stop 本质停止定时器
                clearInterval(timer);
            }
            div.style.left = div.offsetLeft + 1 + 'px';
        }, 30);
    </script>

动画函数简单封装

传递两个参数 动画对象和移动的距离
<div></div>
    <span>xiayuhe</span>
    <script>
        //目标对象,目标位置
        function animate(obj, target) {

            var timer = setInterval(function () {
                if (obj.offsetLeft >= target) {
                    //stop 本质停止定时器
                    clearInterval(timer);
                }
                obj.style.left = obj.offsetLeft + 1 + 'px';
            }, 30);
        }
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        // animate(div, 300);
        animate(span, 200);
    </script>

给不同元素记录不同的计时器

 <div></div>
    <span>夏雨荷</span>
    <button>点击夏雨荷触发</button>
    <script>
        //目标对象,目标位置
        function animate(obj, target) {
            //当我们不断的点击按钮,这个元素的速度会越来越快,因为开启了太多的定时器
            //解决方案,让我们的元素只有一个定时器执行
            //先清除以前的定时器,只保留一个定时器执行
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {
                if (obj.offsetLeft >= target) {
                    //stop 本质停止定时器
                    clearInterval(timer);
                }
                obj.style.left = obj.offsetLeft + 1 + 'px';
            }, 30);
        }
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        var btn = document.querySelector('button');
        animate(div, 300);
        btn.addEventListener('click', function () {
            animate(span, 200);
        });
    </script>

 

缓动动画效果

  1. 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来
  2. 核心算法:(目标值-现在的位置)/10 作为每次移动的距离步长
  3. 停止条件是:让当前盒子位置等于目标位置就停止定时器
<div></div>
    <span>夏雨荷</span>
    <button>点击夏雨荷触发</button>
    <script>
        //目标对象,目标位置
        function animate(obj, target) {
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {
                var step = (target - obj.offsetLeft) / 10;
                if (obj.offsetLeft == target) {
                    //stop 本质停止定时器
                    clearInterval(timer);
                }
                //把每次+1的步长值改为一个慢慢变小的值
                obj.style.left = obj.offsetLeft + step + 'px';
            }, 30);
        }
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        var btn = document.querySelector('button');
        animate(div, 300);
        btn.addEventListener('click', function () {
            animate(span, 200);
        });
        //匀速动画就是盒子当前的位置+固定的值10
        //缓动动画就是盒子当前的位置+变化的值((目标值-现在的位置)/10)
    </script>
动画函数多个目标值之间移动
可以让动画从800移动到500
判断是正值还是负值
1.如果是正值,则步长往大取整
2.如果是负值,则步长往小取整
<span>夏雨荷</span>
    <button class="btn500">点击夏雨荷触发500</button>
    <button class="btn800">点击夏雨荷触发800</button>
    <script>
        //目标对象,目标位置
        function animate(obj, target) {
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {
                //把步长改为整数
                var step = (target - obj.offsetLeft) / 10;
                step = step > 0 ? Math.ceil(step) : Math.floor(step);
                if (obj.offsetLeft == target) {
                    //stop 本质停止定时器
                    clearInterval(timer);
                }
                //把每次+1的步长值改为一个慢慢变小的值
                obj.style.left = obj.offsetLeft + step + 'px';
            }, 30);
        }
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        var btn500 = document.querySelector('.btn500');
        var btn800 = document.querySelector('.btn800');
        animate(div, 300);
        btn500.addEventListener('click', function () {
            animate(span, 500);
        });
        btn800.addEventListener('click', function () {
            animate(span, 800);
        });
        //匀速动画就是盒子当前的位置+固定的值10
        //缓动动画就是盒子当前的位置+变化的值((目标值-现在的位置)/10)
    </script>
动画函数添加回调函数
原理:函数可以作为一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数。
 
动画函数封装到单独JS文件里
创建一个JS文件
function animate(obj, target, callback) {
    // console.log(callback);  callback = function() {}  调用的时候 callback()

    // 先清除以前的定时器,只保留当前的一个定时器执行
    clearInterval(obj.timer);
    obj.timer = setInterval(function() {
        // 步长值写到定时器的里面
        // 把我们步长值改为整数 不要出现小数的问题
        // var step = Math.ceil((target - obj.offsetLeft) / 10);
        var step = (target - obj.offsetLeft) / 10;
        step = step > 0 ? Math.ceil(step) : Math.floor(step);
        if (obj.offsetLeft == target) {
            // 停止动画 本质是停止定时器
            clearInterval(obj.timer);
            // 回调函数写到定时器结束里面
            // if (callback) {
            //     // 调用函数
            //     callback();
            // }
            callback && callback();
        }
        // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
        obj.style.left = obj.offsetLeft + step + 'px';

    }, 15);
}
返回顶部
滚动窗口至文档中的特定位置
Window.scroll(x,y)
 
posted @ 2022-03-29 00:34  终究还是避免不了遗憾  阅读(72)  评论(0编辑  收藏  举报