这一节肯定能完!

  

  经过DOM字符串的AST转化,再通过render变成vnode,最后就剩下patch到页面上了。

  render函数跑完应该是在这里:

    function mountComponent(vm, el, hydrating) {
vm.$el = el;
if (!vm.$options.render) {
vm.$options.render = createEmptyVNode; {
// warning
}
}
// beforeMount var updateComponent;
/* istanbul ignore if */
if ("development" !== 'production' && config.performance && mark) {
updateComponent = function() {
// dev render
};
} else {
updateComponent = function() {
vm._update(vm._render(), hydrating);
};
} // code... // mounted
return vm
}

  vm._render()会生成一个vnode看,接下来调用_update渲染页面,如下:

    Vue.prototype._update = function(vnode, hydrating) {
var vm = this;
// beforeUpdate // code... if (!prevVnode) {
// initial render
vm.$el = vm.__patch__(
vm.$el, vnode, hydrating, false /* removeOnly */ ,
vm.$options._parentElm,
vm.$options._refElm
);
} else {
// updates
vm.$el = vm.__patch__(prevVnode, vnode);
} // code...
}; Vue$3.prototype.__patch__ = inBrowser ? patch : noop; var patch = createPatchFunction({
nodeOps: nodeOps,
modules: modules
}); function createPatchFunction(backend) {
var i, j;
var cbs = {}; var modules = backend.modules;
var nodeOps = backend.nodeOps; for (i = 0; i < hooks.length; ++i) {
// hook...
} // fn... return function patch(oldVnode, vnode, hydrating, removeOnly, parentElm, refElm) {
// code... if (isUndef(oldVnode)) {
// component...
} else {
var isRealElement = isDef(oldVnode.nodeType);
if (!isRealElement && sameVnode(oldVnode, vnode)) {
// patch existing root node
} else {
// SSR or hydrating var oldElm = oldVnode.elm;
var parentElm$1 = nodeOps.parentNode(oldElm);
createElm(
vnode,
insertedVnodeQueue,
oldElm._leaveCb ? null : parentElm$1,
nodeOps.nextSibling(oldElm)
); //code...
}
} invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch);
return vnode.elm
}
}

  由于是初始化页面,所有在update的过程中,oldVNode被设置为空的div虚拟DOM,然后与生成的虚拟DOM进行替换。

  核心细节在上述代码中的createElm函数:

    // vnode => 生成的vnode
// insertedVnodeQueue => []
// parentElm => body
// refElm => #text
// nested => undefined
function createElm(vnode, insertedVnodeQueue, parentElm, refElm, nested) {
vnode.isRootInsert = !nested; // for transition enter check
if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
return
} var data = vnode.data;
var children = vnode.children;
var tag = vnode.tag;
if (isDef(tag)) {
// pre... vnode.elm = vnode.ns ?
nodeOps.createElementNS(vnode.ns, tag) :
// 调用这个生成一个tag标签
nodeOps.createElement(tag, vnode);
setScope(vnode); {
// 处理子节点
// 子节点是5个vnode组成的数据 因此会循环调用本函数
createChildren(vnode, children, insertedVnodeQueue);
if (isDef(data)) {
// 生成DOM节点的属性
invokeCreateHooks(vnode, insertedVnodeQueue);
}
// 将子节点插入到父节点中
// 处理到最外层节点 页面会渲染
insert(parentElm, vnode.elm, refElm);
} if ("development" !== 'production' && data && data.pre) {
inPre--;
}
} else if (isTrue(vnode.isComment)) {
vnode.elm = nodeOps.createComment(vnode.text);
insert(parentElm, vnode.elm, refElm);
} else {
vnode.elm = nodeOps.createTextNode(vnode.text);
insert(parentElm, vnode.elm, refElm);
}
}

  其实,这个普通的patch没有区别,只是由于是多个标签,所以会有兄弟元素,在插入节点会调用insertBefore进行插入,最后5个a标签依次插入生成的div,然后div插入body标签完成页面渲染。

  虽然循环生成a标签以及其属性比较麻烦,但是由于整个标签是一次性插入body中,所以对于性能也没有什么影响。

  完事,确实没什么好说的,至于v-if、v-show那些,有空一次性写完。

