uni-app oneplus+8手机canvas超级卡顿

uni-app oneplus+8手机canvas超级卡顿

开发环境 版本号 项目创建方式
Mac 11.3 HBuilderX

产品分类:uniapp/App

PC开发环境操作系统:Mac

PC开发环境操作系统版本号:11.3

HBuilderX类型:正式

HBuilderX版本号:3.2.16

手机系统:Android

手机系统版本号:Android 11

手机厂商:oppo旗下一加手机

手机机型:Oneplus 8T

页面类型:vue

vue版本:vue2

打包方式:云端

项目创建方式:HBuilderX

示例代码:

<view id="canvasPanel" :style="'width:' + ctxWidth + 'px;height:' + ctxWidth + 'px;margin:0 auto;position:relative;'">  
    <canvas type="2d" canvas-id="myCanvas" id="myCanvas"   
    :style="'width:' + ctxWidth + 'px;height:' + ctxWidth + 'px;position:absolute;top:0;left:0;right:0;'" >  
        <p style="color:white;"></p>  
    </canvas>  
    <canvas type="2d" canvas-id="pointCanvas" id="pointCanvas"   
    @touchstart="canvasTouchStartHandler"   
    @touchend="canvasTouchEndHandler" @touchmove="canvasTouchMoveHandler"  
    :style="'width:' + ctxWidth + 'px;height:' + ctxWidth + 'px;position:absolute;top:0;left:0;right:0;z-index:8888;'">  
    </canvas>  
</view>
canvasTouchStartHandler(event) {  
    var eventPos = this.getOtherToucchIntOffset(event);  
    // this.bigEventImg();  
    const { x, y } = event.changedTouches[0];  
    this.reDrawEventImg(x, y);  
},  
canvasTouchEndHandler(event) {  
    var eventPos = this.getToucchEndIntOffset(event);  

    // this.smallerEventImg();  
    const { x, y } = event.changedTouches[0];  
    // this.reDrawEventImg(x, y);  
    this.updateColor(eventPos.X, eventPos.Y);  
},  
getOtherToucchIntOffset(event) {  
    return this.getToucchIntOffset(event.changedTouches[0]);  
},  
getToucchEndIntOffset(event) {  
    return this.getToucchIntOffset(event.changedTouches[0]);  
},  
getToucchIntOffset(touch) {  
    var pageX = parseInt(touch.x);  
    var pageY = parseInt(touch.y);  
    return { X: pageX, Y: pageY };  
},  
getToucchSelectorQuery() {  
    uni.createSelectorQuery().select('#canvasPanel').boundingClientRect(data => {  
        if (!data || data.length === 0) {  
            setTimeout(() => this.getToucchSelectorQuery(), 20)  
            return  
        }  
        this.position = data;  
    }).exec();  
},  
canvasTouchMoveHandler(event) {  
    event.preventDefault();  
    var eventPos = this.getOtherToucchIntOffset(event);  
    // this.reDrawEventImg(eventPos.X, eventPos.Y);  
    this.updateColor(eventPos.X, eventPos.Y);  
},  
reDrawEventImg(mouseX, mouseY) {  
    if (!this.pointInWheel(mouseX, mouseY)) {  
        return;  
    }  
    // this.pointCanvas.clearRect(mouseX - 20, mouseY - 20, 40, 40);  
    this.pointCanvas.drawImage(this.strawIcon, mouseX - 20, mouseY - 20, 40, 40);  
    this.pointCanvas.draw()  
},  
generateImageData() {  
    const that = this;  
    uni.canvasGetImageData({  
      canvasId: 'myCanvas',  
      x: 0,  
      y: 0,  
      width: that.ctxWidth,  
      height: that.ctxHeight,  
      success(res) {  
        that.imageData = res.data;  
      }  
    })  
},  
updateColor(mouseX, mouseY) {  
    if (this.pointInWheel(mouseX, mouseY) == false) {  
        return;  
    }  
    // 3. redraw the wheel event img  
    this.reDrawEventImg(mouseX, mouseY);  

    const that = this;  
    if(this.imageData.length > 0) {  
        let data = this.imageData;  
        var i = ((mouseY * that.ctxWidth) + mouseX) * 4;  
        //  get RGBA values  
        var hexVal = (that.d2Hex(data[i]) + that.d2Hex(data[i + 1]) + that.d2Hex(data[i + 2]));  
        that.setCurrentColor(data[i], data[i + 1], data[i + 2]);  
        that.hexVal = hexVal  
    } else {  
        uni.canvasGetImageData({  
          canvasId: 'myCanvas',  
          x: 0,  
          y: 0,  
          width: that.ctxWidth,  
          height: that.ctxHeight,  
          success(res) {  
            var data = res.data;  
            that.imageData = data;  
            var i = ((mouseY * that.ctxWidth) + mouseX) * 4;  
            //  get RGBA values  
            var hexVal = (that.d2Hex(data[i]) + that.d2Hex(data[i + 1]) + that.d2Hex(data[i + 2]));  
            that.setCurrentColor(data[i], data[i + 1], data[i + 2]);  
            that.hexVal = hexVal  
          }  
        })  
    }  
}

操作步骤: 参照以上代码实现方式

预期结果: 色环取值滑动流畅,不卡顿

实际结果: 色环取值滑动超级卡顿

bug描述: canvas实时画图超级卡顿


更多关于uni-app oneplus+8手机canvas超级卡顿的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于uni-app oneplus+8手机canvas超级卡顿的实战教程也可以访问 https://www.itying.com/category-93-b0.html


根据你的代码和描述,问题主要出在频繁调用uni.canvasGetImageData导致的性能瓶颈。在touchmove事件中实时获取整个canvas的像素数据,对OnePlus 8这类机型也会造成明显卡顿。

核心优化方案:

  1. 避免高频获取完整ImageData

    • generateImageData()的调用移至色环初始化阶段,仅执行一次
    • updateColor中直接使用已缓存的this.imageData
  2. 优化坐标计算逻辑

    updateColor(mouseX, mouseY) {
      if (!this.pointInWheel(mouseX, mouseY)) return;
      
      // 使用缓存的imageData
      if (this.imageData && this.imageData.length > 0) {
        const index = ((mouseY * this.ctxWidth) + mouseX) * 4;
        const [r, g, b] = [
          this.imageData[index],
          this.imageData[index + 1], 
          this.imageData[index + 2]
        ];
        
        this.setCurrentColor(r, g, b);
        this.hexVal = this.d2Hex(r) + this.d2Hex(g) + this.d2Hex(b);
      }
      
      // 减少重绘频率
      this.throttleRedraw(mouseX, mouseY);
    }
    
  3. 添加绘制节流

    let lastDrawTime = 0;
    throttleRedraw(x, y) {
      const now = Date.now();
      if (now - lastDrawTime > 16) { // 约60fps
        this.reDrawEventImg(x, y);
        lastDrawTime = now;
      }
    }
回到顶部