这一节肯定能完!
经过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 官网介绍
随机推荐
-
如何在.NET上处理二维码
在移动设备,网站以及应用程序间传送数据,而使用二维码真是一种较快捷的方法,也避免了蓝牙配对的混乱状况.ZXing.NET是一个开源,多格式1D/2D条码图像处理库的C#实现,ZXing.NET是个相当 ...
-
ExtJS4插件EditArea
EditArea是一个支持语法高亮的文本编辑器,同类软件还有Ace, CodeMirror等.具体功能方面的差异,请访问http://en.wikipedia.org/wiki/Comparison_ ...
-
[苏飞开发助手V1.0测试版]官方教程与升级报告
[苏飞开发助手V1.0测试版]官方教程与升级报告导读部分----------------------------------------------------------------- ...
-
CI框架学习笔记
打印SQL语句$this->dbRead->last_query(); 重映射方法正如上文所说,URI 的第二段通常决定控制器的哪个方法被调用.CodeIgniter 允许你使用 _rem ...
-
【百度地图开发之二】基于Fragment的地图框架的使用
写在前面的话: [百度地图开发之二]基于Fragment的地图框架的使用(博客地址:http://blog.csdn.net/developer_jiangqq),转载请注明. Author:hmji ...
-
Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode, toggle the option in Preferences ->; SQL Queries and reconn
使用MySQL执行update的时候报错: MySQL 在使用mysql执行update的时候,如果不是用主键当where语句,会报如下错误,使用主键用于where语句中正常. 异常内容: ...
-
eclipse简介及下载
一.Eclipse 是非常着名的跨平台的*集成开发环境(IDE).最初主要用来Java语言开发,但是目前亦有人通过插件使其作为其他计算机语言比如C++和Python的开发工具. 二.Eclipse的 ...
-
LeetCode258 各位相加
题目链接:https://leetcode-cn.com/problems/add-digits/ 给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数. 示例: 输入: 38 输出: ...
-
SQL1:基础
1.SQL命令类型: 1)DDL:CREATE TABLE/INDEX/VIEW ; ALTER TABLE/INDEX/VIEW ; DROP TABLE/INDEX 2)DML:INSERT,UP ...
-
java线程总结(1/5)
前言 闲来无事正值面试,看面试中有线程之问题,特此总结一番. 正文 一.线程和进程的区别:1.每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销.2.线程可以看成时轻量级的进程 ...