vue.js_vue.jscsdn-程序员宅基地

技术标签: 前端  vue.js  

一:vue.js 是什么?
Vuejs,通常简称为Vue,是一 款友好的、多用途且高性能、渐进式的JavaScript 框架,能够帮助我们创建可维护性和可测试性更强的代码。它是目前所有主流框架中学习曲线最平缓的框架,非常容易上手,其官方文档也写得非常清晰、易懂。

二:什么是渐进式框架?
所谓渐进式框架,就是把框架分层。最核心的部分是视图层渲染,然后往外是组件机制,在这个基础上再加上路由机制,再加入状态管理,最外层是构建工具。
在这里插入图片描述
所谓分层,就是既可以只用最核心的视图层渲染功能来快速开发一些需求,也可以使用一整套全家桶来开发大型应用。vue.js有足够的灵活性来适应不同的需求,所以可以根自己的需求选择不同的层级。

javascript的流行库和框架带有元编程的特征。所谓元编程,简单来说,是指框架的作者使用一种编程语言固有的语言特性,创造出相对新的语言特性,使得最终使用者能够以新的语法和语义来构建他们的应用程序,从而在某些领域开发中获得更好的开发体验。
尽管vue.js框架赋予开发者众多特性和能力,但他仍然是使用原生javascript实现的应用框架。JavaSript自身提供了许多元编程特性,比如从ES5就开始支持的属性访问器( property acessor),ES6支持的代理( proxy) .还有标准提案已经处于Stage 3阶段的装饰器( decorator)。基于这些语言特性,我们能够比较方便地扩展新的语言特性,将这些特性融人应用框架,从而使得应用开发者能够更加得心应手地使用框架开发出优雅、简洁的应用程序模块。
>如何设计API和如何使用元编程思想将新特性融入到框架中,是现代JavaScript框架设计的两个核心,Vue.js 更侧重于后者。理解元编程思想有助于深刻理解Vue,js的本质。而理解元编程思想本身最好的方法又是通过深人研究Vuc,jis的源码,因为元编程思想一旦涉及具体实现,不仅仅是使用JavaScirpt提供的特性来扩展能力那么简单,这其中有许多细节需要考虑,比如要做到向下兼容,那么就要对一些特性的实现方式做出取舍,一些语言能力可以通过书写向下兼容代码
来弥补,而另一些则需要通过编译机制来做到,还有一些则必须舍弃;同样,基于性能考虑,一些特性也可能需要做出一定的修改或妥协。 这些问题不仅在框架设计和实现的过程中会遇到,而且在具体实现应用程序的过程中也会遇到。因此,通过学习Vuejs,我们不仅能够掌握设计应用程序框架的一般性技巧,还可以在实现应用程序时运用其中的具体设计思想和方法论。

三:vue解决了jQuery的什么问题?
用jQuery命令式操作DOM写需求,如果程序复杂之后,代码很多,难以维护,所以vue.js提供了声明操作DOM的能力。通过描述状态和DOM之间的映射关系,就可以将状态渲染成DOM呈现在用户界面中,也就是渲染到网页上。

四:vue.js1.0和vue.js2.0的区别
俩者间的内部变化非常大,整个渲染层都重写了,但API层面的变化却很小。
vue2引入了非常多的特性
①引入了虚拟DOM树,其渲染过程变得更快了。准确的说是80%的场景下变得更快了,而剩下的20%反而变慢了。
②支持JSX
③支持TypeScript
④支持流式服务端渲染
⑤提供了跨平台的能力

