看板
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import type { ExtractPropTypes, PropType } from 'vue';
|
||||
import { baseProps } from '../common/props';
|
||||
import zIndex from '../../libs/config/zIndex';
|
||||
|
||||
/**
|
||||
* StickyProps 吸顶组件 props 类型定义
|
||||
* @description 吸顶组件,支持自定义吸顶距离、z-index、背景色等
|
||||
*/
|
||||
export const StickyProps = {
|
||||
...baseProps,
|
||||
/** 吸顶容器到顶部某个距离的时候,进行吸顶,在H5平台,NavigationBar为44px */
|
||||
offsetTop: { type: [Number, String] as PropType<number | string>, default: 0 },
|
||||
/** 列表中的索引值 */
|
||||
index: { type: [Number, String] as PropType<number | string>, default: '' },
|
||||
/** 是否开启吸顶功能 */
|
||||
enable: { type: Boolean, default: true },
|
||||
/** h5顶部导航栏的高度 */
|
||||
h5NavHeight: { type: [Number, String] as PropType<number | string>, default: 44 },
|
||||
/** 吸顶区域的背景颜色 */
|
||||
bgColor: { type: String, default: 'var(--u-bg-white)' },
|
||||
/** z-index值 */
|
||||
zIndex: { type: [Number, String] as PropType<number | string>, default: zIndex.sticky }
|
||||
};
|
||||
|
||||
export type StickyProps = ExtractPropTypes<typeof StickyProps>;
|
||||
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<view>
|
||||
<view
|
||||
class="u-sticky-wrap"
|
||||
:class="[elClass, customClass]"
|
||||
:style="
|
||||
$u.toStyle(
|
||||
{
|
||||
height: fixed ? height + 'px' : 'auto',
|
||||
backgroundColor: bgColor
|
||||
},
|
||||
customStyle
|
||||
)
|
||||
"
|
||||
>
|
||||
<view
|
||||
class="u-sticky"
|
||||
:style="{
|
||||
position: fixed ? 'fixed' : 'static',
|
||||
top: stickyTop + 'px',
|
||||
left: left + 'px',
|
||||
width: width == 'auto' ? 'auto' : width + 'px',
|
||||
zIndex: uZIndex
|
||||
}"
|
||||
>
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'u-sticky',
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
// #ifndef MP-TOUTIAO
|
||||
virtualHost: true,
|
||||
// #endif
|
||||
styleIsolation: 'shared'
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, nextTick, onMounted, onBeforeUnmount, getCurrentInstance } from 'vue';
|
||||
import { $u } from '../..';
|
||||
import { StickyProps } from './types';
|
||||
|
||||
/**
|
||||
* sticky 吸顶
|
||||
* @description 该组件与CSS中position: sticky属性实现的效果一致,当组件达到预设的到顶部距离时, 就会固定在指定位置,组件位置大于预设的顶部距离时,会重新按照正常的布局排列。
|
||||
* @tutorial https://uviewpro.cn/zh/components/sticky.html
|
||||
* @property {String|Number} offsetTop 吸顶时与顶部的距离,单位rpx(默认0)
|
||||
* @property {String|Number} index 自定义标识,用于区分是哪一个组件
|
||||
* @property {Boolean} enable 是否开启吸顶功能(默认true)
|
||||
* @property {String} bgColor 组件背景颜色(默认var(--u-bg-white))
|
||||
* @property {String|Number} zIndex 吸顶时的z-index值(默认970)
|
||||
* @property {String|Number} h5NavHeight 导航栏高度,自定义导航栏时(无导航栏时需设置为0),需要传入此值,单位px(默认44)
|
||||
* @event fixed 组件吸顶时触发
|
||||
* @event unfixed 组件取消吸顶时触发
|
||||
* @example <u-sticky offset-top="200"><view>塞下秋来风景异,衡阳雁去无留意</view></u-sticky>
|
||||
*/
|
||||
const props = defineProps(StickyProps);
|
||||
|
||||
const emit = defineEmits(['fixed', 'unfixed']);
|
||||
|
||||
const instance = getCurrentInstance();
|
||||
const fixed = ref(false);
|
||||
const height = ref<'auto' | number>('auto');
|
||||
const stickyTop = ref(0);
|
||||
const elClass = ref('');
|
||||
const left = ref(0);
|
||||
const width = ref<'auto' | number>('auto');
|
||||
let contentObserver: any = null;
|
||||
|
||||
elClass.value = $u.guid();
|
||||
|
||||
const uZIndex = computed(() => (props.zIndex ? props.zIndex : ($u?.zIndex?.sticky ?? 970)));
|
||||
|
||||
watch(
|
||||
() => props.offsetTop,
|
||||
() => {
|
||||
initObserver();
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.enable,
|
||||
val => {
|
||||
if (val == false) {
|
||||
fixed.value = false;
|
||||
disconnectObserver('contentObserver');
|
||||
} else {
|
||||
initObserver();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
initObserver();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
disconnectObserver('contentObserver');
|
||||
});
|
||||
|
||||
/**
|
||||
* 初始化 IntersectionObserver 监听
|
||||
*/
|
||||
function initObserver() {
|
||||
if (!props.enable) return;
|
||||
// #ifdef H5
|
||||
stickyTop.value =
|
||||
Number(props.offsetTop) !== 0
|
||||
? uni.upx2px(Number(props.offsetTop)) + Number(props.h5NavHeight)
|
||||
: Number(props.h5NavHeight);
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
stickyTop.value = Number(props.offsetTop) !== 0 ? uni.upx2px(Number(props.offsetTop)) : 0;
|
||||
// #endif
|
||||
disconnectObserver('contentObserver');
|
||||
$u.getRect('.' + elClass.value, instance).then((res: any) => {
|
||||
height.value = res.height;
|
||||
left.value = res.left;
|
||||
width.value = res.width;
|
||||
nextTick(() => {
|
||||
observeContent();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 IntersectionObserver 监听内容区域
|
||||
*/
|
||||
function observeContent() {
|
||||
disconnectObserver('contentObserver');
|
||||
|
||||
contentObserver = uni.createIntersectionObserver(instance?.proxy, {
|
||||
thresholds: [0.95, 0.98, 1]
|
||||
});
|
||||
contentObserver.relativeToViewport({
|
||||
top: -stickyTop.value
|
||||
});
|
||||
contentObserver.observe('.' + elClass.value, (res: any) => {
|
||||
if (!props.enable) return;
|
||||
setFixed(res.boundingClientRect.top);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 fixed 状态
|
||||
*/
|
||||
function setFixed(top: number) {
|
||||
const isFixed = top < stickyTop.value;
|
||||
if (isFixed) emit('fixed', props.index);
|
||||
else if (fixed.value) emit('unfixed', props.index);
|
||||
fixed.value = isFixed;
|
||||
}
|
||||
|
||||
/**
|
||||
* 断开 observer
|
||||
*/
|
||||
function disconnectObserver(observerName: string) {
|
||||
if (observerName === 'contentObserver' && contentObserver) {
|
||||
contentObserver.disconnect();
|
||||
contentObserver = null;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../libs/css/style.components.scss';
|
||||
.u-sticky {
|
||||
z-index: 9999999999;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user