更新:登录功能
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
<template>
|
||||
<view style="position: relative">
|
||||
<view :class="`wd-sticky-box ${props.customClass}`" :style="customStyle" :id="styckyBoxId">
|
||||
<wd-resize @resize="handleResize">
|
||||
<slot />
|
||||
</wd-resize>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-sticky-box',
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
// virtualHost: true,
|
||||
styleIsolation: 'shared'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import wdResize from '../wd-resize/wd-resize.vue'
|
||||
import { getCurrentInstance, onBeforeMount, reactive, ref } from 'vue'
|
||||
import { getRect, uuid } from '../common/util'
|
||||
import { baseProps } from '../common/props'
|
||||
import { STICKY_BOX_KEY } from './types'
|
||||
import { useChildren } from '../composables/useChildren'
|
||||
|
||||
const props = defineProps(baseProps)
|
||||
|
||||
const styckyBoxId = ref<string>(`wd-sticky-box${uuid()}`)
|
||||
|
||||
const observerMap = ref<Map<any, any>>(new Map())
|
||||
|
||||
const boxStyle = reactive({
|
||||
height: 0,
|
||||
width: 0
|
||||
})
|
||||
|
||||
const { proxy } = getCurrentInstance() as any
|
||||
|
||||
const { children: stickyList, linkChildren } = useChildren(STICKY_BOX_KEY)
|
||||
linkChildren({
|
||||
boxStyle: boxStyle,
|
||||
observerForChild
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
observerMap.value = new Map()
|
||||
})
|
||||
|
||||
/**
|
||||
* 容器大小变化后重新监听sticky组件与box组件的交叉状态
|
||||
* @param detail
|
||||
*/
|
||||
function handleResize(detail: any) {
|
||||
// 相对的容器大小改变后,同步设置 wd-sticky-box 的大小
|
||||
boxStyle.width = detail.width
|
||||
boxStyle.height = detail.height
|
||||
// wd-sticky-box 大小变化时,重新监听所有吸顶元素
|
||||
const temp = observerMap.value
|
||||
observerMap.value = new Map()
|
||||
for (const [uid] of temp) {
|
||||
const child = stickyList.find((sticky) => {
|
||||
return sticky.$.uid === uid
|
||||
})
|
||||
observerForChild(child)
|
||||
}
|
||||
temp.forEach((observer) => {
|
||||
observer.disconnect()
|
||||
})
|
||||
temp.clear()
|
||||
}
|
||||
/**
|
||||
* 删除对指定sticky的监听
|
||||
* @param child 指定的子组件
|
||||
*/
|
||||
function deleteObserver(child: any) {
|
||||
const observer = observerMap.value.get(child.$.uid)
|
||||
if (!observer) return
|
||||
observer.disconnect()
|
||||
observerMap.value.delete(child.$.uid)
|
||||
}
|
||||
/**
|
||||
* 针对指定sticky添加监听
|
||||
* @param child 指定的子组件
|
||||
*/
|
||||
function createObserver(child: any) {
|
||||
const observer = uni.createIntersectionObserver(proxy, { thresholds: [0, 0.5] })
|
||||
observerMap.value.set(child.$.uid, observer)
|
||||
return observer
|
||||
}
|
||||
/**
|
||||
* 监听子组件
|
||||
* @param child 子组件
|
||||
*/
|
||||
function observerForChild(child: any) {
|
||||
deleteObserver(child)
|
||||
const observer = createObserver(child)
|
||||
const exposed = child.$.exposed
|
||||
let offset = exposed.stickyState.height + exposed.offsetTop
|
||||
// #ifdef H5
|
||||
// H5端,导航栏为普通元素,需要将组件移动到导航栏的下边沿
|
||||
// H5的导航栏高度为44px
|
||||
offset = offset + 44
|
||||
// #endif
|
||||
|
||||
if (boxStyle.height <= exposed.stickyState.height) {
|
||||
exposed.setPosition(false, 'absolute', 0)
|
||||
}
|
||||
observer.relativeToViewport({ top: -offset }).observe(`#${styckyBoxId.value}`, (result) => {
|
||||
handleRelativeTo(exposed, result)
|
||||
})
|
||||
// 当子组件默认处于边界外且永远不会进入边界内时,需要手动调用一次
|
||||
getRect(`#${styckyBoxId.value}`, false, proxy)
|
||||
.then((res) => {
|
||||
// #ifdef H5
|
||||
// H5端,查询节点信息未计算导航栏高度
|
||||
res.bottom = Number(res.bottom) + 44
|
||||
// #endif
|
||||
if (Number(res.bottom) <= offset) handleRelativeTo(exposed, { boundingClientRect: res })
|
||||
})
|
||||
.catch((res) => {
|
||||
console.log(res)
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 监听容器组件
|
||||
* @param {Object} exposed wd-sticky实例暴露出的事件
|
||||
* @param {Object} boundingClientRect 边界信息
|
||||
*/
|
||||
function handleRelativeTo(exposed: any, { boundingClientRect }: any) {
|
||||
let childOffsetTop = exposed.offsetTop
|
||||
// #ifdef H5
|
||||
// H5端,导航栏为普通元素,需要将组件移动到导航栏的下边沿
|
||||
// H5的导航栏高度为44px
|
||||
childOffsetTop = childOffsetTop + 44
|
||||
// #endif
|
||||
const offset = exposed.stickyState.height + childOffsetTop
|
||||
let isAbsolute = boundingClientRect.bottom <= offset
|
||||
// #ifdef H5 || APP-PLUS
|
||||
isAbsolute = boundingClientRect.bottom < offset
|
||||
// #endif
|
||||
if (isAbsolute) {
|
||||
exposed.setPosition(true, 'absolute', boundingClientRect.height - exposed.stickyState.height)
|
||||
} else if (boundingClientRect.top <= offset && !isAbsolute) {
|
||||
if (exposed.stickyState.state === 'normal') return
|
||||
exposed.setPosition(false, 'fixed', childOffsetTop)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
Reference in New Issue
Block a user