五:什么是变化侦测?
Vue.js最独特的特性之一是看起来并不显眼的响应系统。变化侦测的作用是侦测数据的变化。当数据发生变化时,会通知视图进行相应的更新。如何确定状态中发生了什么变化?变化侦测就是解决这个问题的,他分为俩种类型:一种是“推”,另一种是“拉”。
①Angular(脏检查)和React(虚拟DOM)中的变化侦测都属于“”,就是说当状态发生变化时,它不知道是哪个状态变了,只知道状态有可能变了,然后回发送一个信号告诉框架,框架内部接受到信号后,会进行暴力对比找出哪些节点可能需要重新渲染。
②Vue.js的变化侦测属于”“。当状态发生变化时,vue.js立刻就知道了,而且在一定程度上知道了哪些状态变了,因此它知道的信息更多,也就可以进行更细粒度的更新。
所谓更细粒度的更新,就是说假如有一个状态绑定着好多个依赖,每个依赖表示一个具体的DOM节点,那么当这个状态发生变化时,向这个状态的所有依赖发送通知,让它们进行DOM更新操作。相比较而言,“拉”的粒度是最粗的。
但是它也有一定的代价, 因为粒度越细,每个状态所绑定的依赖就越多,依赖追踪在内存上的开销就会越大。因此,从Vue,js 2.0开始,它引入了虚拟DOM,将粒度调整为中等粒度,即一个状态所绑定的依赖不再是具体的DOM节点,而是一个组件。这样状态变化后,会通知
到组件,组件内部再使用虚拟DOM进行比对。这可以大大降低依赖数量,从而降低依赖追踪所消耗的内存。
vue.js之所以能随意调整粒度,本质上还要归功于变化侦测。因为”推“类型的变化侦测可以随意调整粒度。

六:Object的变化侦测
1.如何追踪变化?
在JS中,侦测变化的方式有俩种:虽然方式不一样,但是原理都是一样的
①使用Object.defineProperty(√)
②ES6的Proxy(× 考虑到浏览器支持并不理想)
在这里插入图片描述
2.如何收集依赖?(重要)
要观察数据的目的就是当数据的属性发生变化时,可以通知那些曾经使用了该数据的地方。
所以步骤应当是:先收集依赖,即把用到该数据的地方收集起来,然后等属性发生变化时,把之前收集好的依赖循环触发一遍即可。
总结起来:在getter中收集依赖,在setter中触发依赖。
3.依赖收集在哪里?
首先想到的是每个key都有一个数组(dep),用来存储当前key的依赖。
方式一:新增一个数组dep,用来存储被收集的依赖,然后在set被触发时,循环 dep以触发收集到的依赖。但是这样写有点耦合,不便于管理依赖。在这里插入图片描述
方式二:把依赖收集的代码封装成一个Dep类,专门帮助我们管理依赖,使用该类,可以收集依赖、删除依赖或者向依赖发送通知等。
在这里插入图片描述
之后再改造defineReactive
在这里插入图片描述
在这里插入图片描述
4.依赖是谁?
收集谁,依赖就是谁。就是当属性发生变化后,通知谁。在上面的代码中,我们收集的依赖是window.target
由于使用这个数据的地方很多,而且类型还不一样,即有可能是模板,也有可能是用户写的一个watch,所以此时需要抽象出一个能集中处理这些情况的类,在收集阶段只收集这个封装好的类的实例进来,通知也只通知它一个,接着它再负责通知其他地方。该类起名叫watcher。
5.什么是watcher?
Watcher是一个中介的角色,数据发生变化时通知它,然后他再通知其他地方。
关于Watcher,先看一个经典的使用方式:
当data.a.b.c属性发生变化时,触发第二个参数中的 函数:在这里插入图片描述
那么如何实现作为中介角色的功能呢?
好像只要把这个Watcher实例添加到data.a.b.c属性的Dep中即可,然后data.a.b.c的值发生变化时,通知watcher,接着Watcher再执行参数中的这个回调函数。
代码实现如下:这段代码可以自己主动将watcher添加到data.a.b.c的Dep中去。

