这一节肯定能完!

  

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

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

  1. function mountComponent(vm, el, hydrating) {
  2. vm.$el = el;
  3. if (!vm.$options.render) {
  4. vm.$options.render = createEmptyVNode; {
  5. // warning
  6. }
  7. }
  8. // beforeMount
  9.  
  10. var updateComponent;
  11. /* istanbul ignore if */
  12. if ("development" !== 'production' && config.performance && mark) {
  13. updateComponent = function() {
  14. // dev render
  15. };
  16. } else {
  17. updateComponent = function() {
  18. vm._update(vm._render(), hydrating);
  19. };
  20. }
  21.  
  22. // code...
  23.  
  24. // mounted
  25. return vm
  26. }

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

  1. Vue.prototype._update = function(vnode, hydrating) {
  2. var vm = this;
  3. // beforeUpdate
  4.  
  5. // code...
  6.  
  7. if (!prevVnode) {
  8. // initial render
  9. vm.$el = vm.__patch__(
  10. vm.$el, vnode, hydrating, false /* removeOnly */ ,
  11. vm.$options._parentElm,
  12. vm.$options._refElm
  13. );
  14. } else {
  15. // updates
  16. vm.$el = vm.__patch__(prevVnode, vnode);
  17. }
  18.  
  19. // code...
  20. };
  21.  
  22. Vue$3.prototype.__patch__ = inBrowser ? patch : noop;
  23.  
  24. var patch = createPatchFunction({
  25. nodeOps: nodeOps,
  26. modules: modules
  27. });
  28.  
  29. function createPatchFunction(backend) {
  30. var i, j;
  31. var cbs = {};
  32.  
  33. var modules = backend.modules;
  34. var nodeOps = backend.nodeOps;
  35.  
  36. for (i = 0; i < hooks.length; ++i) {
  37. // hook...
  38. }
  39.  
  40. // fn...
  41.  
  42. return function patch(oldVnode, vnode, hydrating, removeOnly, parentElm, refElm) {
  43. // code...
  44.  
  45. if (isUndef(oldVnode)) {
  46. // component...
  47. } else {
  48. var isRealElement = isDef(oldVnode.nodeType);
  49. if (!isRealElement && sameVnode(oldVnode, vnode)) {
  50. // patch existing root node
  51. } else {
  52. // SSR or hydrating
  53.  
  54. var oldElm = oldVnode.elm;
  55. var parentElm$1 = nodeOps.parentNode(oldElm);
  56. createElm(
  57. vnode,
  58. insertedVnodeQueue,
  59. oldElm._leaveCb ? null : parentElm$1,
  60. nodeOps.nextSibling(oldElm)
  61. );
  62.  
  63. //code...
  64. }
  65. }
  66.  
  67. invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch);
  68. return vnode.elm
  69. }
  70. }

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

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

  1. // vnode => 生成的vnode
  2. // insertedVnodeQueue => []
  3. // parentElm => body
  4. // refElm => #text
  5. // nested => undefined
  6. function createElm(vnode, insertedVnodeQueue, parentElm, refElm, nested) {
  7. vnode.isRootInsert = !nested; // for transition enter check
  8. if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
  9. return
  10. }
  11.  
  12. var data = vnode.data;
  13. var children = vnode.children;
  14. var tag = vnode.tag;
  15. if (isDef(tag)) {
  16. // pre...
  17.  
  18. vnode.elm = vnode.ns ?
  19. nodeOps.createElementNS(vnode.ns, tag) :
  20. // 调用这个生成一个tag标签
  21. nodeOps.createElement(tag, vnode);
  22. setScope(vnode);
  23.  
  24. {
  25. // 处理子节点
  26. // 子节点是5个vnode组成的数据 因此会循环调用本函数
  27. createChildren(vnode, children, insertedVnodeQueue);
  28. if (isDef(data)) {
  29. // 生成DOM节点的属性
  30. invokeCreateHooks(vnode, insertedVnodeQueue);
  31. }
  32. // 将子节点插入到父节点中
  33. // 处理到最外层节点 页面会渲染
  34. insert(parentElm, vnode.elm, refElm);
  35. }
  36.  
  37. if ("development" !== 'production' && data && data.pre) {
  38. inPre--;
  39. }
  40. } else if (isTrue(vnode.isComment)) {
  41. vnode.elm = nodeOps.createComment(vnode.text);
  42. insert(parentElm, vnode.elm, refElm);
  43. } else {
  44. vnode.elm = nodeOps.createTextNode(vnode.text);
  45. insert(parentElm, vnode.elm, refElm);
  46. }
  47. }

  其实,这个普通的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. Java单链表实现

    /** * * 单链表基本操作 * * @author John * */ class LinkList { private Node first; private int pos = 0; publ ...

  2. springmvc03-异常处理-静态文件

    1,一个简单的登录 login.jsp页面 <%@ page language="java" contentType="text/html; charset=UTF ...

  3. 离线安装 Cloudera Manager 5 和 CDH5.10

    关于CDH和Cloudera Manager CDH (Cloudera's Distribution, including Apache Hadoop),是Hadoop众多分支中的一种,由Cloud ...

  4. css控制div强制换行

    div{white-space:nowrap;} 自动换行 div{ word-wrap: break-word; word-break: normal; } 强制英文单词断行 div{word-br ...

  5. H5上传图片并使用canvas制作海报

    马上就要"十一"国庆节了,又恰逢公司已经三周岁了,所以市场部和产品共同策划了一个"正青春,共成长"的主题代言活动,准备在国庆节以及中秋节期间让公司员工和用户为公 ...

  6. Codeforces 845 A. Chess Tourney 思路:简单逻辑题

    题目: 题意:输入一个整数n,接着输入2*n个数字,代表2*n个选手的实力.    实力值大的选手可以赢实力值小的选手,实力值相同则都有可能赢.    叫你把这2*n个选手分成2个有n个选手的队伍. ...

  7. java中集合的增删改操作及遍历总结

      集合的增删改操作及遍历总结

  8. 【JAVA零基础入门系列】Day4 变量与常量

    这一篇主要讲解Java中的变量,什么是变量,变量的作用以及如何声明,使用变量. 那么什么是变量?对于初学者而言,可以将变量理解为盒子,这些盒子可以用来存放数据,不同类型的数据需要放在对应类型的盒子里. ...

  9. UIAlertController基本使用与内存泄露分析!!!

    最近开发过程中,发现内存会无故增加,在做内存优化的过程中,无意间发现了内存泄露的情况,那就是从iOS8.0 苹果开始推荐我们使用的UIAlertController!!! 看到这你是不是会嘲笑我第一次 ...

  10. Jmeter脚本调试——关联(正则表达式)

    关联,在脚本中,是必应用到的一个设置方法,将脚本中,每次都会动态变化的特殊值进行关联.一个能正确执行的脚本,都需要进行关联(LR.jmeter). Jmeter关联: 在脚本回放过程中,客户端发出请求 ...