Web APIs:PC 端网页特效--元素偏移量 offset 系列及模态框拖拽和仿京东放大镜案例

发布于:2022-10-23 ⋅ 阅读:(435) ⋅ 点赞:(0)

offsetLeft和offsetTop获取元素偏移

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

获得元素距离带有定位父元素的位置

获得元素自身的大小(宽度高度)

注意: 返回的数值都不带单位

element.offsetTop        element.offsetLeft 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        
        .father {
            /* position: relative; */
            width: 200px;
            height: 200px;
            background-color: pink;
            margin: 150px;
        }
        
        .son {
            width: 100px;
            height: 100px;
            background-color: purple;
            margin-left: 45px;
			
        }
        
        .w {
            height: 200px;
            background-color: skyblue;
            margin: 0 auto 200px;
            padding: 10px;
            border: 15px solid red;
        }
    </style>
</head>

<body>
    <div class="father">
        <div class="son"></div>
    </div>
    <div class="w"></div>
    <script>
        // offset 系列
        var father = document.querySelector('.father');
        var son = document.querySelector('.son');
        // 1.可以得到元素的偏移 位置 返回的不带单位的数值  
        console.log(father.offsetTop);
        console.log(father.offsetLeft);
        // 它以带有定位的父亲为准  如果么有父亲或者父亲没有定位 则以 body 为准
        console.log(son.offsetLeft);
</script>
</body>

</html>

  

offsetWidth和offsetHeight获取元素大小

// 2.可以得到元素的大小 宽度和高度 是包含padding + border + width 
        console.log(w.offsetWidth);
        console.log(w.offsetHeight);
        // 3. 返回带有定位的父亲 否则返回的是body
        console.log(son.offsetParent); // 返回带有定位的父亲 否则返回的是body
        console.log(son.parentNode); // 返回父亲 是最近一级的父亲 亲爸爸 不管父亲有没有定位

offset与style的区别

offset

offset 可以得到任意样式表中的样式值

offset 系列获得的数值是没有单位的

offsetWidth 包含padding+border+width

offsetWidth 等属性是只读属性,只能获取不能赋值

所以,我们想要获取元素大小位置,用offset更合适

style

style 只能得到行内样式表中的样式值

style.width 获得的是带有单位的字符串

style.width 获得不包含padding和border 的值

style.width 是可读写属性,可以获取也可以赋值

所以,我们想要给元素更改值,则需要用style改变

获取鼠标在盒子内的坐标

案例分析

① 我们在盒子内点击,想要得到鼠标距离盒子左右的距离。

② 首先得到鼠标在页面中的坐标(e.pageX, e.pageY)

③ 其次得到盒子在页面中的距离 ( box.offsetLeft, box.offsetTop)

④ 用鼠标距离页面的坐标减去盒子在页面中的距离,得到鼠标在盒子内的坐标

⑤ 如果想要移动一下鼠标,就要获取最新的坐标,使用鼠标移动事件 mousemove

var box = document.querySelector('.box');
box.addEventListener('mousemove', function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
this.innerHTML = 'x坐标是' + x + ' y坐标是' + y;
})

 模态框拖拽

弹出框,我们也称为模态框。

1. 点击弹出层, 会弹出模态框, 并且显示灰色半透明的遮挡层。

2. 点击关闭按钮,可以关闭模态框,并且同时关闭灰色半透明遮挡层。

  

 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';
	   })

3. 鼠标放到模态框最上面一行,可以按住鼠标拖拽模态框在页面中移动。

4. 鼠标松开,可以停止拖动模态框移动。

案例分析

① 点击弹出层, 模态框和遮挡层就会显示出来 display:block;

② 点击关闭按钮,模态框和遮挡层就会隐藏起来 display:none;

③ 在页面中拖拽的原理: 鼠标按下并且移动, 之后松开鼠标

④ 触发事件是鼠标按下 mousedown, 鼠标移动mousemove 鼠标松开 mouseup

⑤ 拖拽过程: 鼠标移动过程中,获得最新的值赋值给模态框的left和top值, 这样模态框可以跟着鼠标走了

⑥ 鼠标按下触发的事件源是 最上面一行,就是 id 为 title

⑦ 鼠标的坐标 减去 鼠标在盒子内的坐标, 才是模态框真正的位置。

⑧ 鼠标按下,我们要得到鼠标在盒子的坐标。

⑨ 鼠标移动,就让模态框的坐标 设置为 : 鼠标坐标 减去盒子坐标即可,注意移动事件写到按下事件里面。

// 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',function(e){
			   login.style.left=e.pageX-x+'px';//最新的坐标,如果用offsetLeft就会写死,固定不动
			   console.log(login.offsetTop)
			   login.style.top=e.pageY-y+"px";
		   })
	   })

⑩ 鼠标松开,就停止拖拽,就是可以让鼠标移动事件解除

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

完整代码


<!DOCTYPE html>
<html>