在这里插入图片描述
因为再get方法中先把window.target设置成了this,也就是当前watcher实例,然后再读一下data.a.b.c的值,肯定会触发getter,而触发了getter,就会触发收集依赖的逻辑。而依赖逻辑是从window.target中读取一个依赖并主动添加到keypath的Dep中。
而依赖注入Dep中后,每当data.a.b.c的值发生变化时,就会让依赖列表中所有的依赖循环触发update方法(watcher的update方法)
,而update方法会执行参数中的回调函数,将value和oldValue传入到参数中。
6.递归侦测所有的key
前面介绍的已经可以实现侦测数据中的某一个属性了,但是我们希望把数据中的所以属性(包括子属性)都能侦测到,所以封装一个Observer类,这个类的作用是将一个数据内的所有属性(包括子属性)都转换成getter/setter的形式,然后去追踪它们的变化。
在这里插入图片描述
在这里插入图片描述
该observer类用来将正常的object转换成被侦测的object,然后判断数据的类型,只有object类型才会调用walk将每一个属性转换成getter/setter的形式来侦测变化。最后,在deineReactive中新增new Observer(val)来递归子属性,这样就把data中所有属性(包括子属性)都转换成了getter/setter的形式来侦测变化。
也就是说,只要我们将一个object传到observer中,那么这个object就会变成相应式的object.
7.关于object侦测存在的问题
前面介绍的object类型数据的变化侦测原理,了解了数据的变化是通过getter/setter来追踪的,也正是因为这种追踪方式,导致有些语法中即使数据发生了变化,vue.js也追踪不到,比如向object添加删除属性,虽然Obj新增了属性,但是vue.js无法侦测到这个变化,所以不会向依赖发送通知。
增加一个属性:
在这里插入图片描述
再比如删除一个属性:vue.js也无法侦测到这个变化,所以不会向依赖发送通知
在这里插入图片描述
vue.js通过Object.defineProperty来将对象的key转换成getter/setter的形式来追踪变化,但是getter/setter只能追踪一个数据是否被修改,无法追踪新增属性和删除属性,所以才会导致上面的问题。
但这也是没办法的事,因为再ES6之前,js没有提供元编程的能力,无法监测一个新属性被添加/删除到对象。为了解决这个问题,vue.js提供了俩个API----vm.$set与vm. $delete,下面第四章会介绍到。
8.总结:
①所谓依赖,其实就是watcher,只有watcher触发getter才会收集依赖,哪个watcher触发了getter,就把哪个watcher收集到Dep中,当数据发生变化时,会循环依赖列表,把所有的watcher都通知一遍。
②watcher的原理是先把自己设置到全局的唯一位置(例如:window.targte),然后读取数据,会触发这个数据的getter,接着,getter中就会从全局唯一的那个位置读取数据的watcher,就把这个watcher收集到Dep中去,通过这样的方式主动去订阅任意一个数据的变化。
③建立了Observer类,作用是把一个object中的所有数据(包括子数据)都转换成响应式的,会侦测object中的所有数据(包括子数据)的变化。
在这里插入图片描述
Data通过Observer转换成了getter/setter 的形式来追踪变化。当外界通过Watcher读取数据时,会触发getter 从而将Watcher添加到依赖中。
当数据发生了变化时,会触发setter,从而向Dep中的依赖( Watcher )发送通知。Watcher接收到通知后,会向外界发送通知,变化通知到外界后可能会触发视图更新,也有可能触发用户的某个回调函数等。

