JavaScript---PC端网页特效---偏移量offset、可视区client、滚动scroll---1.29

元素偏移量offset系列

offset概述

offset就是偏移量,使用offset系列相关属性可以动态的得到该元素的位置(偏移)、大小等。

  • son.offsetParent:返回带有定位的父亲,父亲没有定位则返回body
  • son.parentNode:返回最近一级的父亲,不管父亲有没有定位

offset与style的区别

案例:获取鼠标在盒子内的坐标

  • 首先得到鼠标在页面中的坐标(e.pageX,e.pageY)
  • 其次得到盒子在页面中的距离(box.offsetLeft,box.offsetTop)
  • 用鼠标距离页面的坐标减去盒子在页面中的距离,得到鼠标在盒子内的坐标
<style>
    .box {width: 200px;height: 200px;margin: 100px;background-color: pink;}
</style>
<div class="box"></div>
<script>
    var box = document.querySelector('.box');
    box.addEventListener('mousemove',function(e) {
        // console.log(e.pageX);
        // console.log(e.pageY);
        // console.log(box.offsetLeft);
        // console.log(box.offsetTop);
        var x = e.pageX-this.offsetLeft;
        var y = e.pageY-this.offsetTop;
        this.innerHTML = 'X坐标是' + x +' Y坐标是' + y;
    });
</script>

案例:模拟框拖拽(弹出框也称为模态框。)

  • 点击弹出层,模态框和遮挡层就会显示 display:block
  • 点击关钮闭按,模态框和遮挡层就会隐藏 display:none
  • 在页面中拖拽的原理:鼠标按下并且移动,之后松开鼠标
  • 触发事件是鼠标按下 mousedown,鼠标移动 mousemove,鼠标松开 mouseup
  • 拖拽过程:鼠标移动过程中,获得最新的值,赋值给模态框的left和top值,模态框就可以跟着鼠标走
  • 鼠标按下触发的事件源是最上面一行,id为title
  • 鼠标的坐标减去鼠标在盒子内的坐标,才是模态框真正的位置
  • 鼠标按下,我们要得到鼠标在盒子的坐标。
  • 鼠标移动,就让模态框的坐标设置为:鼠标坐标减去盒子坐标即可,注意移动事件写到按下事件里面
  • 鼠标松开,就停止拖拽,让鼠标移动事件解除
