HTML中各种 div 位置距离关系
- 一. 盒模型图片展示:
- 二. 位置距离计算属性
- 三. 应用场景
一. 盒模型图片展示:
二. 位置距离计算属性
-
offsetWidth, offsetHeight
获取盒子的宽度/高度(包括盒子的border,padding和内容width/height),不包括外边距 -
offsetLeft
获取盒子当前位置(左上角)距离自己最近定位的父元素左侧的距离,如果没有最近的定位的父元素,则相当于HTML -
offsetTop
获取盒子当前位置距离自己最近定位的父元素顶部的距离,如果没有最近的定位的父元素,则相当于HTML -
clientWidth,clientHeight
获取盒子的可视区域宽度、高度,包括padding在内,不包括border,这里是不包括滚动条的情况,如果有滚动条,发现盒子的宽度(width)从100变成83,可知滚动条的宽度为17px,而且是占据盒子内容的宽度,除了可视宽高,似乎其他都没有影响。
所谓的可视区域,个人理解就是一个盒子里面,能够展示出被人看见的内容区域 -
clientLeft
获取盒子的左边框的宽度,可理解为可视区域和左侧边(这个左侧边不是border)之间的距离 -
clientTop
获取盒子的上边框的宽度,可理解为可视区域和上侧边(这个上侧边不是border)之间的距离 -
scrollWidth,scrollHeight
获取盒子内容里面元素占据的真正宽度、高度 -
scrollLeft,scrollTop
滚动条距离左侧边,上侧边的距离
滚动条的最大滚动高度为滚动高度(scrollHeight) - 盒子可视高度(clientHeight) -
innerWidth,innerHeight
窗口宽度、高度,也可以理解为window窗口的可视区域宽度、高度
let IH = window.innerHeight
// 标准模式下
if (document.documentElement) {let IH = document.documentElement.clientHeight
// 怪异模式
} else {let IH = document.body.clientHeight
}
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)
},
-
pageX & pageY
正常情况下,window的可视区域的是不变的,所以相对于可视区域的坐标也就不会变,无论怎么点,clientX和clientY都是一样的。但是从page就可以知道,这个是页面坐标,也就是点击的页面距离window可视区域左上角的坐标距离。
一般可视区域是固定的,但是页面大小就不一定是固定的,如果有滚动条,说面页面大小超过了可视区域,这时候点击滚动隐藏区域,pageX&pageY肯定是大于clientX&clientY -
screenX & screenY
点击的位置距离屏幕的左上角的上左距离
三. 应用场景
-
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切换事件,默认truerightCanChange: 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 = falsethis.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"><divv-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?