示例源码如下,请查看 pre > code 标签中的内容
<template>
<view style="padding-bottom: var(--uni-safe-area-inset-bottom);">
<page-intro content="本页演示 uni.createResizeObserver:监听元素尺寸变化,回调中可获取 contentRect(x、y、width、height)。含 view 嵌套、text、image、scroll-view 等组件的监听示例;可点击方块改宽高、改变字体/图片/scroll-view 尺寸,支持停止/恢复监听、隐藏/显示元素。"></page-intro>
<text>点击蓝色或红色方块区域会修改元素宽高</text>
<view v-show="boxDisplay" style="align-items: center; justify-content: center; margin: 10px;">
<view
style="width: 140px; height: 140px; background-color: blue; align-items: center; justify-content: center; padding: 5px;"
id="outBox" @click="outBoxClick">
<view style="width: 80px; height: 80px; background-color: red; padding: 5px;" id="innerBox"
@click="innerBoxClick"></view>
</view>
</view>
<button @click="revertBoxSize">还原修改前元素宽高</button>
<button @click="toggleDisplay">{{boxDisplay? '隐藏元素': '显示元素'}}</button>
<button @click='cancelListen'>停止监听</button>
<button @click='goOnListen'>恢复监听</button>
<view>
<text class="info-text">蓝色方块元素:</text>
<view class="info-item">
<text class="info-text">{{outBoxSizeInfo}}</text>
</view>
<text class="info-text" style="margin-top: 20px;">红色方块元素:</text>
<view class="info-item">
<text class="info-text">{{innerBoxSizeInfo}}</text>
</view>
</view>
<!-- text 组件示例 -->
<view class="uni-common-mt" v-show="textImageScrollViewDisplay">
<text class="uni-title-text">Text 组件示例:</text>
<text id="testText" :style="{fontSize: textFontSize + 'px', color: '#333'}">这是一个可以改变字体大小的文本</text>
<button @click="changeTextSize">改变文本字体大小</button>
<view class="info-item">
<text class="info-text">{{data.textSizeInfo}}</text>
</view>
</view>
<!-- image 组件示例 -->
<view class="uni-common-mt" v-show="textImageScrollViewDisplay">
<text class="uni-title-text">Image 组件示例:</text>
<image id="testImage" :style="{width: imageWidth + 'px', height: imageHeight + 'px'}" src="/static/test-image/logo.png" mode="aspectFit"></image>
<button @click="changeImageSize">改变图片尺寸</button>
<view class="info-item">
<text class="info-text">{{data.imageSizeInfo}}</text>
</view>
</view>
<!-- scroll-view 组件示例 -->
<view class="uni-common-mt" v-show="textImageScrollViewDisplay">
<text class="uni-title-text">Scroll-view 组件示例:</text>
<scroll-view id="testScrollView" :style="{width: scrollViewWidth + 'px', height: '100px', border: '1px solid #ccc'}" >
<view style="padding: 10px;">
<text>这是 scroll-view 内的内容</text>
<text v-for="i in 10" :key="i">第 {{i}} 行内容</text>
</view>
</scroll-view>
<button @click="changeScrollViewSize">改变 scroll-view 宽度</button>
<view class="info-item">
<text class="info-text">{{data.scrollViewSizeInfo}}</text>
</view>
</view>
</view>
</template>
<script setup lang="ts">
const outBoxSizeInfo = ref("")
const innerBoxSizeInfo = ref("")
const offset = ref(2)
const boxDisplay = ref(false)
let outBoxElement: UniElement | null = null
let innerBoxElement: UniElement | null = null
let resizeObserver: UniResizeObserver | null = null
// text 组件相关
const textFontSize = ref(16)
let textElement: UniElement | null = null
// image 组件相关
const imageWidth = ref(100)
const imageHeight = ref(100)
let imageElement: UniElement | null = null
// scroll-view 组件相关
const scrollViewWidth = ref(300)
let scrollViewElement: UniElement | null = null
// 控制 text、image、scroll-view 的显示
const textImageScrollViewDisplay = ref(false)
type ContentRectType = {
x: number,
y: number,
width: number,
height: number,
}
type BoxSizeType = {
blockSize: number,
inlineSize: number,
}
type ResizeInfoType = {
contentRect: ContentRectType,
borderBoxSize: BoxSizeType,
contentBoxSize: BoxSizeType,
// #ifndef WEB
devicePixelContentBoxSize: BoxSizeType,
// #endif
}
type DataType = {
outBoxElementOnResize: boolean,
textSizeInfo: string,
imageSizeInfo: string,
scrollViewSizeInfo: string,
textSizeInfoObj: ResizeInfoType | null,
imageSizeInfoObj: ResizeInfoType | null,
scrollViewSizeInfoObj: ResizeInfoType | null,
}
const data = reactive({
outBoxElementOnResize: false,
textSizeInfo: "",
imageSizeInfo: "",
scrollViewSizeInfo: "",
textSizeInfoObj: null,
imageSizeInfoObj: null,
scrollViewSizeInfoObj: null,
} as DataType)
function innerBoxClick() {
if (innerBoxElement != null) {
innerBoxElement!.style.setProperty("width", innerBoxElement!.offsetWidth + offset.value + 'px')
innerBoxElement!.style.setProperty("height", innerBoxElement!.offsetWidth + offset.value + 'px')
}
}
function outBoxClick() {
if (outBoxElement != null) {
outBoxElement!.style.setProperty("width", outBoxElement!.offsetWidth + offset.value + 'px')
outBoxElement!.style.setProperty("height", outBoxElement!.offsetWidth + offset.value + 'px')
}
}
function revertBoxSize() {
if (outBoxElement != null) {
outBoxElement!.style.setProperty("width", "140px")
outBoxElement!.style.setProperty("height", "140px")
}
if (innerBoxElement != null) {
innerBoxElement!.style.setProperty("width", "80px")
innerBoxElement!.style.setProperty("height", "80px")
}
}
//自动化测试专用
function setOutBoxMarginLeft(value : string) {
if (outBoxElement != null) {
data.outBoxElementOnResize = false
outBoxElement!.style.setProperty("margin-left", value)
}
}
function toggleDisplay() {
boxDisplay.value = !boxDisplay.value
}
function analysisResizeObserverEntry(entry : UniResizeObserverEntry) : string {
const contentBoxSize = entry.contentBoxSize[0]
const borderBoxSize = entry.borderBoxSize[0]
// #ifndef WEB
const devicePixelContentBoxSize = entry.devicePixelContentBoxSize[0]
return "borderBoxSize: \n{blockSize:" + borderBoxSize.blockSize + ", inlineSize:" + borderBoxSize.inlineSize + "}\n" +
"contentBoxSize: \n{blockSize:" + contentBoxSize.blockSize + ", inlineSize:" + contentBoxSize.inlineSize + "}\n" +
"devicePixelContentBoxSize: \n{blockSize:" + devicePixelContentBoxSize.blockSize + ", inlineSize:" + devicePixelContentBoxSize.inlineSize + "}\n" +
"contentRect: \n{x:" + entry.contentRect.x + ", y:" + entry.contentRect.y + ", width:" + entry.contentRect.width + ", height:" + entry.contentRect.height + "}"
// #endif
// #ifdef WEB
return "borderBoxSize: \n{blockSize:" + borderBoxSize.blockSize + ", inlineSize:" + borderBoxSize.inlineSize + "}\n" +
"contentBoxSize: \n{blockSize:" + contentBoxSize.blockSize + ", inlineSize:" + contentBoxSize.inlineSize + "}\n" +
"contentRect: \n{x:" + entry.contentRect.x + ", y:" + entry.contentRect.y + ", width:" + entry.contentRect.width + ", height:" + entry.contentRect.height + "}"
// #endif
}
// 将 ResizeObserverEntry 转换为 ResizeInfoType 对象(用于测试)
function convertResizeEntryToInfo(entry : UniResizeObserverEntry) : ResizeInfoType {
const contentBoxSize = entry.contentBoxSize[0]
const borderBoxSize = entry.borderBoxSize[0]
// #ifndef WEB
const devicePixelContentBoxSize = entry.devicePixelContentBoxSize[0]
return {
contentRect: {
x: entry.contentRect.x,
y: entry.contentRect.y,
width: entry.contentRect.width,
height: entry.contentRect.height,
} as ContentRectType,
borderBoxSize: {
blockSize: borderBoxSize.blockSize,
inlineSize: borderBoxSize.inlineSize,
} as BoxSizeType,
contentBoxSize: {
blockSize: contentBoxSize.blockSize,
inlineSize: contentBoxSize.inlineSize,
} as BoxSizeType,
devicePixelContentBoxSize: {
blockSize: devicePixelContentBoxSize.blockSize,
inlineSize: devicePixelContentBoxSize.inlineSize,
} as BoxSizeType,
} as ResizeInfoType
// #endif
// #ifdef WEB
return {
contentRect: {
x: entry.contentRect.x,
y: entry.contentRect.y,
width: entry.contentRect.width,
height: entry.contentRect.height,
} as ContentRectType,
borderBoxSize: {
blockSize: borderBoxSize.blockSize,
inlineSize: borderBoxSize.inlineSize,
} as BoxSizeType,
contentBoxSize: {
blockSize: contentBoxSize.blockSize,
inlineSize: contentBoxSize.inlineSize,
} as BoxSizeType,
} as ResizeInfoType
// #endif
}
function cancelListen() {
// resizeObserver?.unobserve()
resizeObserver!.unobserve(outBoxElement!)
resizeObserver!.unobserve(innerBoxElement!)
}
function goOnListen() {
resizeObserver!.observe(outBoxElement!)
resizeObserver!.observe(innerBoxElement!)
}
// 改变 text 字体大小
function changeTextSize() {
textFontSize.value = textFontSize.value + 2
}
// 改变 image 尺寸
function changeImageSize() {
imageWidth.value = imageWidth.value + 10
imageHeight.value = imageHeight.value + 10
}
// 改变 scroll-view 宽度
function changeScrollViewSize() {
scrollViewWidth.value = scrollViewWidth.value + 20
}
onBackPress(() : boolean => {
if (resizeObserver != null) {
resizeObserver!.disconnect()
}
return false
})
onReady(() => {
if (resizeObserver == null) {
resizeObserver = new UniResizeObserver((entries : Array<UniResizeObserverEntry>) => {
entries.forEach(entry => {
if (entry.target == outBoxElement) {
outBoxSizeInfo.value = analysisResizeObserverEntry(entry)
data.outBoxElementOnResize = true
} else if (entry.target == innerBoxElement) {
innerBoxSizeInfo.value = analysisResizeObserverEntry(entry)
} else if (entry.target == textElement) {
data.textSizeInfo = analysisResizeObserverEntry(entry)
data.textSizeInfoObj = convertResizeEntryToInfo(entry)
} else if (entry.target == imageElement) {
data.imageSizeInfo = analysisResizeObserverEntry(entry)
data.imageSizeInfoObj = convertResizeEntryToInfo(entry)
} else if (entry.target == scrollViewElement) {
data.scrollViewSizeInfo = analysisResizeObserverEntry(entry)
data.scrollViewSizeInfoObj = convertResizeEntryToInfo(entry)
}
})
})
outBoxElement = uni.getElementById("outBox")
if (outBoxElement != null) {
resizeObserver!.observe(outBoxElement!)
}
innerBoxElement = uni.getElementById("innerBox")
if (innerBoxElement != null) {
resizeObserver!.observe(innerBoxElement!)
}
//监听 text 组件
textElement = uni.getElementById("testText")
if (textElement != null) {
resizeObserver!.observe(textElement!)
}
//监听 image 组件
imageElement = uni.getElementById("testImage")
if (imageElement != null) {
resizeObserver!.observe(imageElement!)
}
//监听 scroll-view 组件
scrollViewElement = uni.getElementById("testScrollView")
if (scrollViewElement != null) {
resizeObserver!.observe(scrollViewElement!)
}
boxDisplay.value = true
textImageScrollViewDisplay.value = true
}
})
defineExpose({
data,
setOutBoxMarginLeft,
changeTextSize,
changeImageSize,
changeScrollViewSize
})
</script>
<style>
.info-item {
flex-direction: row;
}
.info-text {
font-size: 14px;
}
</style>