vue for循环源码实现
Vue 中 v-for 的源码实现
Vue 的 v-for 指令通过编译器和运行时协作实现循环渲染。其核心逻辑位于虚拟 DOM 的 patch 阶段,通过 diff 算法高效更新列表。
模板编译阶段
模板中的 v-for 会被编译器转换为 _l(renderList)函数调用。例如:
<div v-for="(item, index) in items" :key="item.id">{{ item.name }}</div>
编译为:
_l(items, (item, index) => _c('div', { key: item.id }, [_v(_s(item.name))]))
运行时实现
_l 函数(src/core/instance/render-helpers/list.js)会遍历数组或对象,为每个元素生成对应的 VNode:
export function renderList (
val: any,
render: (
val: any,
keyOrIndex: string | number,
index?: number
) => VNode
): ?Array<VNode> {
if (Array.isArray(val)) {
return val.map((item, i) => render(item, i))
} else if (typeof val === 'number') {
return new Array(val).fill(null).map((_, i) => render(i + 1, i))
} else if (isObject(val)) {
return Object.keys(val).map(key => render(val[key], key))
}
}
Key 的作用
在 patch 阶段(src/core/vdom/patch.js),Vue 通过 sameVnode 比较 key 和标签类型:
function sameVnode (a, b) {
return (
a.key === b.key &&
a.tag === b.tag &&
/* 其他条件 */
)
}
Key 帮助 Vue 识别节点身份,实现高效的原地复用或重新排序。
性能优化策略
对于大型列表,Vue 的 diff 算法采用双端比较策略:
- 新旧节点首尾交叉对比
- 建立 key 到 index 的映射表
- 移动而非重新创建可复用的 DOM 节点
响应式更新机制
当 items 变化时:
- 依赖收集系统触发组件重新渲染
- 新的
_l调用生成新的 VNode 数组 patch阶段通过 diff 算法最小化 DOM 操作
这种实现方式平衡了声明式编程的便利性和手动优化的性能控制能力。







