uni-app 当滚动区域的高度大于等于视口高度(100%或100vh)时 弹出层中的canvas绘制错位
uni-app 当滚动区域的高度大于等于视口高度(100%或100vh)时 弹出层中的canvas绘制错位
示例代码:
<template>
<view class="app-container">
<view v-for="item in 20" :key="item" class="warp-item" @click="open">
占位元素
</view>
<uni-popup ref="popup" type="bottom" background-color="#FFFFFF">
<canvas canvas-id="my-canvas" class="my-canvas"></canvas>
</uni-popup>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello'
}
},
onLoad() {
const context = uni.createCanvasContext("my-canvas", this)
context.setStrokeStyle("#00ff00")
context.setLineWidth(5)
context.rect(0, 0, 200, 200)
context.stroke()
context.setStrokeStyle("#ff0000")
context.setLineWidth(2)
context.moveTo(160, 100)
context.arc(100, 100, 60, 0, 2 * Math.PI, true)
context.moveTo(140, 100)
context.arc(100, 100, 40, 0, Math.PI, false)
context.moveTo(85, 80)
context.arc(80, 80, 5, 0, 2 * Math.PI, true)
context.moveTo(125, 80)
context.arc(120, 80, 5, 0, 2 * Math.PI, true)
context.stroke()
context.draw()
},
methods: {
open() {
this.$refs.popup.open()
}
}
}
</script>
<style scoped lang="scss">
.app-container {
height: 100vh;
background-color: #CCCCCC;
overflow-y: auto;
.warp-item {
height: 100rpx;
background-color: #FFFFFF;
margin-bottom: 10rpx;
display: flex;
justify-content: center;
align-items: center;
}
.my-canvas {
width: 100%;
height: 500rpx;
}
}
</style>
操作步骤:
滑动列表,滚动到中间或底部,然后点击占位元素,弹窗中的canvas绘制出现偏移,只在真机中存在问题,修改.app-container的高度为height: calc(100vh - 1px);即可解决问题,不知道是否属于bug
预期结果:
滑动列表,滚动到中间或底部,然后点击占位元素,弹窗中的canvas绘制出现偏移,只在真机中存在问题,修改.app-container的高度为height: calc(100vh - 1px);即可解决问题,不知道是否属于bug
实际结果:
滑动列表,滚动到中间或底部,然后点击占位元素,弹窗中的canvas绘制出现偏移,只在真机中存在问题,修改.app-container的高度为height: calc(100vh - 1px);即可解决问题,不知道是否属于bug
bug描述:
当滚动区域的高度大于等于视口高度(100%或100vh),滚动列表后,popup组件中的canvas绘制出现了偏移,且只在真机出现,开发者工具正常展示,修改.app-container的高度为height: calc(100vh - 1px);即可解决问题,不知道是否属于bug
更多关于uni-app 当滚动区域的高度大于等于视口高度(100%或100vh)时 弹出层中的canvas绘制错位的实战教程也可以访问 https://www.itying.com/category-93-b0.html
我测试了你提供的代码,的确有这个 canvas 漂移的问题,真机调试发现 canvas 元素本身的位置是正确的,但实际回执的位置不对。
使用新版本的 canvas 写法,弹窗后重新绘制,位置是正常的,怀疑是微信旧版的 canvas 处理不当。
更多关于uni-app 当滚动区域的高度大于等于视口高度(100%或100vh)时 弹出层中的canvas绘制错位的实战教程也可以访问 https://www.itying.com/category-93-b0.html
好的,感谢反馈,我这边试一下新版写法看看
这是bug复现的代码包
感谢反馈。我验证下你提供的代码
在使用 uni-app
开发时,如果在滚动区域的高度大于或等于视口高度(即 100%
或 100vh
)的情况下,弹出层中的 canvas
绘制出现错位问题,通常是由于 canvas
的绘制位置或尺寸计算不准确导致的。以下是一些可能的解决方案:
1. 检查 canvas
的尺寸和位置
确保 canvas
的尺寸和位置是相对于弹出层的视口计算的,而不是相对于页面的滚动区域。可以使用 uni-app
提供的 getSystemInfoSync
获取视口高度,并根据需要动态设置 canvas
的尺寸。
const systemInfo = uni.getSystemInfoSync();
const canvasHeight = systemInfo.windowHeight; // 视口高度
const canvasWidth = systemInfo.windowWidth; // 视口宽度
在 canvas
的 style
中动态设置高度和宽度:
<canvas canvas-id="myCanvas" :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"></canvas>
2. 使用 fixed
定位弹出层
如果弹出层是浮动的,确保其使用 fixed
定位,而不是 absolute
定位。这样可以避免滚动区域的影响。
.popup {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 999;
}
3. 监听滚动事件并重新绘制
如果滚动区域的高度大于视口高度,可能会导致 canvas
的绘制位置错位。可以通过监听滚动事件,在滚动时重新计算 canvas
的绘制位置。
onPageScroll(e) {
this.scrollTop = e.scrollTop; // 获取滚动距离
this.redrawCanvas(); // 重新绘制 canvas
},
methods: {
redrawCanvas() {
const ctx = uni.createCanvasContext('myCanvas', this);
// 根据 scrollTop 重新计算绘制位置
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctx.draw();
}
}
4. 使用 uni.createSelectorQuery
获取元素位置
通过 uni.createSelectorQuery
获取 canvas
或相关元素的位置信息,确保绘制时使用正确的坐标。
uni.createSelectorQuery()
.select('#myCanvas')
.boundingClientRect((rect) => {
const canvasTop = rect.top; // canvas 距离视口顶部的距离
const canvasLeft = rect.left; // canvas 距离视口左边的距离
// 根据 canvasTop 和 canvasLeft 进行绘制
})
.exec();
5. 避免在滚动区域中使用 canvas
如果可能,尽量避免在滚动区域中使用 canvas
,尤其是在弹出层中。可以将 canvas
放置在固定位置,或者使用其他方式(如图片)替代 canvas
的绘制。
6. 调试和排查
- 使用
console.log
输出canvas
的尺寸、位置以及绘制时的坐标,检查是否存在偏差。 - 使用
uni-app
的调试工具检查canvas
的实际渲染情况。
示例代码
以下是一个完整的示例,结合了上述解决方案:
<template>
<view>
<!-- 滚动区域 -->
<scroll-view scroll-y style="height: 100vh;">
<view style="height: 150vh; background: #f0f0f0;">
<!-- 内容 -->
</view>
</scroll-view>
<!-- 弹出层 -->
<view class="popup" v-if="showPopup">
<canvas canvas-id="myCanvas" :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"></canvas>
</view>
</view>
</template>
<script>
export default {
data() {
return {
showPopup: true,
canvasWidth: 0,
canvasHeight: 0,
};
},
mounted() {
const systemInfo = uni.getSystemInfoSync();
this.canvasWidth = systemInfo.windowWidth;
this.canvasHeight = systemInfo.windowHeight;
this.drawCanvas();
},
methods: {
drawCanvas() {
const ctx = uni.createCanvasContext('myCanvas', this);
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
ctx.draw();
},
},
};
</script>
<style>
.popup {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 999;
}
</style>