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 官网介绍
随机推荐
- JavaScript中DOM
概念 什么是DOM 1. 什么是 DOM DOM 的全称是document object model 它的基本思想是将结构化文佳例如HTML xml解析成一系列的节点.就像一颗树一样. 所有的节点和最 ...
- JavaScript中的ASCII碼轉換成字符的兩種方法
方法一:轉義字符 \xxx:用十六進制的ASCII碼值轉換成字符. 方法二:String方法 String.fromCharCode(value): //用十進制的ASCII碼值轉換成字符. 舉例:結 ...
- Check for Palindromes-FCC
問題: 检查回文字符串 如果给定的字符串是回文,返回true,反之,返回false. 如果一个字符串忽略标点符号.大小写和空格,正着读和反着读一模一样,那么这个字符串就是palindrome(回文). ...
- nodejs中http-proxy使用小结
最近在写xmocker的工具,用于开发前期的mock数据,不可避免的用到了代理的中间件.当然,github上有关于http-proxy封装的中间件.毕竟是自己练手的项目,就自己写了个中间件,方便定制功 ...
- 深入浅出数据结构C语言版(22)——排序决策树与桶式排序
在(17)中我们对排序算法进行了简单的分析,并得出了两个结论: 1.只进行相邻元素交换的排序算法时间复杂度为O(N2) 2.要想时间复杂度低于O(N2),算法必须进行远距离的元素交换 而今天,我们将对 ...
- Dubbo服务集群、服务启动依赖检查
一.什么叫Dubbo服务集群 指把同一个服务部署到多台机器,然后通过Dubbo服务集群的容错配置实现一台机器的服务挂掉之后自动切换到另外的一台机器 二.Dubbo服务集群容错配置--集群容错模式 标签 ...
- 关于加载离线SHP文件、geodatabase文件所遇到的路径问题
正文开始之前还是先吐槽一下,一行代码DEBUG了一天不知道怎么改,终于误打误撞弄出来了(以下以shp文件为例) 对于虚拟机测试 public String getPath(){ File sdDir ...
- Python in/not in --- if not/if + for...[if]...构建List+ python的else子句
区分几个容易出错的地方: in 成员运算符 - 如果字符串中包含给定的字符返回 True >>>"H" in a True not in 成员运算符 - 如果字符 ...
- javascript数组的常用方法总结
http://jingyan.baidu.com/album/86fae346bce16d3c49121af9.html?picindex=1 1. concat()方法 数组和数组的 粘结: var ...
- 微信小程序城市定位(借助百度地图API判断城市)
概述 微信小程序提供一些API(地址)用于获取当前用户的地理位置等信息,但无论是wx.getLocation,还是wx.chooseLocation均没有单独的字段表示国家与城市信息,仅有经纬度信息. ...