Vue源码后记-vFor列表渲染(3)
这一节肯定能完!
经过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)的更多相关文章
- Vue源码后记-vFor列表渲染(1)
钩子函数比较简单,没有什么意思,这一节搞点大事情 => 源码中v-for的渲染过程. vue的内置指令包含了v-html.v-if.v-once.v-bind.v-on.v-show等,先从一个 ...
- Vue源码后记-vFor列表渲染(2)
这一节争取搞完! 回头来看看那个render代码,为了便于分析,做了更细致的注释: (function() { // 这里this指向vue对象 下面的所有方法默认调用Vue$3.prototype上 ...
- Vue源码后记-其余内置指令(3)
其实吧,写这些后记我才真正了解到vue源码的精髓,之前的跑源码跟闹着玩一样. go! 之前将AST转换成了render函数,跳出来后,由于仍是字符串,所以调用了makeFunction将其转换成了真正 ...
- Vue源码后记-钩子函数
vue源码的马拉松跑完了,可以放松一下写点小东西,其实源码讲20节都讲不完,跳了好多地方. 本人技术有限,无法跟大神一样,模拟vue手把手搭建一个MVVM框架,然后再分析原理,只能以门外汉的姿态简单过 ...
- Vue源码后记-其余内置指令(2)
-- 指令这个讲起来还有点复杂,先把html弄上来: <body> <div id='app'> <div v-if="vIfIter" v-bind ...
- Vue源码后记-其余内置指令(1)
把其余的内置指令也搞完吧,来一个全家桶. 案例如下: <body> <div id='app'> <div v-if="vIfIter" v-bind ...
- Vue源码后记-更多options参数(1)
我是这样计划的,写完这个还写一篇数据变动时,VNode是如何更新的,顺便初探一下diff算法. 至于vue-router.vuex等插件源码,容我缓一波好吧,vue看的有点伤. 其实在之前讲其余内置指 ...
- vue项目开发之v-for列表渲染的坑
不知道大家在用vue开发的过程中有没有遇到过在使用v-for的时候会出现大片的黄色警告,比如下图: 其实这是因为没有写key的原因 :key是为vue的响应式渲染提供方法,在列表中单条数据改变的情况下 ...
- vue源码解析阅读列表
https://zhuanlan.zhihu.com/p/24435564 开发vue(或类似的MVVM框架)的过程中,需要面对的主要问题有哪些? 剖析vue实现原理,自己动手实现mvvm 官网介绍
随机推荐
- 关于Tomcat一些启动错误的解决方法
一.Eclipse tomcat 启动超时: 错误内容: Server JBoss v4.0 at localhost was unable to start within 50 seconds. I ...
- django的admin或者应用中使用KindEditor富文本编辑器
由于django后台管理没有富文本编辑器,看着好丑,展示出来的页面不美观,无法做到所见即所得的编辑方式,所以我们需要引入第三方富文本编辑器. 之前找了好多文档已经博客才把这个功能做出来,有些博客虽然写 ...
- 使用STS时遇到的小“麻烦”
背景 今天尝试着用STS(Spring Tool Suite)建立了一个Maven webapp来做一个SpringMVC的小demo,在使用的过程中就遇到了一些小麻烦!!记录在此的目的,其一是为了自 ...
- HTML5可预览多图片ajax上传(使用formData传递数据)
HTML5可预览多图片ajax上传(使用formData传递数据) 在介绍上传图片之前,我们简单的来了解下FormData的基本使用:介绍完成后这些基本知识后,我们会在文章最后提供一个demo,就是a ...
- 记录maven 整合SSM框架
一.新建maven项目 建好的项目结构如下图: 还需要做以下配置: 勾选上这两项后,就会自动生成 "src/main/java" 和 "src/main/resour ...
- 代码与编程(java基础)
代码与编程(面试与笔试java) 1.写一个Singleton出来 Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在. 一般Singleton模式通常有几种种 ...
- 移植u-boot-2012.04.01到JZ2440
开发环境:Ubuntu 12.04 开发板:JZ2440 256M NandFlash 64M SDRAM 交叉编译器:arm-linux-gcc-4.3.2 u-boot:u-boot-2012 ...
- 【JAVA零基础入门系列】Day3 Java基本数据类型
前两篇已经将开发环境搭建完成,如果你已经按之前的教程按部就班的完成了部署,那么世界上最优秀的编程语言之一和世界上最优秀的IDE之一已经出现在你的电脑上(此处应有掌声),如果你还没入门,或者正在台阶上踱 ...
- linux视频之media媒体框架
linux视频媒体(kernel层分析)主要包括三个文件: (/drivers/media/media-device.c , /drivers/media/media-devnode.c , /dr ...
- STM8学习
今天正式学习STM8,用的是风驰STM8S208R开发板. 在编译例程遇到了如下这样的问题. " #error clnk debug\stm8s_demo.lkf:47 can't open ...