<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <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>
</head>

<body>
    <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. 开始拖拽
            // (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';//最新的坐标,如果用offsetLeft就会写死,固定不动
		   			   console.log(login.offsetTop)
		   			   login.style.top=e.pageY-y+"px";
		   }
		   // (3) 鼠标弹起,就让鼠标移动事件移除
		   document.addEventListener('mouseup',function(){
			   document.removeEventListener('mousemove',move)
		   })
	   })
            
          
            
            
    </script>
</body>

</html>

仿京东放大镜

添加一个maskdiv 设置在preview_img下,设置css

还要有个放大的盒子,big,在结果big下要有个大图

第一步的效果,接下来书写js代码

① 鼠标经过小图片盒子, 黄色的遮挡层 和 大图片盒子显示,离开隐藏2个盒子功能

② 就是显示与隐藏

案例分析

① 黄色的遮挡层跟随鼠标功能。

② 把鼠标坐标给遮挡层不合适。因为遮挡层坐标以父盒子为准。

③ 首先是获得鼠标在盒子的坐标。

④ 之后把数值给遮挡层做为left 和top值。

⑤ 此时用到鼠标移动事件,但是还是在小图片盒子内移动。

⑥ 发现,遮挡层位置不对,需要再减去盒子自身高度和宽度的一半。

⑦ 遮挡层不能超出小图片盒子范围。

⑧ 如果小于零,就把坐标设置为0

⑨ 如果大于遮挡层最大的移动距离,就把坐标设置为最大的移动距离

⑩ 遮挡层的最大移动距离: 小图片盒子宽度 减去 遮挡层盒子宽度

 现在鼠标位于mask的左上角,要使它居中,只要top,left各减一半

preview_img.addEventListener('mousemove',function(e){
		var x=e.pageX-this.offsetLeft;
		var y=e.pageY-this.offsetTop;
		// 盒子高度的一半 让鼠标居中
		mask.style.left=x-mask.offsetWidth/2+'px';
		mask.style.top=y-mask.offsetHeight/2+'px';
	})

给约束,不能超出范围

// 2鼠标移动的时候,让黄色盒子跟着鼠标来走
	preview_img.addEventListener('mousemove',function(e){
		var x=e.pageX-this.offsetLeft;
		var y=e.pageY-this.offsetTop;
		//2 盒子高度的一半 让鼠标居中
		var maskX=x-mask.offsetWidth/2;
		var maskY=y-mask.offsetHeight/2;
		if(maskX<=0){
			maskX=0;
		}else if(maskX>=preview_img.offsetWidth-mask.offsetWidth){
			maskX=preview_img.offsetWidth-mask.offsetWidth;
		}
		if(maskY<=0){
			maskY=0;
		}else if(maskY>=preview_img.offsetHeight-mask.offsetHeight){
			maskY=preview_img.offsetHeight-mask.offsetHeight;
		}
		mask.style.left=maskX+'px';
		mask.style.top=maskY+'px';
	})

 大图片随小图片移动

① 移动黄色遮挡层,大图片跟随移动功能

② 求大图片的移动距离公式 

注意:图片要给定位要不然走不了

window.addEventListener('load',function(){
	var preview_img=document.querySelector('.preview_img');
	var mask=document.querySelector(".mask");
	var big=document.querySelector('.big');
	// 1.当我们鼠标经过preview_img 就是显示和隐藏mask 遮挡层和big大盒子
	preview_img.addEventListener('mouseover',function(){
		mask.style.display='block';
		big.style.display='block';
	})
	preview_img.addEventListener('mouseout',function(){
		mask.style.display='none';
		big.style.display='none';
	})
	// 2鼠标移动的时候,让黄色盒子跟着鼠标来走
	preview_img.addEventListener('mousemove',function(e){
		var x=e.pageX-this.offsetLeft;
		var y=e.pageY-this.offsetTop;
		//2 盒子高度的一半 让鼠标居中
		var maskX=x-mask.offsetWidth/2;
		var maskY=y-mask.offsetHeight/2;
		// 遮挡层的最大移动距离
		var maskMax=preview_img.offsetWidth-mask.offsetWidth;
		if(maskX<=0){
			maskX=0;
		}else if(maskX>=maskMax){
			maskX=maskMax;
		}
		if(maskY<=0){
			maskY=0;
		}else if(maskY>=maskMax){
			maskY=maskMax;
		}
		mask.style.left=maskX+'px';
		mask.style.top=maskY+'px';
		var bigIMg=document.querySelector('.bigImg');
		// 大图片最大移动距离
		var bigMax=bigIMg.offsetWidth-big.offsetWidth;
		// 大图片的移动距离
		var bigX=maskX*bigMax/maskMax;
		var bigY=maskY*bigMax/maskMax;
		bigIMg.style.left=-bigX+'px';
		bigIMg.style.top=-bigY+'px';
	})
})

 

本文含有隐藏内容,请 开通VIP 后查看