187 lines
4.9 KiB
Vue
187 lines
4.9 KiB
Vue
<template>
|
||
<view class="tn-sticky-class">
|
||
<view
|
||
class="tn-sticky__wrap"
|
||
:class="[stickyClass]"
|
||
:style="[stickyStyle]"
|
||
>
|
||
<view
|
||
class="tn-sticky__item"
|
||
:style="{
|
||
position: fixed ? 'fixed' : 'static',
|
||
top: stickyTop + 'px',
|
||
left: left + 'px',
|
||
width: width === 'auto' ? 'auto' : width + 'px',
|
||
zIndex: elZIndex
|
||
}"
|
||
>
|
||
<slot></slot>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: 'tn-sticky',
|
||
props: {
|
||
// 吸顶容器到顶部某个距离的时候进行吸顶
|
||
// 在H5中,customNavBar的高度为45px
|
||
offsetTop: {
|
||
type: Number,
|
||
default: 0
|
||
},
|
||
// H5顶部导航栏的高度
|
||
h5NavHeight: {
|
||
type: Number,
|
||
default: 45
|
||
},
|
||
// 自定义顶部导航栏高度
|
||
customNavHeight: {
|
||
type: Number,
|
||
default: 0
|
||
},
|
||
// 是否开启吸顶
|
||
enabled: {
|
||
type: Boolean,
|
||
default: true
|
||
},
|
||
// 吸顶容器的背景颜色
|
||
backgroundColor: {
|
||
type: String,
|
||
default: '#FFFFFF'
|
||
},
|
||
// z-index
|
||
zIndex: {
|
||
type: Number,
|
||
default: 0
|
||
},
|
||
// 索引值,区分不同的吸顶组件
|
||
index: {
|
||
type: [String, Number],
|
||
default: ''
|
||
}
|
||
},
|
||
computed: {
|
||
elZIndex() {
|
||
return this.zIndex ? this.zIndex : this.$tn.zIndex.sticky
|
||
},
|
||
backgroundColorStyle() {
|
||
return this.$tn.color.getBackgroundColorStyle(this.backgroundColor)
|
||
},
|
||
backgroundColorClass() {
|
||
return this.$tn.color.getBackgroundColorInternalClass(this.backgroundColor)
|
||
},
|
||
stickyClass() {
|
||
let clazz = ''
|
||
clazz += this.elClass
|
||
if (this.backgroundColorClass) {
|
||
clazz += ` ${this.backgroundColorClass}`
|
||
}
|
||
return clazz
|
||
},
|
||
stickyStyle() {
|
||
let style = {}
|
||
style.height = this.fixed ? this.height + 'px' : 'auto'
|
||
if (this.backgroundColorStyle) {
|
||
style.color = this.backgroundColorStyle
|
||
}
|
||
if (this.elZIndex) {
|
||
style.zIndex = this.elZIndex
|
||
}
|
||
return style
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
// 监听组件别名
|
||
stickyObserverName: 'tnStickyObserver',
|
||
// 组件的唯一编号
|
||
elClass: this.$tn.uuid(),
|
||
// 是否固定
|
||
fixed: false,
|
||
// 高度
|
||
height: 'auto',
|
||
// 宽度
|
||
width: 'auto',
|
||
// 距离顶部的距离
|
||
stickyTop: 0,
|
||
// 左边距离
|
||
left: 0
|
||
}
|
||
},
|
||
watch: {
|
||
offsetTop(val) {
|
||
this.initObserver()
|
||
},
|
||
enabled(val) {
|
||
if (val === false) {
|
||
this.fixed = false
|
||
this.disconnectObserver(this.stickyObserverName)
|
||
} else {
|
||
this.initObserver()
|
||
}
|
||
},
|
||
customNavHeight(val) {
|
||
this.initObserver()
|
||
}
|
||
},
|
||
mounted() {
|
||
this.initObserver()
|
||
},
|
||
methods: {
|
||
// 初始化监听组件的布局状态
|
||
initObserver() {
|
||
if (!this.enabled) return
|
||
// #ifdef H5
|
||
this.stickyTop = this.offsetTop != 0 ? uni.upx2px(this.offsetTop) + this.h5NavHeight : this.h5NavHeight
|
||
// #endif
|
||
// #ifndef H5
|
||
this.stickyTop = this.offsetTop != 0 ? uni.upx2px(this.offsetTop) + this.customNavHeight : this.customNavHeight
|
||
// #endif
|
||
|
||
this.disconnectObserver(this.stickyObserverName)
|
||
this._tGetRect('.' + this.elClass).then((res) => {
|
||
this.height = res.height
|
||
this.left = res.left
|
||
this.width = res.width
|
||
this.$nextTick(() => {
|
||
this.connectObserver()
|
||
})
|
||
})
|
||
},
|
||
// 监听组件的布局状态
|
||
connectObserver() {
|
||
this.disconnectObserver(this.stickyObserverName)
|
||
// 组件内获取布局状态,不能用uni.createIntersectionObserver,而必须用this.createIntersectionObserver
|
||
const contentObserver = this.createIntersectionObserver({
|
||
thresholds: [0.95, 0.98, 1]
|
||
})
|
||
contentObserver.relativeToViewport({
|
||
top: -this.stickyTop
|
||
})
|
||
contentObserver.observe('.' + this.elClass, res => {
|
||
if (!this.enabled) return
|
||
this.setFixed(res.boundingClientRect.top)
|
||
})
|
||
this[this.stickyObserverName] = contentObserver
|
||
},
|
||
// 设置是否固定
|
||
setFixed(top) {
|
||
const fixed = top < this.stickyTop
|
||
if (fixed) this.$emit('fixed', this.index)
|
||
else if (this.fixed) this.$emit('unfixed', this.index)
|
||
this.fixed = fixed
|
||
},
|
||
// 停止监听组件的布局状态
|
||
disconnectObserver(observerName) {
|
||
const observer = this[observerName]
|
||
observer && observer.disconnect()
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
</style>
|