必须用 markraw 包裹第三方插件实例,因其依赖原始引用、自有状态或特殊属性访问,被 vue 响应式系统代理会导致 === 失效、方法失上下文、symbol 属性拦截失败及无效更新。

直接用 markRaw 包裹第三方插件实例,就能让它彻底避开 Vue 的响应式劫持——既不被 Proxy 代理,也不触发依赖收集和视图更新。
为什么第三方插件实例必须 markRaw?
很多插件(如 ECharts、Three.js、MapLibre、Canvas 2D 上下文)内部依赖原始引用、自有状态管理或特殊属性访问方式。一旦被 Vue 响应式系统包裹,容易出现:
- === 判断失效(代理对象 ≠ 原始实例)
- 方法调用丢失上下文(如
chart.setOption()报错或静默失败) - getter/setter 或 Symbol 属性无法正确拦截
- 频繁触发无意义的更新,拖慢渲染甚至导致内存泄漏
典型写法:初始化后立刻标记
关键原则:markRaw 必须在实例创建后、进入 reactive/ref 之前调用。
✅ 正确示例(ECharts):
import { markRaw, ref, onMounted } from 'vue'<br>import * as echarts from 'echarts'<br><br>export default {<br> setup() {<br> const chartRef = ref(null)<br> const chartInstance = ref(null)<br><br> onMounted(() => {<br> const el = chartRef.value<br> if (el) {<br> // 创建后立即 markRaw<br> chartInstance.value = markRaw(echarts.init(el))<br> }<br> })<br><br> return { chartRef, chartInstance }<br> }<br>}❌ 错误写法(让 ref 自动代理):
const chartInstance = ref(echarts.init(el)) // Vue 会尝试 Proxy 包装,大概率出错
其他常见第三方对象场景
-
Three.js:用
markRaw(new THREE.Scene())、markRaw(renderer) -
Canvas 渲染上下文:
markRaw(canvas.getContext('2d')) -
WebSocket 实例:
markRaw(new WebSocket(url)),配合手动消息处理 -
地图库(Leaflet / MapLibre):
markRaw(mapInstance),避免 Vue 干预其内部事件系统
搭配 shallowRef 提升控制精度
如果只想让“持有实例的 ref”本身响应式(比如切换图表容器),但实例内容不响应,推荐组合使用:
import { markRaw, shallowRef } from 'vue'<br><br>const chartInstance = shallowRef(null)<br>chartInstance.value = markRaw(echarts.init(el))<br>// ✅ chartInstance 是响应式 ref<br>// ❌ chartInstance.value 不会被递归代理,保持原样这样既保留了 ref 的响应式能力(如用于 v-if 切换),又完全规避了对插件实例的劫持。










