需求分析
- 支持页面向下滚动时组件会自动粘滞在窗口顶部;
- 可配置粘滞在窗口顶部的间距;
方法实现
一、思路:
1、通过窗口顶部到文档顶部的距离(window.scrollY)和sticky组件到窗口顶部的距离(top + window.scrollY)加上窗口顶部到文档顶部的距离(window.scrollY)来比较,前面大于后面则吸顶,后面大于前面则不吸顶。
window.scrollY > top + window.scrollY
二、方法实现
1、sticky外部组件传参定义:
<template>
<div class="box">
<div>内容一</div>
<div>内容一</div>
<div>内容一</div>
<div>内容一</div>
<div>内容一</div>
<div>内容一</div>
<t-sticky :distance="30"> //sticky距离顶部可配置的值
<div class="sticky-box">这是一段很长的代码这是一段很长的代码这是一段很长的代码</div>
</t-sticky>
<div>内容一</div>
<div>内容一</div>
<div>内容一</div>
<div>内容一</div>
<div>内容一</div>
<div>内容一</div>
<div>内容一</div>
<div>内容一</div>
<div>内容一</div>
</div>
</template>
2、sticky内部组件实现
1、主要通过 _windowScrollHandler() 函数来判断是否粘滞顶部,如果粘滞则改变css的类(fixed),不粘滞则取消这个类。
2、可配置的粘滞在窗口顶部的间距通过组件外部传参(distance) 在 _windowScrollHandler() 函数中的 if 判断那里加上distance参数进行动态计算。
if (window.scrollY > top - this.distance)
<template>
<div class="t-sticky-content" ref="wrapper" :style="{height}">
<div class="t-sticky-content-box" :class="classes" :style="{width, left, top}">
<slot></slot>
</div>
</div>
</template>
export default {
name: 't-sticky',
props: {
distance: {
type: Number,
default: 0
}
},
data() {
return {
sticky: false,
left: undefined,
width: undefined,
height: undefined,
top: undefined,
}
},
computed: {
classes() {
return {
sticky: this.sticky
}
}
},
mounted() {
this.windowScrollHandler = this._windowScrollHandler.bind(this)
window.addEventListener('scroll', this.windowScrollHandler)
},
beforeDestroy() {
window.removeEventListener('scroll', this.windowScrollHandler)
},
methods: {
offsetTop() {
let {top} = this.$refs.wrapper.getBoundingClientRect()
return {top: top + window.scrollY}
},
_windowScrollHandler() {
let {top} = this.offsetTop()
if (window.scrollY > top - this.distance) {
let {height, left, width} = this.$refs.wrapper.getBoundingClientRect()
this.height = height + 'px'
this.width = width + 'px'
this.top = this.distance + 'px'
this.left = left + 'px'
this.sticky = true
} else {
this.height = undefined
this.width = undefined
this.top = undefined
this.left = undefined
this.sticky = false
}
},
}
}
3、一些需要注意的坑
1、在组件fixed定位时,组件会脱离文档流,需要在组件原来的位置留出高度,不然在滚动的时候会出现BUG。
2、在组件fiexd定位时,需要动态计算组件未粘滞时距离左右视口的距离(left,right)及组件宽度(width)。
3、在页面销毁的时候要关闭scroll监听,在beforeDestroy钩子里关闭,否则会影响性能以及会有BUG。
完整代码可参考我的GitHub:https://github.com/A-Tione/tione/blob/master/src/sticky/sticky.vue