You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue中调用three.js截图报错:'modelViewMatrix'为只读不可配置属性

问题分析与解决方案

问题根源

这个错误是因为Vue的响应式代理与Three.js内部属性访问不兼容导致的:

  • Vue3会对data、ref、reactive中的对象生成Proxy代理;Vue2则通过Object.defineProperty做响应式处理。
  • Three.js核心类(如Camera、Scene、WebGLRenderer)内部包含大量只读、不可配置的底层属性(比如报错中的modelViewMatrix),当这些实例被Vue代理后,Three.js访问属性时会拿到代理后的对象,而非原始的Three.js内部实例(如Matrix4),触发类型校验失败。

键盘触发正常是因为window事件绑定脱离了Vue的响应式上下文执行,而按钮点击属于Vue事件处理逻辑,会在响应式代理的上下文里访问这些实例。

解决步骤

1. 禁止Vue代理Three.js核心实例

不要将camera、scene、renderer放在Vue的响应式数据中:

  • Vue3:使用markRaw标记实例为非响应式,避免被Proxy代理
import { markRaw } from 'vue';
import * as THREE from 'three';

// 在setup或组件初始化时:
const camera = markRaw(new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000));
const scene = markRaw(new THREE.Scene());
const renderer = markRaw(new THREE.WebGLRenderer({ antialias: true }));

// 之后将这些实例挂载到组件上下文(如this,或通过expose暴露)
  • Vue2:直接在created钩子中初始化实例,不要放在data选项里
import * as THREE from 'three';

export default {
  created() {
    // 直接挂载到this,不经过data的响应式处理
    this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    this.scene = new THREE.Scene();
    this.renderer = new THREE.WebGLRenderer({ antialias: true });
  }
}

2. 优化截图函数(可选)

移除重复的renderer.render调用,简化逻辑:

async snapShot() {
  const { camera, scene, renderer } = this;
  if (!camera || !scene || !renderer) return null;

  const strMime = "image/jpeg";
  // 仅渲染一次场景
  renderer.render(scene, camera);

  return new Promise((resolve) => {
    renderer.domElement.toBlob(resolve, strMime);
  });
}

3. 验证按钮事件绑定

确保按钮点击的事件处理函数中this指向正确,比如Vue模板中使用:

<button @click="testClick">截图</button>

组件中:

methods: {
  async testClick() {
    const blob = await this.snapShot();
    // 处理blob数据
  }
}

内容的提问来源于stack exchange,提问作者USMANHEART

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 10:01:01