Files
taimed-international-app/uni_modules/wot-design-uni/components/wd-resize/wd-resize.vue
2025-11-04 12:37:04 +08:00

145 lines
4.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view :class="`wd-resize ${customClass}`" :style="rootStyle">
<!--插槽需要脱离父容器文档流防止父容器固宽固高进而导致插槽大小被被父容器限制-->
<view :id="resizeId" :class="`wd-resize__container ${customContainerClass}`">
<!--被监听的插槽-->
<slot />
<!--监听插槽变大-->
<scroll-view
class="wd-resize__wrapper"
:scroll-y="true"
:scroll-top="expandScrollTop"
:scroll-x="true"
:scroll-left="expandScrollLeft"
@scroll="onScrollHandler"
>
<view class="wd-resize__wrapper--placeholder" style="height: 100000px; width: 100000px"></view>
</scroll-view>
<!--监听插槽变小-->
<scroll-view
class="wd-resize__wrapper"
:scroll-y="true"
:scroll-top="shrinkScrollTop"
:scroll-x="true"
:scroll-left="shrinkScrollLeft"
@scroll="onScrollHandler"
>
<view class="wd-resize__wrapper--placeholder" style="height: 250%; width: 250%"></view>
</scroll-view>
</view>
</view>
</template>
<script lang="ts">
export default {
name: 'wd-resize',
options: {
virtualHost: true,
addGlobalClass: true,
styleIsolation: 'shared'
}
}
</script>
<script lang="ts" setup>
import { computed, getCurrentInstance, onMounted, ref } from 'vue'
import { addUnit, objToStyle, uuid } from '../common/util'
import { resizeProps } from './types'
const props = defineProps(resizeProps)
const emit = defineEmits(['resize'])
const expandScrollTop = ref<number>(0)
const shrinkScrollTop = ref<number>(0)
const expandScrollLeft = ref<number>(0)
const shrinkScrollLeft = ref<number>(0)
const height = ref<number>(0)
const width = ref<number>(0)
const scrollEventCount = ref<number>(0)
const rootStyle = computed(() => {
const style: Record<string, string | number> = {
width: addUnit(width.value),
height: addUnit(height.value)
}
return `${objToStyle(style)}${props.customStyle}`
})
let onScrollHandler = () => {}
const { proxy } = getCurrentInstance() as any
const resizeId = ref<string>(`resize${uuid()}`)
onMounted(() => {
// 初始化数据获取
const query = uni.createSelectorQuery().in(proxy).select(`#${resizeId.value}`).boundingClientRect()
query.exec(([res]) => {
// 闭包记录容器高度
let lastHeight = res.height
let lastWidth = res.width
// 立即填充父容器高宽
height.value = lastHeight
width.value = lastWidth
// 监听滚动事件
onScrollHandler = () => {
const query = uni.createSelectorQuery().in(proxy).select(`#${resizeId.value}`).boundingClientRect()
query.exec(([res]) => {
// 前两次滚动事件被触发,说明 created 的修改已渲染,通知用户代码当前容器大小
if (scrollEventCount.value++ === 0) {
const result: Record<string, string | number> = {}
;['bottom', 'top', 'left', 'right', 'height', 'width'].forEach((propName) => {
result[propName] = res[propName]
})
emit('resize', result)
}
// 滚动条拉到底部会触发两次多余的事件,屏蔽掉。
if (scrollEventCount.value < 3) return
// 手动设置父容器高宽,防止父容器坍塌
// 滚动完,重新获取容器新的高度
const newHeight = res.height
const newWidth = res.width
// 立即填充父容器高宽
height.value = newHeight
width.value = newWidth
// 宽高都改变时,只需要触发一次 size 事件
const emitStack: number[] = []
if (newHeight !== lastHeight) {
lastHeight = newHeight
emitStack.push(1)
}
if (newWidth !== lastWidth) {
lastWidth = newWidth
emitStack.push(1)
}
if (emitStack.length !== 0) {
const result: Record<string, any> = {}
;['bottom', 'top', 'left', 'right', 'height', 'width'].forEach((propName) => {
result[propName] = res[propName]
})
emit('resize', result)
}
// 滚动条拉到底部(如果使用 nextTick 效果更佳)
scrollToBottom({
lastWidth: lastWidth,
lastHeight: lastHeight
})
})
}
// 滚动条拉到底部(如果使用 nextTick 效果更佳)
scrollToBottom({
lastWidth: lastWidth,
lastHeight: lastHeight
})
})
})
function scrollToBottom({ lastWidth, lastHeight }: { lastWidth: number; lastHeight: number }) {
expandScrollTop.value = 100000 + lastHeight
shrinkScrollTop.value = 3 * height.value + lastHeight
expandScrollLeft.value = 100000 + lastWidth
shrinkScrollLeft.value = 3 * width.value + lastWidth
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>