2020-04-03 16:34:17 +08:00
|
|
|
<template>
|
2020-04-04 20:34:09 +08:00
|
|
|
<div>
|
|
|
|
|
<div
|
|
|
|
|
v-if="showPlaceHolder"
|
|
|
|
|
:style="stylePlaceHolder"
|
2020-10-06 17:03:32 +08:00
|
|
|
/>
|
2020-04-04 20:34:09 +08:00
|
|
|
<div
|
|
|
|
|
ref="scroll-affix"
|
|
|
|
|
:style="affixStyle"
|
|
|
|
|
class="scroll-affix-container"
|
|
|
|
|
>
|
2020-10-06 17:03:32 +08:00
|
|
|
<slot />
|
2020-04-04 20:34:09 +08:00
|
|
|
</div>
|
2020-04-03 16:34:17 +08:00
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
export default {
|
|
|
|
|
name: 'Affix',
|
|
|
|
|
props: {
|
|
|
|
|
offsetTop: {
|
|
|
|
|
type: Number,
|
|
|
|
|
default: 0
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
data () {
|
|
|
|
|
return {
|
|
|
|
|
affixStyle: {
|
2020-04-04 21:11:18 +08:00
|
|
|
position: 'initial',
|
2020-04-03 16:34:17 +08:00
|
|
|
top: 'initial'
|
|
|
|
|
},
|
2020-04-04 20:34:09 +08:00
|
|
|
|
2020-04-05 16:44:20 +08:00
|
|
|
// 占位区域样式
|
|
|
|
|
stylePlaceHolder: {},
|
|
|
|
|
|
|
|
|
|
// 占位区域
|
2020-04-04 20:34:09 +08:00
|
|
|
showPlaceHolder: false,
|
2020-04-05 16:44:20 +08:00
|
|
|
|
|
|
|
|
// 实例
|
2020-04-03 16:34:17 +08:00
|
|
|
instance: '',
|
2020-04-05 16:44:20 +08:00
|
|
|
|
|
|
|
|
// 用于记录实例的初始状态下的位置
|
2020-04-03 16:34:17 +08:00
|
|
|
defaultInstancePosition: ''
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
mounted () {
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
this.instance = this.$refs['scroll-affix']
|
|
|
|
|
this.createAffix()
|
|
|
|
|
})
|
|
|
|
|
},
|
2020-10-06 17:03:32 +08:00
|
|
|
beforeDestroy () {
|
|
|
|
|
document.removeEventListener('scroll', this.scrollListener)
|
|
|
|
|
},
|
2020-04-03 16:34:17 +08:00
|
|
|
methods: {
|
|
|
|
|
getInstanceRect () {
|
|
|
|
|
return this.instance.getBoundingClientRect()
|
|
|
|
|
},
|
2020-04-05 16:44:20 +08:00
|
|
|
|
2020-04-03 16:34:17 +08:00
|
|
|
getWindowScrollTop () {
|
|
|
|
|
return window.pageYOffset ||
|
|
|
|
|
document.documentElement.scrollTop ||
|
|
|
|
|
document.body.scrollTop
|
|
|
|
|
},
|
2020-04-05 16:44:20 +08:00
|
|
|
|
2020-04-03 16:34:17 +08:00
|
|
|
createAffix () {
|
|
|
|
|
this.defaultInstancePosition = this.getInstanceRect().top
|
|
|
|
|
this.beforeListener()
|
|
|
|
|
document.addEventListener('scroll', this.scrollListener)
|
|
|
|
|
},
|
2020-04-05 16:44:20 +08:00
|
|
|
|
2020-04-03 16:34:17 +08:00
|
|
|
setFixedForInstance () {
|
|
|
|
|
this.affixStyle = {
|
|
|
|
|
position: 'fixed',
|
|
|
|
|
top: `${this.offsetTop}px`
|
|
|
|
|
}
|
|
|
|
|
},
|
2020-04-05 16:44:20 +08:00
|
|
|
|
|
|
|
|
// 用于设置实例在固定后的空白占位
|
2020-04-04 20:34:09 +08:00
|
|
|
setPlaceHolder () {
|
2020-04-04 20:36:09 +08:00
|
|
|
this.showPlaceHolder = true
|
|
|
|
|
|
2020-04-04 20:34:09 +08:00
|
|
|
const instanceRect = this.getInstanceRect()
|
|
|
|
|
this.stylePlaceHolder = {
|
2020-04-04 21:04:30 +08:00
|
|
|
width: `${instanceRect.width}px`,
|
|
|
|
|
height: `${instanceRect.height}px`
|
2020-04-04 20:34:09 +08:00
|
|
|
}
|
|
|
|
|
},
|
2020-04-03 16:34:17 +08:00
|
|
|
beforeListener () {
|
2020-04-05 16:44:20 +08:00
|
|
|
// 若下一次进入页面发现滚动条所处位置已经超过了实例,则立即固定
|
2020-04-03 16:34:17 +08:00
|
|
|
if (this.defaultInstancePosition < this.offsetTop) {
|
|
|
|
|
this.setFixedForInstance()
|
2020-04-04 20:34:09 +08:00
|
|
|
this.setPlaceHolder()
|
2020-04-03 16:34:17 +08:00
|
|
|
}
|
2020-04-04 20:34:09 +08:00
|
|
|
|
2020-04-03 16:34:17 +08:00
|
|
|
this.defaultInstancePosition = this.getWindowScrollTop() + this.defaultInstancePosition
|
|
|
|
|
},
|
|
|
|
|
scrollListener () {
|
|
|
|
|
const offsetTop = this.getInstanceRect().top
|
2020-04-05 16:44:20 +08:00
|
|
|
// 当实例距离顶部的距离刚好接近(0px+设置的 top 距离)时,则立即固定
|
2020-04-03 16:34:17 +08:00
|
|
|
if (offsetTop <= this.offsetTop) {
|
|
|
|
|
this.setFixedForInstance()
|
2020-04-04 20:34:09 +08:00
|
|
|
this.setPlaceHolder()
|
2020-04-03 16:34:17 +08:00
|
|
|
}
|
2020-04-04 20:34:09 +08:00
|
|
|
|
|
|
|
|
const windowScrollTop = this.getWindowScrollTop()
|
2020-04-03 16:34:17 +08:00
|
|
|
const isArrivalDefault = (this.defaultInstancePosition - this.offsetTop) >= windowScrollTop
|
2020-04-04 20:34:09 +08:00
|
|
|
|
2020-04-05 16:44:20 +08:00
|
|
|
// 当实例的初始位置减去设置的 top 距离刚好接近滚动条滚过的距离时(即一直在向上滚动)&& 实例已经在固定状态,则取消固定
|
2020-04-03 16:34:17 +08:00
|
|
|
if (isArrivalDefault && this.affixStyle.position === 'fixed') {
|
|
|
|
|
this.affixStyle = {}
|
2020-04-04 20:36:09 +08:00
|
|
|
this.showPlaceHolder = false
|
2020-04-04 20:34:09 +08:00
|
|
|
this.stylePlaceHolder = {}
|
2020-04-03 16:34:17 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
.scroll-affix-container {
|
|
|
|
|
position: initial;
|
|
|
|
|
top: initial;
|
|
|
|
|
}
|
|
|
|
|
</style>
|