HTML中各种 div 位置距离关系

本文介绍了HTML盒模型,详细讲解了盒模型的图片展示和位置距离计算属性,包括宽度、高度、边界、可视区域等概念。同时,讨论了这些属性在实际应用场景中的作用,如Swiper组件的滑动切换及元素可视区检测。通过getBoundingClientRect()方法可以获取元素距离浏览器周边的位置,用于判断元素是否进入可视区域。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. 盒模型图片展示:

在这里插入图片描述

二. 位置距离计算属性

  1. offsetWidth, offsetHeight
    获取盒子的宽度/高度(包括盒子的border,padding和内容width/height),不包括外边距

  2. offsetLeft
    获取盒子当前位置(左上角)距离自己最近定位的父元素左侧的距离,如果没有最近的定位的父元素,则相当于HTML

  3. offsetTop
    获取盒子当前位置距离自己最近定位的父元素顶部的距离,如果没有最近的定位的父元素,则相当于HTML

  4. clientWidth,clientHeight
    获取盒子的可视区域宽度、高度,包括padding在内,不包括border,这里是不包括滚动条的情况,如果有滚动条,发现盒子的宽度(width)从100变成83,可知滚动条的宽度为17px,而且是占据盒子内容的宽度,除了可视宽高,似乎其他都没有影响。
    所谓的可视区域,个人理解就是一个盒子里面,能够展示出被人看见的内容区域

  5. clientLeft
    获取盒子的左边框的宽度,可理解为可视区域和左侧边(这个左侧边不是border)之间的距离

  6. clientTop
    获取盒子的上边框的宽度,可理解为可视区域和上侧边(这个上侧边不是border)之间的距离

  7. scrollWidth,scrollHeight
    获取盒子内容里面元素占据的真正宽度、高度

  8. scrollLeft,scrollTop
    滚动条距离左侧边,上侧边的距离
    滚动条的最大滚动高度为滚动高度(scrollHeight) - 盒子可视高度(clientHeight)

  9. innerWidth,innerHeight
    窗口宽度、高度,也可以理解为window窗口的可视区域宽度、高度

let IH = window.innerHeight
// 标准模式下
if (document.documentElement) {
    let IH = document.documentElement.clientHeight
// 怪异模式
} else {
    let IH = document.body.clientHeight
}
  1. clientX & clientY
    鼠标点击或者触屏时,点击位置距离window可视区域左上角的(0, 0)的坐标距离
<div @touchstart="touchStart($event)" @touchmove="touchMove($event)" @touchend="touchEnd($event)">
 </div>

touchStart(e){
	let info = this.dropDownInfo;
    info.startX = e.targetTouches[0].clientX;
    info.startY = e.targetTouches[0].clientY;
    console.log(e)
},

在这里插入图片描述

  1. pageX & pageY
    正常情况下,window的可视区域的是不变的,所以相对于可视区域的坐标也就不会变,无论怎么点,clientX和clientY都是一样的。但是从page就可以知道,这个是页面坐标,也就是点击的页面距离window可视区域左上角的坐标距离。
    一般可视区域是固定的,但是页面大小就不一定是固定的,如果有滚动条,说面页面大小超过了可视区域,这时候点击滚动隐藏区域,pageX&pageY肯定是大于clientX&clientY

  2. screenX & screenY
    点击的位置距离屏幕的左上角的上左距离
    在这里插入图片描述

三. 应用场景

  1. swiper左右滑动切换列表的内部嵌套slide滑块

    问题:内部slide滑块滑动事件与swiper左右滑动切换事件冲突,影响性能

    解决办法:监听滑块滑到触左、触右,触左时可触发swiper左切换,触右时可触发swiper右切换,除此之外,内部滑动阻止冒泡

<div @scroll="scrollEvent" @touchstart="touchStart($event)" @touchmove="touchMove($event)" class="slide">
	<div class="slide__item"></div>
	<div class="slide__item"></div>
	<div class="slide__item"></div>
</div>