七:Array的变化侦测
Array的侦测方式和Object的侦测方式不同,eg: list.push(1),我们使用上面的代码改变了数组,但是使用push方法来改变数组,并不会触发getter/setter,正因为通过Array原型上的方法来改变数组的内容,所以Object那种通过getter/setter的实现方式就行不通了。
1.如何追踪变化?
object的变化是靠setter来追踪的,只要数据发生变化,就会触发setter。同理,前面例子中使用push来改变数组的内容,那么只要再使用push操作数组的时候通知,就能实现同样目的。但是再ES6之前。js没有提供元编程的能力,没有提供可以拦截原型方法的能力,但是我们可以用自定义的方法去覆盖原生的原型方法。
我们可以用一个拦截器覆盖Array.prototype,之后每次使用Array原型上的方法操作数组时,其实执行的都是拦截器中提供的方法,然后,拦截器中使用原生Array的原型方法去操作数组。这样通过拦截器,我们就可以追踪到Array的变化。
在这里插入图片描述
2.拦截器
拦截器其实就是一个和Array.prototype一样的object,里面包含的属性一模一样,只不过这个object中某些可以改变数组自身内容的方法是我们处理过的,经过发现原型上可以改变数组自身内容的方法有7个,分别为push、pop、shift、unshift、splice、sort和reverse.
在这里插入图片描述
在这里插入图片描述
在上面的代码中,创建了变量arrayMethos,他继承自Array.prototype,具备其所有功能,未来要使用arrayMethods去覆盖Array.prototype。接下来在arrayMethods上使用Object.defineProperty方法将那些可以改变数组自身内容的方法进行封装。所以说使用push方法的时候,其实是调用arrayMethods.push,实际上执行的是mutator函数。因此我们可以在mutator函数中做一些其他的事,比如发送变化通知。
3.使用拦截器覆盖Array原型
有拦截器之后如果想让它生效,就要使用它去覆盖Array.prototype,但是又不能直接覆盖,因为这样会污染全局的Array,所以我们只希望拦截操作只针对那些被侦测了变化的数据生效,也就是说希望拦截器只覆盖那些响应式数组的原型。而将一个数据转换成响应式的,需要通过observer,所以只需要在observer中使用拦截器覆盖掉那些即将被转换成响应式Array类型数据的原型就可以。
在这里插入图片描述
上面的作用式将拦截器赋值给value.__ proto _,通过 proto 可以很巧妙地实现覆盖value原型的功能。
在这里插入图片描述
__ proto 其实是ES6的Object.getPrototypeOf和Object.setPrototypeof的早期实现,所以可以用ES6的俩种方式代替,但是由于目前浏览器对ES6的支持并不理想。
4.将拦截器方法挂载到数组的属性上
虽然大多数属性都支持这种非标准的属性(在ES6之前并不是标准)来访问原型,但并不是所有浏览器都支持,所以我们要考虑不能使用
proto __的情况,如果不能使用,则直接将arrayMethods上的方法设置到被侦测的数组上。
①支持该属性,则直接用protoAugment函数覆盖原型。
②如果不支持,则调用copyAugment函数将拦截器中的方法挂载到value上。因为访问对象方法时,只有其自身不存在这个方法,才会去原型中找这个方法。
在这里插入图片描述
在这里插入图片描述
在上面的代码中,新增了hasProto来判断当前浏览器是否支持 __ proto __,还新增copyAugment函数,用来将已经加工了拦截操作的原型方法直接添加到value的属性。 因为当访问一个对象的方法时,只有其自身不存在这个方法,才会去他的原型上找这个方法。
在这里插入图片描述
5.如何收集依赖
创建拦截器,本质上是为了可以当数组内容变化时,可以得到让依赖通知。如果只有拦截器,那么什么事情都做不了,所以我们要收集到存储在Dep中的依赖,那么如何收集呢?回顾一些object的依赖时如何收集的,在defineReactive中的getter里使用Dep收集的,每个key都会有一个对应的Dep列表来存储依赖。简单说就是在getter中收集依赖,依赖被存储在Dep里。那么数组也是在getter中收集依赖的。
举个例子:
list:[1,2,3,4,5]
如果是上面这样的数据,要想得到list数组,肯定要访问list这个key,因此在读取list的时候,肯定会触发list这个属性的getter,所以Array的依赖也和Object的依赖一样,在defineReactive中收集。
在这里插入图片描述
在这里插入图片描述
所以Array在getter中收集依赖,在拦截器中去触发依赖。
6.依赖列表存在哪里?
Array的依赖存放在observer中,因为依赖要在getter中收集,拦截器中触发,所以依赖必须在getter和拦截器中都可以访问。
7.收集依赖
把Dep实例保存在observer的属性上之后,我们可以在getter中像下面这样访问并收集依赖
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
8.在拦截器中获取observer实例
因为array拦截器是对原型的一种封装,所以在拦截器中可以访问到this(当前被操作的数组),而dep报存在observer中,所以需要在this上读取到observer的实例。
在这里插入图片描述
在上面代码中,我们在obserber中新增了一段代码,他可以在value上新增一个不可枚举的属性__ob ,这个属性的值就是当前observer的实例。
在这里插入图片描述
在这里插入图片描述
在上面diamond中,在mutator函数里通过this.
ob__来获取observer实例。
9.向数组的依赖发送通知
当侦测到数组变化,会向依赖发送通知,首先要能访问到依赖,上面的操作即可以在拦截器中访问到observer实例,再在observer实例中拿到dep,然后发送通知即可。
在这里插入图片描述
在这里插入图片描述
10.侦测数组中元素的变化
前面所说的侦测数组变化,指的是数组自身的变化,比如是否新增一个元素,是否删除一个元素等。
其实数组中保存了一些元素它们的变化也是需要侦测的,比如其中一个值发生了变化,需要发送通知。
此外,如果用户使用了push往数组新增元素,这个新增元素的变化也需要侦测。
也就是说,所有响应式数据的子数据集都要侦测,不论是object中的数据还是array中的数据。
那么如何侦测所有数据子集的变化呢?
在这里插入图片描述
在这里插入图片描述
observer新增了对array类型数据的处理逻辑。
这里新增了observeArray方法,其作用是循环array的每一项执行observe函数来侦测变化。而observe函数是将数组的每个元素执行一遍new Observer,这是递归过程。现在只要把数据丢进去,observer就会把数据的所有子数据转换成响应式的。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_45847735/article/details/121947765