<style>
    * {margin: 0;padding: 0;}
    .login-header {text-align: center;}
    .login-title {width: 100%;margin: 10px 0 0 0;text-align: center;
            line-height: 40px;font-size: 18px;position: relative;
            cursor: move;
    }
    .login-input-content {margin-top: 20px;}
    .login-button {width: 50%;margin: 30px auto 0 auto;line-height: 40px;
            font-size: 14px;border: #ebebeb 1px solid;text-align: center;
    }
    .login-button a {display: block;}
    .login-input input.list-input {float: left;line-height: 35px;height: 35px;
            width: 350px;border: 1px solid #ebebeb;text-indent: 5px;
    }
    .login-input {overflow: hidden;margin: 0 0 20px 0;}
    .login-input label {float: left;width: 90px;padding-right: 10px;
            text-align: right;line-height: 35px;height: 35px;font-size: 14px;
    }
    h6,a {padding: 0;margin: 0;}
    .login {display: none;width: 512px;height: 280px;position: fixed;
            border: 1px solid #ebebeb;left: 50%;top: 50%;
            background-color: #ffffff;box-shadow: 0 0 20px #ddd;
            z-index: 9999;transform: translate(-50%, -50%);
    }
    .login-title {width: 100%;margin: 10px 0 0 0;text-align: center;
            line-height: 40px;height: 40px;font-size: 18px;position: relative;
    }
    .login-title span {position: absolute;font-size: 12px;right: -20px;
            top: -30px;background-color: #ffffff;border: 1px solid #ebebeb;
            width: 40px;height: 40px;border-radius: 20px;
    }
    .sk {line-height: 40px;font-size: 14px;
            border: 1px solid #ebebeb;text-align: center;
     }
    .login-bg {display: none;width: 100%;height: 100%;position: fixed;
            left: 0;top: 0;background-color: rgba(0, 0, 0, 0.3);
    }
    a {text-decoration: none;color: #222222;}
</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.点击弹出这个链接 link 让 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.开始拖拽
  //当我们鼠标按下,就获得鼠标在盒子内的坐标 
  title.addEventListener('mousedown',function(e) {
       var x = e.pageX-login.offsetLeft;
       var y = e.pageY-login.offsetTop;
       //鼠标移动的时候,把鼠标在页面中的坐标,减去 鼠标在盒子内的坐标就是模态框的left和top
       document.addEventListener('mousemove',move);
       function move(e) {
            login.style.left = e.pageX-x+'px';
            login.style.top = e.pageY-y+'px';
       }
       //鼠标弹起,就让鼠标移动事件移除
       document.addEventListener('mouseup',function() {
            document.removeEventListener('mousemove',move);
        });
    })
</script>

案例:仿京东放大镜

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {position: relative;width: 300px;height: 200px;}
        .pre {width: 100%;}
        .mask {display: none;position: absolute;top: 0px;left: 0px;
            width: 150px;height: 150px;background-color: pink;
            opacity: 0.7;
        }
        .big {display: none;position: absolute;top: 0px;left: 310px;
            width: 400px;height: 400px;background-color: pink;
            border: 1px solid #ccc;overflow: hidden;
        }
        .bigtu {position: absolute;top: 0px;left: 0px;}
        .box:hover {cursor: move;}
    </style>
</head>
<body>
    <div class="box">
        <img src="images/iPhone.jpg" class="pre">
        <div class="mask"></div>
        <div class="big">
            <img src="images/iPhone.jpg" class="bigtu">
        </div>
    </div>
    <script>
        //1、鼠标进入小盒子,遮罩层、大盒子出现
        var box = document.querySelector('.box');
        var mask = document.querySelector('.mask');
        var big = document.querySelector('.big');
        var bigtu = document.querySelector('.bigtu');
        box.addEventListener('mouseover', function() {
                mask.style.display = 'block';
                big.style.display = 'block';
            })
        //2、鼠标离开小盒子地时候,遮罩层、大盒子隐藏
        box.addEventListener('mouseout', function() {
                mask.style.display = 'none';
                big.style.display = 'none';
            })
        //3、添加移动效果,遮罩层跟随鼠标移动,鼠标在小盒子的坐标就是遮罩层的位置
        box.addEventListener('mousemove', function(e) {
            //求鼠标在小盒子里的坐标
            var x = e.pageX - this.offsetLeft;
            var y = e.pageY - this.offsetTop;
            //将鼠标地坐标给遮罩层
            // mask.style.left = x + 'px'
            // mask.style.top = y + 'px'
            //鼠标应该位于遮罩层地中心位置,maskx和masky为遮挡层可移动的距离
            var maskx = x - mask.offsetWidth / 2;
            var masky = y - mask.offsetHeight / 2;
            //约束遮罩层移动范围,也就是约束鼠标位置
            if (maskx <= 0) {
                maskx = 0;
            } else if(maskx >= box.offsetWidth - mask.offsetWidth) {
                maskx = box.offsetWidth - mask.offsetWidth;
            }
            if (masky <= 0) {
                masky = 0;
            } else if(masky >= box.offsetHeight - mask.offsetHeight) {
                masky = box.offsetHeight - mask.offsetHeight;
            }
            mask.style.left = maskx + 'px';
            mask.style.top = masky + 'px';
            //让大盒子里的图片跟随移动,加相对定位
            //原理:鼠标在小盒子里移动距离与鼠标在大盒子里移动距离成比例
            //大图片的移动距离bigtux=遮挡层移动距离*大图片最大移动距离/遮挡层的最大移动距离
            var bigtux = maskx * (big.offsetWidth - bigtu.offsetWidth) / (box.offsetWidth - mask.offsetWidth);
            var bigtuy = masky * (big.offsetHeight - bigtu.offsetHeight) / (box.offsetHeight - mask.offsetHeight);
            bigtu.style.left = bigtux + 'px';
            bigtu.style.top = bigtuy + 'px';
            //应该也要对大盒子里面地图片移动范围进行约束
            //忽视了一点:bigtu图大小是450*450,大盒子应该小于450*450;这样图片在大盒子里才有移动余地
        })
    </script>
</body>
</html>

元素可视区client系列

client翻译过来就是客户端,使用client系列的相关属性来获取元素可视区的相关信息。可以动态的得到该元素的边框大小、元素大小等。

 淘宝flexible.js源码分析

// 立即执行函数(function() {})(),不需要调用就能执行
(function flexible(window,document) {
    var docEl = document.documentElement;
    var dpr = window.devicePixelRatio || 1;//dpr物理像素比
    
    //adjust body font size.
    function setBodyFontSize() {
        if (document.body) {//判断页面中是否有body元素
            document.body.style.fontSize = (12*dpr)+'px';
        } else {
            // 没有body元素,就等页面主要的DOM元素加载完毕再设置body大小
            document.addEventListener('DOMContentLoaded',setBodyFontSize);
        }
    }
    setBodyFontSize();

    //set html  1rem = viewWidth / 10
    function setRemUnit() {
        var rem = docEl.clientwidth / 10;
        docEl.style.fontSize = rem +'px';
    }
    setRemUnit();

    //reset rem unit on page resize  页面尺寸变化时,重置rem
    window.addEventListener('resize',setRemUnit);
    //页面重新加载触发pageshow事件
    window.addEventListener('pageshow',function(e) {
        //如页面是从缓存取过来的页面,也需要重新计算rem的大小
        if (e.persisted) {
            setRemUnit();
        }
    });

    //有些移动端的浏览器不支持0.5像素的写法   以下是解决办法
    //detect 0.5px supports  
    if (dpr >= 2) {
        var fakeBody = document.createElement('body');
        var testElement = document.createElement('div');
        testElement.style.border ='.5px solid transparent';
        fakeBody.appendChild(testElement);
        docEl.appendChild(fakeBody)
        if (testElement.offsetHeight === 1) {
            docEl.classList.add('hairlines');
        }
        docEl.removeChild(fakeBody);
    }
})(window,document);

元素滚动scroll系列

元素scroll系列属性

scroll翻译过来就是滚动,使用scroll系列的相关属性可以动态的得到该元素的大小、滚动距离等。

 

页面被卷去的头部

浏览器的高度或宽度不足以显示整个页面时,会自动出现滚动条。当滚动条向下滚动时,页面上面被隐藏掉的高度,就称为页面被卷去的头部。滚动条在滚动时会触发onscroll事件

<style>
    div {width: 100px;height: 100px;background-color: pink;
        overflow: auto;padding: 10px;border: 10px solid #ccc;
        }
</style>
<div>内容内容内容内容内容内容内容内容内容内容内容内容内容内容</div>
<script>
    var div = document.querySelector('div');
    console.log(div.scrollHeight);
    console.log(div.clientHeight);
    // scroll滚动事件:当我们滚动条发生变化会触发的事件
    div.addEventListener('scroll',function() {
        console.log(div.scrollTop);
    })
</script>

案例:仿淘宝固定右侧侧边栏

  • 原先侧边栏是绝对定位,当页面滚动到一定位置,侧边栏改为固定定位,页面继续滚动,会让"返回顶部"显示出来
  • 需要用到页面滚动事件scroll因为是页面滚动,所以事件源是页面document
  • 滚动到某个位置,就是判断页面被卷去的上部值
  • 页面被卷去的头部:可以通过window.pageYOffset获得,如果是被卷去的左侧:window.pageXOffset
  • 注意:元素被卷去的头部:element.scrollTop页面被卷去的头部:window.pageYOffset
<style>
    .slider-bar {position: absolute;left: 50%;top: 300px;
        margin-left: 600px;width: 45px;height: 130px;
        background-color: pink;
    }
    .w {width: 1200px;margin: 10px auto;}
    .header {height: 150px;background-color: purple;}
    .banner {height: 250px;background-color: skyblue;}
    .main {height: 800px;background-color: yellow;}
    span {display: none;position: absolute;bottom: 0;}
</style>
<div class="slider-bar">
    <span class="goback">返回顶部</span>
</div>
<div class="header w">头部区域</div>
<div class="banner w">banner区域</div>
<div class="main w">主体部分</div>
<script>
    var sliderbar = document.querySelector('.slider-bar');
    var banner = document.querySelector('.banner');
    var bannerTop = banner.offsetTop;//banner.offsetTop就是被卷去头部的大小
    //sliderbarTop是当我们侧边栏固定定位后应该变化的数值
    var sliderbarTop = sliderbar.offsetTop-bannerTop;
    var main = document.querySelector('.main');
    var goback = document.querySelector('.goback');
    var mainTop = main.offsetTop;
    document.addEventListener('scroll',function() {
        //当页面被卷去的头部大于bannertop就改为固定定位
        if(window.pageYOffset >= bannerTop) {
            sliderbar.style.position = 'fixed';
            sliderbar.style.top = sliderbarTop + 'px';
        } else {
            sliderbar.style.position = 'absolute';
            sliderbar.style.top = '300px';
        }
        // 当页面滚动到main盒子,就显示goback模块
        if(window.pageYOffset >= mainTop) {
            goback.style.display = 'block';
        } else {
            goback.style.display = 'none';
        }
    })
</script>

三大系列总结

 

 

 

主要用法:

  • offset系列经常用于获得元素位置 offsetLeft、offsetTop
  • client经常用于获取元素大小 clientWidth、clientHeight
  • scroll经常用于获取滚动距离 scrollTop、scrollLeft
  • 注意:页面滚动的距离通过 window.pageXOffset 获得

mouseenter和mouseover的区别

  • mouseover鼠标经过自身盒子会触发,经过子盒子还会触发。
  • mouseenter只会经过自身盒子触发。
  • 之所以这样,就是因为mouseenter不会冒泡
  • 跟mouseenter搭配,鼠标离开mouseleave同样不会冒泡。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值