小程序初始提交

This commit is contained in:
jdc
2025-11-13 10:36:23 +08:00
parent f26b4f9a2f
commit 5db3b180eb
447 changed files with 83351 additions and 0 deletions

View File

@@ -0,0 +1,170 @@
<template>
<view
class="cl-sticky-wrapper"
:style="{
height: rect.height == 0 ? 'auto' : rect.height + 'px',
zIndex
}"
>
<view
class="cl-sticky"
:class="[
{
'is-active': isSticky
}
]"
:style="{
width: isSticky ? rect.width + 'px' : '100%',
left: isSticky ? rect.left + 'px' : 0,
top: stickyTop + 'px'
}"
>
<slot></slot>
<slot name="content" :is-sticky="isSticky"></slot>
</view>
</view>
</template>
<script lang="ts" setup>
import { isEmpty, isHarmony, router } from "@/cool";
import { computed, getCurrentInstance, nextTick, onMounted, reactive, ref, watch } from "vue";
import { usePage } from "../../hooks";
defineOptions({
name: "cl-sticky"
});
defineSlots<{
default(): any;
content(props: { isSticky: boolean }): any;
}>();
const props = defineProps({
offsetTop: {
type: Number,
default: 0
},
zIndex: {
type: Number,
default: 100
},
scrollTop: {
type: Number,
default: 0
}
});
const { proxy } = getCurrentInstance()!;
// cl-page 上下文
const { onScroll } = usePage();
// 表示元素的位置信息
type Rect = {
height: number; // 高度
width: number; // 宽度
left: number; // 距离页面左侧的距离
top: number; // 距离页面顶部的距离
};
// 存储当前sticky元素的位置信息
const rect = reactive<Rect>({
height: 0,
width: 0,
left: 0,
top: 0
});
// 当前页面滚动的距离
const scrollTop = ref(0);
// 计算属性,判断当前是否处于吸顶状态
const isSticky = computed(() => {
if (rect.height == 0) return false;
return scrollTop.value >= rect.top;
});
// 计算属性返回sticky元素的top值吸顶时的偏移量
const stickyTop = computed(() => {
if (isSticky.value) {
let v = 0;
// #ifdef H5
// H5端默认导航栏高度为44
if (!router.isCustomNavbarPage()) {
v = 44;
}
// #endif
return v + props.offsetTop;
} else {
return 0;
}
});
// 获取sticky元素的位置信息并更新rect
function getRect() {
nextTick(() => {
setTimeout(
() => {
uni.createSelectorQuery()
.in(proxy)
.select(".cl-sticky")
.boundingClientRect()
.exec((nodes) => {
if (isEmpty(nodes)) {
return;
}
const node = nodes[0] as NodeInfo;
// 赋值时做空值处理,保证类型安全
rect.height = node.height ?? 0;
rect.width = node.width ?? 0;
rect.left = node.left ?? 0;
// top需要减去offsetTop并加上当前滚动距离保证吸顶准确
rect.top = (node.top ?? 0) - props.offsetTop + scrollTop.value;
});
},
isHarmony() ? 300 : 0
);
});
}
onMounted(() => {
// 获取元素位置信息
getRect();
// 监听页面滚动事件
onScroll((top) => {
scrollTop.value = top;
});
// 监听参数变化
watch(
computed(() => props.scrollTop),
(top: number) => {
scrollTop.value = top;
},
{
immediate: true
}
);
});
defineExpose({
getRect
});
</script>
<style lang="scss" scoped>
.cl-sticky {
@apply relative w-full;
&.is-active {
@apply fixed w-full;
}
}
</style>