data() {
	return {
    	dropDownInfo: {
        	startX: 0,
            startY: 0,
            isDropDown: false, // 是否下拉
            isBorder: false,
       },
       leftCanChange: true, // 靠左touch可以触发父级swiper切换事件,默认true
       rightCanChange: false, // 靠右touch可以触发父级swiper切换事件,默认false
   }
},
methods: {
	scrollEvent(e){
    	const slideWidth = e.target.scrollWidth; // 盒子内容里面元素占据的真正宽度
        const offsetWidth = e.target.offsetWidth; // 盒子的真实宽度,不包括左右margin外边距
        const scrollLeft = e.target.scrollLeft; // 滚动条滚动的宽度
        if (scrollLeft <= 0) {
        	// 触左
            this.leftCanChange = true
        } else if (scrollLeft + offsetWidth >= slideWidth) {
        	// 触右(滚动条可滚动的宽度 + 盒子的真实宽度 >= 盒子内容元素的真实宽度)
            this.rightCanChange = true
        } else {
        	this.leftCanChange = false
            this.rightCanChange = false
        }
	},
    /**
    * 触摸开始
    */
    touchStart(e){
    	const info = this.dropDownInfo;
        info.startX = e.targetTouches[0].pageX;
        info.startY = e.targetTouches[0].pageY;
    },
    /**
    * 触摸滑动时
    */
    touchMove(e){
    	let info = this.dropDownInfo;
        const X = e.targetTouches[0].pageX - info.startX;
        const disX = Math.abs(X)
        const disY = e.targetTouches[0].pageY - info.startY
        // 左右滑动且列表数据大于1,阻止冒泡触发父级swiper切换
        if ((disX > disY) && this.options.length > 1) {
        	// 除了触左,右滑 || 触右,左滑不阻止冒泡,防止触发父级swiper切换
            if (!(this.leftCanChange && X > 0 || this.rightCanChange && X < 0)) {
            	e.stopPropagation();
            }
       }
	},
}
.slide{
	position: relative;
    overflow: hidden;
    overflow-x: auto;
    white-space: nowrap;
    -webkit-overflow-scrolling: touch;
    background: #f5f5f5;
}
.slide__item{
	display: inline-block;
    width: 6.58rem;
    min-height: 3rem;
    margin: 0 0.08rem;
    vertical-align: top;
    background: #ffffff;
}

2. 监听元素是否在可视区

mounted() {
        window.addEventListener("scroll", this.handleScroll, false);
},
methods: {
	/**
    * 页面滚动
    */
    handleScroll(e) {
           let el = document.getElementById("elementId"); // 需要监听的元素
           let isVideoVisible = this.$util.isElementVisible(el); 
    }
},
util.js
/**
 * 元素是否在可视区
 * @param el
 * @returns {boolean|boolean | *}
 */
function isElementVisible(el) {
    const rect = el.getBoundingClientRect();
    const vWidth = window.innerWidth || document.documentElement.clientWidth;
    const vHeight = window.innerHeight || document.documentElement.clientHeight;
    const efp = function (x, y) {
        return document.elementFromPoint(x, y);
    };

    if (rect.right < 0 || rect.bottom < 0
        || rect.left > vWidth || rect.top > vHeight) return false;

    return (
        el.contains(efp(rect.left, rect.top))
        || el.contains(efp(rect.right, rect.top))
        || el.contains(efp(rect.right, rect.bottom))
        || el.contains(efp(rect.left, rect.bottom))
    );
}

以上代码只对上下滚动监听有用
在一个页面的slide左右滚动滑块中监听的话要用别的方法
**getBoundingClientRect();**获取元素距离浏览器周边的位置的方法

<div @scroll="scrollEvent" class="council__slide">
	<div
    	v-for="(item, index) in options"
        :key="'list-'+ index"
        class="council__slide-item">
	</div>
</div>
.council__slide-box{
    position: relative;
    overflow: hidden;
    overflow-x: auto;
    white-space: nowrap;
    -webkit-overflow-scrolling: touch;
    &::-webkit-scrollbar {
        width: 0;
        height: 0;
        display: none;
        background: transparent;
    }
}
.council__slide-item{
    display: inline-block;
    width: 6.78rem;
    height: 3.86rem;
    border-radius: 0.4rem;
    overflow: hidden;
    margin: 0 0.1rem;
}
created () {
        this.throttleScroll = $util.throttle(this.pageScroll, 100);
},
mounted () {},
methods: {
        scrollEvent(){
            this.throttleScroll();
        },
        pageScroll () {
            let el = document.getElementById('playVideo');
            const rectLeft = el.getBoundingClientRect(); // 获取元素距离浏览器周边的距离
                // 
                if (Math.abs(rectLeft.left) >= 187) {
                    ...
                }
            }
        },
}
<input type="text" id="inp" />

<script type="text/javascript">
var box = document.getElementById( "inp" ); 
alert(box.getBoundingClientRect().top); 
alert(box.getBoundingClientRect().right); 
alert(box.getBoundingClientRect().bottom); 
alert(box.getBoundingClientRect().left);
function getRect( elements ){ 
    var rect = elements.getBoundingClientRect(); 
    var clientTop = document.documentElement.clientTop; 
    var clientLeft = document.documentElement.clientLeft; 
    return { // 兼容ie多出的两个px 
        top : rect.top - clientTop, // 距离顶部的位置 
        bottom : rect.bottom - clientTop, // 距离顶部加上元素本身的高度就等于bottom的位置 
        left : rect.left - clientLeft, // 距离左边的位置 
        right : rect.right - clientLeft // 距离右边的位置就是 距离左边的位置加上元素本身的宽度 
    }; 
}; 
</script>

如何判断元素是否进入可视区域viewport?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值