智能推荐

机器学习算法学习02:决策树的学习以及应用决策树解决Cora数据集论文分类问题_传统机器学习解决cora数据集论文分类问题-程序员宅基地

文章浏览阅读1.1k次,点赞3次,收藏7次。机器学习03:决策树的学习以及应用决策树解决Cora数据集论文分类问题文章目录机器学习03:决策树的学习以及应用决策树解决Cora数据集论文分类问题1.前言2.算法分析2.1算法概述2.2 算法优化3.算法代码3.1 决策属性优先级选择3.1.1 信息熵3.2.2 信息增益率3.3.3 基尼系数3.2 数据集的预处理3.3 决策树的生成3.4 决策树的分类4.算法运行与评估4.1 使用信息增益来划分数据集4.2 使用信息增益率划分数据4.3 使用基尼指数划分数据5.结语1.前言决策树方法作为非常经典的_传统机器学习解决cora数据集论文分类问题

NVIDIA控制面板不见了解决方法-程序员宅基地

文章浏览阅读4.4k次,点赞2次,收藏2次。NVIDIA控制面板调不出来欢迎使用Markdown编辑器你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。新的改变我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:全新的界面设计 ,将会带来全新的写作体验;在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮

x4412开发板&ibox卡片电脑项目实战16-将hello x4412驱动编译成模块-程序员宅基地

文章浏览阅读1.3k次。在内核根目录执行make menuconfig,进入Device Drivers-> Character devices菜单界面,找到hello X4412 driver配置选项,按空格键将它配置成模块[M],保存退出。执行如下指令,保存配置好的内核配置文件:cp .config arch/arm/configs/x4412_android_defconfig 再在整个源码

新一代大数据引擎操作系统:DataWorks V2.0重磅来袭-程序员宅基地

文章浏览阅读723次。摘要: 众所周知,MaxComput与Blink分别是阿里巴巴自主研发的离线计算、实时计算大数据计算引擎,不仅拥有多项国家专利技术,而且多项关键指标已远超业内开源引擎平均能力,名副其实地成为了阿里巴巴大数据之路上的领航者。认识DataWorks:新一代大数据引擎操作系统众所周知,MaxComput与Blink分别是阿里巴巴自主研发的离线计算、实时计算大数据计算引擎,不仅拥有多项国家专利技术...

