一、为什么组件中data是函数返回对象?
1、组件中的data是函数的设计是因为组件被复用时,data数据源才不会共用,每次复用该组件生成的data数据源都是相互独立的,不会受到相互之间的影响;
2.函数的设计就像懒加载一样。当使用组件时数据源的对象才会创建,这样设计性能更好,不会消耗内存空间。
那为什么new Vue()中的data直接采用对象赋值?
因为new Vue()创建的vm对象是根组件,不需要被复用。
二、 数据劫持的顺序
在组件创建过程中,会经过生命周期函数。在beforecreate和created阶段会去劫持传入对象的各项数据和方法给该组件对象。那么劫持的顺序是什么呢?
在网上的资料中初始化顺序computed,methods,data,props(实际并非如此 猜测是脚手架的导致的打包顺序还有vue的版本导致的劫持顺序不一样) ,我们简记为: CMDP
vue底层源码分析的初始化顺序结果:属性props<方法methods<数据源data<计算属性computed<对属性监听watch
三、单向数据流
Vue框架的特点:数据自向上,由底层流向顶层,但是不能反向。
拿属性传值为例,父组件能够向子组件传值,父组件传的值改变子组件接收的值对应改变,但是子组件中修改传来的这个值,并不能够修改父组件的这个值。
四、在组件中如何css预处理技术
1、在项目直接创建scss文件或者less文件,运行后编辑器会帮我们生成对应的css文件,将这个css文件在组件引入即可使用。
2、直接在.vue文件的style标签中使用scss,前提是在vue create init创建项目时,选择配置scss的加载器,在style标签的行内添加lang="scss",webpack帮我们打包这个文件时会它转换为浏览器能够认识的css。
五、vue加载流程
1.每一个组件在加载时都会调用vue内部的render函数来把这个组件的tamplate选项的模板解析为一个JS对象;这个对象跟DOM节点对象"长得一模一样",就是为了后来的渲染。我们将其称为VNode,虚拟节点。
2.然后是数据劫持代理监听等等 底层有一种设计: 发布/订阅设计 其实就是写了一个watcher函数去订阅(监听) 数据的改变(底层js语法就是defInedproty,v3是proxy)
当数据发生变化以后: 当状态(数据)变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较(diff),记录两棵树差异 把第二棵树所记录的差异应用到第一棵树所构建的真正的DOM树上(patch),视图就更新了
旧VNode树=>新VNode树=>刷新页面 这个想法是不对的 旧VNode树 和 生成的新VNode树 比较差异然后更新DOM(刷新页面) 这个就是对的 实现这个过程的代码就是DIFF算法
六、DIFF算法
用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中;
当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较(diff),记录两棵树差异,把第二棵树所记录的差异应用到第一棵树所构建的真正的DOM树上(patch),视图就更了。
DIFF算法的过程
当数据发生改变时,订阅者watcher就会调用patch给真实的DOM打补丁
通过sameVnode进行判断,相同则调用patchVnode方法
patchVnode做了以下操作:
找到对应的真实dom,称为el
如果都有文本节点且不相等,将el文本节点设置为Vnode的文本节点
如果oldVnode有子节点而VNode没有,则删除el子节点
如果oldVnode没有子节点而VNode有,则将VNode的子节点真实化后添加到el
如果两者都有子节点,则执行updateChildren函数比较子节点
updateChildren主要做了以下操作:
设置新旧VNode的头尾指针
新旧头尾指针进行比较,循环向中间靠拢,根据情况调用patchVnode进行patch重复流程、调用createElem创建一个新节点,从哈希表寻找 key一致的VNode 节点再分情况操作