Files
2026-09-24 16:25:22 +08:00

182 lines
4.1 KiB
Plaintext

<script lang="ts">
import { xProvitae } from "../../config/xConfig.uts"
import { PropType } from "vue"
import { getDefaultColor } from "../../core/util/xCoreColorUtil.uts"
import { checkIsCssUnit, rpx2px, getUid } from "../../core/util/xCoreUtil.uts"
type OBJINFO = {
width : number,
top : number,
left : number,
height : number
}
/**
* @name 粘性布局 Sticky
* @description 可以同时存在多个悬停,多个悬停时,还支持触发距离悬停的设置,
* 在复杂页面需要多个菜单吸附时非常有用。并且配合切换change事件做到更复杂的布局。
* @page /pages/index/sticky
* @category 导航组件
* @constant 平台兼容
* | Harmony | H5 | andriod | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
| --- | --- | --- | --- | --- | --- | --- | --- |
| ☑ | ☑ | ☑️ | ☑️ | ☑️ | ☑️ | 4.76+ | 1.1.18 |
*/
export default {
data() {
return {
id: 'xSticky-' + getUid(),
sizes: {
width: 0,
height: 0,
left: 0,
top: 0
} as OBJINFO,
isFiexd: false
}
},
emits: [
/**
* 当触发悬停切换时触发
* @description 当你有多个悬停,复杂布局页面时这个事件非常有用,可以帮助您做一些逻辑操作。
* @param {boolean} isFixed - 是否悬停的状态
*/
'change'
],
slots: Object as SlotsType<{
default : {
status : boolean
}
}>,
props: {
/**
* 顶部的偏移量
*/
top: {
type: String,
default: "0"
},
/**
* 左边的偏移量。
*/
left: {
type: String,
default: "0"
},
/**
* 触发距离,默认0,意思是组件距离顶部多远时触发悬停。
* 对于需要多个悬停时此属性非常有用。
* 这个值不允许使用%单位,可以是:px,rpx,数字(默认是rpx)
*/
diffTop: {
type: String,
default: '0'
},
/**
* 层级
*/
zIndex: {
type: Number,
default: 88
},
},
computed: {
_stop() : number {
return xProvitae.scrollTop;
},
_top() : string {
if (!this.isFiexd) return "0px"
let p = parseInt(this.top);
if (this.top.lastIndexOf('rpx') > -1) {
p = rpx2px(p);
}
// #ifdef H5
let headerNode = document.querySelector(".uni-page-head")
let headeerTop = uni.getWindowInfo().windowTop
p = p + headeerTop
// #endif
return p.toString() + 'px';
},
_left() : string {
if (!this.isFiexd) return "0px"
return checkIsCssUnit(this.left, 'rpx');
},
_diffTop() : number {
let p = checkIsCssUnit(this.diffTop, 'rpx')
let tp = 0
if (p.lastIndexOf('rpx') > -1) {
tp = rpx2px(parseInt(p))
}
tp = parseInt(p);
return tp
}
},
watch: {
_stop(newValue : number) {
let isf = newValue >= (this.sizes.top - this._diffTop)
if (isf != this.isFiexd) {
this.isFiexd = isf;
/**
* 当触发悬停切换时触发
* @description 当你有多个悬停,复杂布局页面时这个事件非常有用,可以帮助您做一些逻辑操作。
* @param isFixed {boolean} 是否悬停的状态
*/
this.$emit('change',isf)
}
}
},
mounted() {
this.$nextTick(() => {
this.getNodes();
})
},
methods: {
getNodes() {
uni.createSelectorQuery().in(this)
.select(".xStickyWrap")
.boundingClientRect().exec((ret) => {
let nodeinfo = ret[0] as NodeInfo;
this.sizes = {
width: nodeinfo.width!,
height: nodeinfo.height!,
left: nodeinfo.left!,
top: nodeinfo.top!
} as OBJINFO
})
},
getParentTop(){
const parent = this.$parent;
console.log(parent)
}
},
}
</script>
<template>
<view class="xSticky">
<view :id="id" class="xStickyWrap"
:style="{position:isFiexd?'fixed':'relative',left:_left,top:_top,zIndex:isFiexd?zIndex:0}">
<!--
@slot 默认插槽,你要悬停的布局放在这里。
@prop {boolean} status - 当前悬停的状态.
-->
<slot :status="isFiexd"></slot>
</view>
<view v-if="isFiexd" :style="{height:sizes.height+'px'}"></view>
</view>
</template>
<style scoped>
.xStickyWrap {
width: 100%;
}
</style>