不好好作图的NCS系列(五):从这篇Cell学习GSEA的R语言分析及作图-程序员宅基地

文章浏览阅读3.6k次,点赞10次,收藏30次。之前我们在讲转录组系列的时候,说过差异基因的功能富集,用的是GO和KEGG分析。但是这远远不够,很多研究者更喜欢使用GSEA,全名是Gene Set Enrichment Analysis (基因集富集分析)。GSEA在一定程度上与GO一样,但是两者具有巨大的差别。GO使用的是差异基因,因为阈值的设定是人为的,所以很有可能遗漏一些重要基因,仅仅是因为这些基因的变化较小。而GSEA则不同,它需要的是对所有的基因进行分析,因此能够保留更多的信息。通俗的说,GSEA的适用场景是:在两种不同的生物学状态下,

Odoo2021最新实用教程之——Odoo Studio 在线开发工具实战入门指导-程序员宅基地

文章浏览阅读4.7k次。Odoo Studio 作为Odoo企业版中的核心模块,能让odoo使用者通过此设计器快速、高效地构建新模块以及方便地进行已有功能地调整。但目前缺乏与Odoo Studio有关的中文指导资料,本文通过文字与视频结合的方式讲解Odoo Studio的实战操作,希望帮助有需要的朋友快速掌握这个工具。即使你最终可能不用企业版,但通过odoo企业版在线试用提供的这个在线开发工具也能帮助你对odoo的原理更快的了解。 Odoo的在线开发工具是Odoo企业版提供的强力设计工具,本实战..._odoo studio

随便推点

【问题】解决docker 容器中文乱码_主机内的vi支持中文,但是docker内vi不支持中文-程序员宅基地

文章浏览阅读3.5k次。进入容器 查看字符集# docker exec -it <container_id> /bin/bash# locale 查看当前容器字符集# locale -a 查看容器支持的字符集从输出可以看到,系统使用的是POSIX字符集,POSIX字符集是不支持中文的,而UTF-8是支持中文的 只要把系统中的环境 LANG 改为”UTF-8”格式即可解决问题。临时设置#vi /etc/profile 进入文件加入变量# export LANG="en_US..._主机内的vi支持中文,但是docker内vi不支持中文

已知数据信息为 16位,最少应附加( )位校验位,以实现海明码纠错。_已知数据信息为16位,最少应附加-程序员宅基地

文章浏览阅读582次。已知数据信息为 16位,最少应附加( )位校验位,以实现海明码纠错。 A、3B、4C、5D、6答案:C答案解析:根据公式 2的k次方 ≥ n+k+1 , n=16 则 K=5_已知数据信息为16位,最少应附加

VUE项目报错webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --host 192.168.1.10-程序员宅基地

文章浏览阅读1.1k次。首先粘上logF:\BackStage>npm run dev> [email protected] dev F:\BackStage> webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --host 192.168.1.105报这个错我也是很无奈,正常情况下VU...

【ElasticSearch】RestClient和ElasticsearchTemplate实现高亮查询-程序员宅基地

文章浏览阅读1.9k次。在查询的时候希望,查询结果中的包含查询关键字高亮。(Es版本,6.5.4)前提准备,首先建立mappingPOST http://47.101.167.46:9200/hello_es/doc/_mapping{ "properties": { "name": { "type": "text", "analyzer":"ik_max_word", ...

PDF转word_pdf转word的方式csdn-程序员宅基地

文章浏览阅读2.4k次,点赞3次,收藏3次。https://www.addpdf.cn/pdf-to-word_pdf转word的方式csdn

背包问题 ——第K优解 或 次优解_次优解符号-程序员宅基地

文章浏览阅读1.9k次。附上水题一枚:http://acm.hdu.edu.cn/showproblem.php?pid=2639_次优解符号

推荐文章

热门文章

相关标签