renderjs是uni-app在非h5平台绕过vue虚拟dom直接操作原生渲染层的机制,因vue响应式在小程序中编译为setdata易卡顿,而renderjs运行于渲染线程,可直接调用queryselector等api。

RenderJS 是什么,为什么不能直接用 Vue 操作 DOM
RenderJS 不是 Vue 的补充,而是 uni-app 在非 H5 平台(如小程序、App)上绕过 Vue 虚拟 DOM 直接操作原生渲染层的机制。Vue 的响应式更新在小程序里会被编译成 setData,频繁触发会导致卡顿;而 RenderJS 运行在「渲染线程」,能直接调用 querySelector、appendChild 等原生 API,跳过逻辑层通信开销。
但要注意:renderjs 只支持 vue 文件中的 <script type="renderjs"></script> 块,且仅在 App 和微信/支付宝等小程序生效,H5 下不运行。
怎么写一个可用的 RenderJS 脚本
必须满足三个硬性条件,缺一不可:
-
type="renderjs"的<script></script>标签需放在<template></template>后、普通<script></script>前 - 导出对象必须有
mounted方法,否则不执行 - 所有 DOM 操作必须在
mounted或其调用的函数中进行,不能在顶层直接写document.getElementById
示例结构:
<template><view id="list-container"></view></template><script type="renderjs">
export default {
mounted() {
const container = document.getElementById('list-container')
const item = document.createElement('div')
item.textContent = 'renderjs item'
container.appendChild(item)
}
}
</script>
RenderJS 和 Vue 之间怎么传数据
只能单向通信:Vue → RenderJS,靠 props;RenderJS → Vue,靠 this.$emit(注意不是 $emit,也不是 uni.$emit)。
常见错误现象:
- 在 RenderJS 中访问
this.$parent或this.data—— 报错,不存在 - 试图用
props接收响应式对象并监听变化 —— 不会触发,props是初始化快照,后续 Vue 层改了它不会同步 - 在
mounted外调用this.$emit—— 无效,必须等 mounted 执行完才注册好事件通道
正确做法:Vue 层通过 :props="{ list: dataList }" 传原始数组,RenderJS 内部做一次渲染;列表变化时,Vue 主动再调用 this.$refs.xxx.updateList(newList)(需提前在 renderjs 导出方法)。
哪些场景真适合用 RenderJS,哪些只是自找麻烦
适合:
- 高频滚动容器(如聊天消息流、长列表),需局部 DOM 更新避免整块重绘
- Canvas / WebGL 渲染区域需要直连 canvas.getContext
- 第三方 UI 库(如 ECharts 小程序版)依赖原生节点操作
不适合:
- 简单表单交互、按钮点击反馈 —— Vue 响应式足够快,加 RenderJS 反而增加维护成本
- 跨平台一致性要求高的组件 —— RenderJS 在 H5 不生效,得额外写 fallback
- 需要和 Vuex/Pinia 深度联动的状态管理 —— RenderJS 拿不到 store 实例,也不该拿
性能影响很实际:一次 this.$emit 触发 Vue 层更新,本质还是走 setData,所以别指望它替代所有响应式逻辑。真正省的是「渲染层内部重排重绘」,不是「通信链路」。
容易被忽略的一点:RenderJS 脚本无法使用 ES6+ 动态 import、不能访问 localStorage、没有 window 对象,调试时 console.log 输出位置也和普通 JS 不同——它出现在「渲染进程」控制台,不是浏览器或 App 的主控制台。










