一、如何判断一个元素是否在可视区域中?
常用的是以下三种:
-
offsetTop、scrollTop
-
getBoundingClientRect
-
Intersection Observer
1、offsetTop、scrollTop、clientHeight
offectTop:元素的上外边框至包含元素的上内边框之间的像素距离
el.offsetTop - document.documentElement.scrollTop <= viewPortHeight
1
代码实现:
function isInViewPortOfOne (el) {
// viewPortHeight 兼容所有浏览器写法
const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
const offsetTop = el.offsetTop
const scrollTop = document.documentElement.scrollTop
const top = offsetTop - scrollTop
return top <= viewPortHeight
}
延伸知识点:
clientWidth
、clientHeight
:
- clientWidth:元素内容区宽度加上左右内边距宽度,即clientWidth = content + padding
- clientHeight:元素内容区高度加上上下内边距高度,即clientHeight = content + padding
scrollWidth
、scrolltHeight
:
- scrollWidth:左右内边距宽度+元素内容的实际大小,即scrollWidth = content实际大小 + padding
- scrollHeight:上下内边距高度+元素内容的实际大小,即scrollHeight = content实际大小 + padding
2、getBoundingClientRect
返回值是一个 DOMRect对象,拥有left, top, right, bottom, x, y, width, 和 height属性,
如果一个元素在视窗之内的话,那么它一定满足下面四个条件:
- top 大于等于 0
- left 大于等于 0
- bottom 小于等于视窗高度
- right 小于等于视窗宽度
function isInViewPort(element) {
const viewWidth = window.innerWidth || document.documentElement.clientWidth;
const viewHeight = window.innerHeight || document.documentElement.clientHeight;
const {
top,
right,
bottom,
left,
} = element.getBoundingClientRect();
return (
top >= 0 &&
left >= 0 &&
right <= viewWidth &&
bottom <= viewHeight
);
}
3、Intersection Observer(重叠观察者)
I
用于判断两个元素是否重叠,因为不用进行事件的监听,性能方面相比getBoundingClientRect
会好很多
使用步骤主要分为两步:创建观察者和传入被观察者
const options = {
// 表示重叠面积占被观察者的比例,从 0 - 1 取值,
// 1 表示完全被包含
threshold: 1.0,
root:document.querySelector('#scrollArea') // 必须是目标元素的父级元素
};
const callback = function(entries, observer) {
entries.forEach(entry => {
entry.time; // 触发的时间
entry.rootBounds; // 根元素的位置矩形,这种情况下为视窗位置
entry.boundingClientRect; // 被观察者的位置举行
entry.intersectionRect; // 重叠区域的位置矩形
entry.intersectionRatio; // 重叠区域占被观察者面积的比例(被观察者不是矩形时也按照矩形计算)
entry.target; // 被观察者
});
};
// 1、创建观察者
const observer = new IntersectionObserver(callback, options);
// 2、传入被观察者
const target = document.querySelector('.target');
observer.observe(target);
二、如何修改第三方UI组件库样式
常用四种方法:
1、添加 class/style
<el-button type="success" class="mybutton" style="height: 250px;">按钮</el-button>
<style lang="css" scoped>
.mybutton{
border-radius: 20px;
}
</style>
如果某个属性覆盖不了,就加属性的权重;
2、去除style标签上的scoped属性
为了避免样式污染,可以在需要修改的UI组件的外层添加自定义class等,向下包含UI组件的样式代码,这样可以防止影响到别的组件。
3、使用深度选择器
- /deep/ sass和less的样式穿透
- >>> stylus的样式穿透
- ::v-deep vue3中可以会出现/deep/编译报错,可以使用
::v-deep。
使用:
// 1、/deep/是需要写在UI框架的样式类之前的
.liForm {
/deep/.el-textarea {
.el-input__count {
bottom: 2px!important;
}
}
}
// 下面的方式不会生效**********
/deep/.liForm {
.el-textarea {
.el-input__count {
bottom: 2px!important;
}
}
}
// 2、>>>
<style scoped>
.a >>> .b { /* ... */ }
</style>
4、去除scoped+深度选择器
三、单冒号、双冒号区别
1、单冒号:伪类
伪类用于定义元素的特殊状态
常见伪类::hover :active :focus
2、双冒号:伪元素
伪元素用于给某个元素的之前或之后插入特定内容的关键词
常见伪元素:::after ::before