| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- <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>
|