Vue源码后记-vFor列表渲染(3)的更多相关文章

  1. Vue源码后记-vFor列表渲染(1)

    钩子函数比较简单,没有什么意思,这一节搞点大事情 => 源码中v-for的渲染过程. vue的内置指令包含了v-html.v-if.v-once.v-bind.v-on.v-show等,先从一个 ...

  2. Vue源码后记-vFor列表渲染(2)

    这一节争取搞完! 回头来看看那个render代码,为了便于分析,做了更细致的注释: (function() { // 这里this指向vue对象 下面的所有方法默认调用Vue$3.prototype上 ...

  3. Vue源码后记-其余内置指令(3)

    其实吧,写这些后记我才真正了解到vue源码的精髓,之前的跑源码跟闹着玩一样. go! 之前将AST转换成了render函数,跳出来后,由于仍是字符串,所以调用了makeFunction将其转换成了真正 ...

  4. Vue源码后记-钩子函数

    vue源码的马拉松跑完了,可以放松一下写点小东西,其实源码讲20节都讲不完,跳了好多地方. 本人技术有限,无法跟大神一样,模拟vue手把手搭建一个MVVM框架,然后再分析原理,只能以门外汉的姿态简单过 ...

  5. Vue源码后记-其余内置指令(2)

    -- 指令这个讲起来还有点复杂,先把html弄上来: <body> <div id='app'> <div v-if="vIfIter" v-bind ...

  6. Vue源码后记-其余内置指令(1)

    把其余的内置指令也搞完吧,来一个全家桶. 案例如下: <body> <div id='app'> <div v-if="vIfIter" v-bind ...

  7. Vue源码后记-更多options参数(1)

    我是这样计划的,写完这个还写一篇数据变动时,VNode是如何更新的,顺便初探一下diff算法. 至于vue-router.vuex等插件源码,容我缓一波好吧,vue看的有点伤. 其实在之前讲其余内置指 ...

  8. vue项目开发之v-for列表渲染的坑

    不知道大家在用vue开发的过程中有没有遇到过在使用v-for的时候会出现大片的黄色警告,比如下图: 其实这是因为没有写key的原因 :key是为vue的响应式渲染提供方法,在列表中单条数据改变的情况下 ...

  9. vue源码解析阅读列表

    https://zhuanlan.zhihu.com/p/24435564 开发vue(或类似的MVVM框架)的过程中,需要面对的主要问题有哪些? 剖析vue实现原理,自己动手实现mvvm 官网介绍

随机推荐

  1. pl/sql developer 连接服务器上的数据库

    1, 在本地安装的Oracle中找到目录 oracle\product\11.2.0\dbhome_1\network\admin, 它下面一般有两个文件可以进行编辑tnsnames.ora   li ...

  2. 详解go语言的array和slice 【二】

    上一篇已经讲解过,array和slice的一些基本用法,使用array和slice时需要注意的地方,特别是slice需要注意的地方比较多.上一篇的最后讲解到创建新的slice时使用第三个索引来限制sl ...

  3. Linux 常用命令之二

    整理以前学习Linux的笔记. 查找目录.查看当前所在路径.新建文件.查看文件内容.修改文件内容.压缩文件操作.搜索命令.管道命令.查看进程.终止进程.查看端口. 7,命令find--查找目录 fin ...

  4. mvc一对多模型表单的快速构建

    功能需求描述 Q:在实际的开发中,经常会遇到一个模型中包含有多个条目的表单.如何将数据提交到后台? A: 以数组的形式提交到后台就Ok了(真的那么简单么,如果再嵌套一层呢?) A2:拆分多个模型,映射 ...

  5. C语言编译过程及数据类型

    写在前面 C语言可以称得上是高级语言中的低级语言,接下来一段时间,我会写一下文章关于c语言,把它的神秘面纱一 一揭开.下面主要是c语言的C语言编译过程及数据类型 源文件编译过程 为了使计算机能执行高级 ...

  6. 关于VisualStudio一运行带中文程序就出错或输出乱码问题的解决

    昨晚纠结了老半天,各种查资料最后终于解决了此问题.今天上午便来编写这篇随笔了!(由于问题已解决,未附上出状况的截图)以下是解决办法: 此问题的原因应是文件的编码问题,选定好出错的文件后,在菜单栏中选择 ...

  7. JQuery&原生js ——实现剪刀石头布小游戏

    前言 jQuery是一个快速.简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库( 或JavaScript框架).jQuery设计的宗旨是“write L ...

  8. TCP/IP 第二章

    1, 以太网的封装格式.其中MTU的最小值为46字节,所以,ARP和RARP需要添加18字节的PAD.CRC是检验和.(循环冗余检验) 2,SLIP:(串行线路ip) 首尾一个end字符加以区分数据. ...

  9. Treblecross 博弈SG值

    Treblecross is a two player game where the goal is to get three X in a row on a one-dimensional boar ...

  10. PHP和JS判断变量是否定义

    PHP中: 通过isset(变量名)来判断,定义返回true/未定义返回false JS中: 通过typeof来判断.