Vue

Vue 虚构DOM

  • 文档对象模型或DOM定义了一个接口,该接口容许JacasCript拜访和操作HTML文档。元素由数中的节点示意,并且接口容许咱们操纵它们,然而大量十分频繁的DOM操作会使页面速度变慢
  • 每个元素都是一个节点,每段文字也是一个节点,一个节点就是页面的一部分,每个节点也有对应的子节点
  • 虚构DOM就是为了解决操作实在DOM带来的性能问题而呈现的
  • 虚构DOM就是用js对象模仿实在的DOM节点(虚构节点VNode),也就是将所有的更新DOM的操作先全副反馈在JS对象上
  • 操作内存中的js对象显然速度要快很多,等更新实现后,再将最终的JS对象映射到实在的DOM上,交由浏览器去绘制页面
  • 总结起来就是

    • 获取监听变动后生成的虚构节点数
    • 与上一次虚构DOM节点数进行比拟
    • 找到差别的局部,渲染到实在的DOM节点上
    • 更新

diff算法

因为在浏览器中操作DOM的代价是十分“低廉”的,所以才在Vue引入了Virtual DOM,Virtual DOM是对实在DOM的一种形象形容,不懂的敌人能够自行查阅相干材料。

即便应用了Virtual DOM来进行实在DOM的渲染,在页面更新的时候,也不能全量地将整颗Virtual DOM进行渲染,而是去渲染扭转的局部,这时候就须要一个计算Virtual DOM树扭转局部的算法了,这个算法就是Diff算法。

简略的说就是新旧虚构dom 的比拟,如果有差别就以新的为准,而后再插入的实在的dom中,从新渲染

  • 只会做同级比拟,不做跨级比拟.
  • 比拟后几种状况

    • if (oldVnode === vnode),他们的援用统一,能够认为没有变动
    • if(oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text),文本节点的比拟,须要批改,则会调用Node.textContent = vnode.text。
    • if( oldCh && ch && oldCh !== ch ), 两个节点都有子节点,而且它们不一样,这样咱们会调用updateChildren函数比拟子节点,这是diff的外围
    • else if (ch),只有新的节点有子节点,调用createEle(vnode),vnode.el曾经援用了老的dom节点,createEle函数会在老dom节点上增加子节点。
    • else if (oldCh),新节点没有子节点,老节点有子节点,间接删除老节点。

key的作用
不设key,newCh和oldCh只会进行头尾两端的互相比拟,设key后,除了头尾两端的比拟外,还会从用key生成的对象oldKeyToIdx中查找匹配的节点,所以为节点设置key能够更高效的利用dom
所以咱们须要应用key来给每个节点做一个惟一标识,Diff算法就能够正确的辨认此节点,找到正确的地位区插入新的节点。
key的作用次要是为了高效的更新虚构DOM。另外vue中在应用雷同标签名元素的过渡切换时,也会应用到key属性,其目标也是为了让vue能够辨别它们,否则vue只会替换其外部属性而不会触发过渡成果

v-for中key的作用

次要作用:

  1. key的次要作用就是用来进步渲染性能的!
  2. key属性能够防止数据凌乱的状况呈现 (如果元素中蕴含了有长期数据的元素,如果不必key就会产生数据凌乱)

    • vue很大的一个特点就是双向数据绑定,数据一旦扭转,页面就渲染新的数据出现在页面。
    • 而为了在削减数据时缩小渲染值,复用未扭转值,从而提高效率。
    • v-for默认应用复用策略,列表数据批改的时候,他会依据key值去判断某个值是否批改,如果批改就重现渲染这一项,否则就复用。
    • 最好是应用数值中不会变动的项作为key,对应到我的项目中,即每条数据都有一个惟一的 id ,来标识这条数据的唯一性。

    Vue双向绑定原理

    MVVM

  3. M(MODEL,模型层),
  4. V(View,视图层)
  5. VM(ViewModel,V与M连贯的桥梁,也能够看作为控制器)
  6. MVVM反对双向绑定,意思就是当M层数据进行批改时,VM层会监测到变动,并且告诉V层进行相应的批改,反之批改V层则会告诉M层数据进行批改,因而实现了视图与模型层的互相解耦

vue双向数据绑定是通过数据劫持联合公布订阅模式的形式来实现的,也就是说数据和视图同步,数据发生变化,视图跟着变动,视图变动,数据也随之产生扭转。
外围:对于Vue双向数据绑定,其外围是Object.defineProperty()办法
介绍一下Object.defineProperty()办法

  • Object.defineProperty(obj,prop,descriptor),这个语法内有三个参数,别离为obj(要定义其上属性的对象)prop(要定义或批改的属性)descriptor(具体的扭转办法)
  • 简略地说,就是用这个办法来定义一个值,当调用时咱们应用了它外面get办法,当咱们给这个属性赋值时,又用到了它外面的set办法

具体实例内容请参考:https://www.jianshu.com/p/e7e...

响应式原理

当把一个一般的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的属性,并应用 Object.defineProperty 把这些属性全副转为 getter/setter。Object.defineProperty 是 ES5 个性,这也就是 Vue 不反对 IE8 以及更低版本浏览器的起因。

  这些 getter/setter 对用户来说是不可见的,然而在外部它们让 Vue 可能追踪依赖,在属性被拜访和批改时告诉变更。

  每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据属性记录为依赖。之后当依赖项的 setter 触发时,会告诉 watcher,从而使它关联的组件从新渲染。
  
  简略了解是由数据劫持联合发布者-订阅者模式实现的。说白了就是通过Object.defineProperty()来劫持对象属性的setter和getter操作,在数据变动时通过发布者-订阅者模式来实现更新试图。

computed计算属性

计算属性是vue实例中的一个配置选项:computed
比方在data里写了三门课程的得分,咱们须要计算平均值。
咱们能够在methods里写函数来计算。
然而更好的解决方案是vue提供的computed属性
通常都是一个个计算相干的函数,函数外头能够去写大量的逻辑,最初返回计算出来的值
即咱们能够把计算的过程写到一个个计算属性中,让它动静的计算。

  • 计算属性个别就是用来通过其余的数据算出一个新数据,而且有个益处就是,它把新的数据缓存下来了,
  • 当其余的依赖数据没有产生扭转,它调用的是缓存的数据,这就极大进步了程序的性能
  • 而写在methods里,数据基本没有缓存的概念,所以每次都会从新机选,这也是为什么不必methods的起因

Vue生命周期

Vue实例有一个残缺的生命周期,也就是说从创立,初始化数据、编译模板、挂在DOM、渲染--更新--渲染、卸载等一系列过程,咱们称为Vue的生命周期,钩子就是在某个阶段给你一个做某些解决的机会

beforeCreate(创立前):

  • 在实例初始化之后,数据观测和事件配置之前被调用,此时组建的选项对象还未创立,el和data并未初始化,因而无法访问methods,data,computed等下面的办法和数据
    created(创立后):
  • 实例曾经创立实现之后被调用,
  • 在这一步,实例已实现以下配置:数据观测、属性和办法的运算、watch/event事件回调,实现了data数据的初始化,el没有。
  • 然而,挂载阶段还没有开始,$el属性目前不可见,这是一个,罕用的生命周期,因为你能够调用methods中的办法,扭转data中的数据,并且批改能够通过Vue的响应式绑定体现在页面上,获取computed中的计算属性等等,通常咱们能够在这里对实例进行预处理,
  • 也有一些喜爱在这里发ajax申请,值得注意的是,这个周期中是没有生命办法来对实例化的过程进行拦挡的,因而退出有某些数据必须获取才容许进入页面的话,并不适宜在这个办法发送申请,倡议在组件路由钩子beforeRouterEnter中实现

beforeMount:

  • 挂载开始之前被调用,相干的render函数首次被调用(虚构DOM),实例已实现以下的配置
  • 编译模板,把data外面的数据和模板生成html,实现了el和data初始化,留神此时还没有挂载html到页面上

mounted:

  • 挂载实现,也就是模板中的HTML渲染到HTML页面中,此时个别能够做一些ajax操作,mounted只会执行一次

beforeUpdata:

  • 在数据更新之前被调用,产生在虚构DOM从新渲染和打补丁之前,能够在该钩子中进一步地更改状态,不会触发附加地重渲染过程

updated(更新后):

  • 在因为数据更改导致地虚构DOM从新渲染和打补丁只会调用,
  • 调用时,组件DOM曾经更新,所以能够执行依赖于DOM的操作,而后在大多数状况下,应该防止在此期间更新状态
  • 因为这可能会导致更新有限循环,该钩子在服务器渲染期间不被调用

beforeDestory(销毁前):

  • 在实例销毁之前调用,实例依然齐全可用
  • 这一步还能够用this来获取实例
  • 个别在这一步做一些重置的操作,比方革除掉组件中的定时器和监听的dom事件

destroyed(销毁后):

  • 在实例销毁之后调用,调用后,所有的事件见同期会被移除,所有的子实例也会被销毁,该钩子在服务器端渲染期间不被调用

Vue和React区别

  1. 监听数据变动的实现原理不同
  • Vue通过getter/setter以及一些函数的劫持,能准确晓得数据变动
  • React默认是通过比拟援用的形式(diff)进行的,如果不优化可能导致大量不必要的VDOM的从新渲染。
  • 为什么React不准确监听数据 变动?

    • 因为Vue和React设计理念上的区别,Vue应用的是可变数据,而React更强调数据的不可变,两者没有好坏之分,Vue更加简略,React构建大型利用的适宜更加好。
  1. 数据流的不同
  • Vue1.0中能够实现两种双向绑定:父子组件之间,props能够双向绑定;组件与DOM之间能够通过v-model双向绑定。
  • Vue2.x中去掉了父子组件双向绑定(然而提供了一个语法糖主动帮你通过事件的形式批改),并且Vue2.x曾经不激励组件对本人的props进行任何批改了
  • React始终不反对双向绑定,提倡的是单向数据流,称之为onChange/setState()模式。不过因为咱们个别都会用Vuex以及Redux等单向数据流的状态治理框架,因而很多时候咱们感触不到这一点区别
  1. HoC和mixin
  • Vue组合不同性能的形式是通过mixin,Vue中组件是一个被包装的函数,并不简略的就是咱们定义组件的时候传入的对象或者函数。比方咱们定义的模板怎么被编译的?比方申明的props怎么承受到的?这些都是Vue创立组件实例的时候隐式干的事。因为Vue默默帮咱们做了这么多事儿,所以咱们本人如果间接把组件的申明包装以下,返回一个HoC,那么这个被包装的组件就无奈失常工作了
  • React组合不同性能的形式是通过HoC(高阶组件)。React最早也是应用mixins的,不过起初他们感觉这种形式侵入太强会导致很多问题,就弃用了mixinx转而应用HoC。高阶组件实质就是高阶函数,React的组件是一个纯正的函数,所以高阶函数对React来说非常简单。
  1. 组件通信的区别
  • Vue中有三种形式能够实现组件通信:

    • 父组件通过props向子组件传递数据或者回调,尽管能够传递回调,但咱们个别只传数据
    • 子组件通过事件向父组件发送音讯
    • 通过V2.2.0中新增的provide/inject来实现父组件向子组件注入数据,能够逾越多个层级
  • React中也有对应的三种形式:

    • 父组件通过props能够向子组件传递数据或者回调
    • 能够通过context进行跨层级的通信,这其实和provide/inject起到的作用差不多
    • React自身并不反对自定义事件,而Vue中子组件向父组件传递音讯有两种形式:事件和回调函数,但Vue更偏向于应用事件。
    • 在React中咱们都是应用回调函数的,这可能是他们二者最大的区别
  1. 模板渲染形式的不同
  • 在表层上,模板语法的不同,React是通过JSX渲染模板。而Vue是通过一种拓展的HTML语法进行渲染,但其实这只是表面现象,比拟React并不必须依赖JSX
  • 在深层上,模板的原理不同。这才是本质区别:

    • React切实组件JS代码中,通过原生JS实现模板中的常见语法, 比方插值,条件,循环等,都是通过JS语法实现的,更加纯正更加原生。
    • 而Vue是在和组件JS代码拆散的独自的模板中,通过指令来实现的,比方条件语句就须要V-IF来实现。对于这一点,这样的作法显得有些独特,会把HTML弄得很乱
  • 比方阐明React的益处:

    • React中render函数是反对闭包个性的,所以咱们import的组件在render中能够间接调用。
    • 然而在Vue中,因为模板中应用的数据都必须挂载在this上进行一次中专,所以咱们import一个组件完了之后,还须要再components中再申明下,这样显得很奇怪但又不得不这样做
  1. 渲染过程不同
  • Vue能够更快的计算出VDOM的差别,这是因为它在渲染过程中,会跟踪每一个组件的依赖关系,不须要从新渲染整个组件库
  • React再利用的状态被扭转时,全副子组件都会从新渲染,通过shouldComponentUpdate这个生命周期办法能够进行管制,但Vue将此视为默认的优化
  • 如果利用中交互简单,须要解决大量的UI变动,那么应用VDOM是一个好主见,如果更新元素不频繁,那么VDOM并不一定实用,性能很可能还不如间接操控DOM
  1. 框架实质不同

Vue实质时MVVM框架,由MVC倒退而来
React是前端组件化框架,由后端组件化发展而来

  1. Vuex和Redux的区别

从外表上来说,store注入和实用形式有一些区别。

  • 在Vue中,$store被间接注入到了组件实例中,因而能够比拟灵便的实用: 应用dispatch,commit提交更新,通过mapState或者间接通过,this.$store来读取数据。
  • 在Redux中,咱们每一个组件都须要事实的用connect把须要的props和dispatch连接起来。
  • 另外Vuex更加灵便一些,组件中即能够dispatch action,也能够commitupdates,
  • 而Redux中只能进行dispatch,不能间接调用reducer进行批改

从实现原理上来说,最大的区别是两点:

  • Redux应用的是不可变数据,
  • 而Vuex的数据是可变的,
  • 因而,Redux每次都是用新state替换旧state,而Vuex是间接批改
  • Redux在检测数据变动的时候,是通过diff的的形式比拟差别的,
  • 而Vuex和Vue的原理一样,是通过getter/setter来比拟的
  • 这两点的区别,也是因为React和Vue设计理念不同。
  • React更偏差于构建稳固大型的利用,十分的刻板化
  • Vue更偏差于简略迅速的解决问题,更灵便,不那么严格遵循条条框框,因而也会给人一种大我的项目用React,小我的项目Vue的感觉

vue-router中keep-alive的应用

背景:在应用基于Vue的单页面富利用的开发中,总会面向这样的产品需要,即从列表页跳转到详情页面,返回时须要保留列表页的状态
这种场景下,若是将数据写入到全局状态中,总会面临简单的页面路由判断来革除和存储页面状态
keep-alive简介
Vue在2.x版本中将keep-alive这已组建属性扩大成了内置的形象组件<keep-alive>,它本身不会渲染一个DOM元素,也不会呈现在父组件链中,当组件在<keep-alive>内被切换,它的activated和deactivated这两个生命周期钩子函数将会被对应执行。使得被keep-alive组件包裹的组件的状态得以保留也防止了该组件的反复渲染

computed里的get set

  • get是基于其余的数据来获取到computed里定义的那个数据
  • set是依据computed里定义的那个数据来扭转其余的数据

Vuex

Vuex是一个专为Vue.js利用程序开发的状态管理模式。它采纳集中式存储管理利用的所有组件的状态,并以相应的规定保障状态以一种可预测的形式发生变化
集体了解 Vuex就是治理组件之间通信的一个插件
Vuex和单纯的全局对象有以下两点不同:

  1. Vuex的状态存储时响应式的。当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应的失去高效更新
  2. 不能间接扭转store中的状态。扭转store中的状态的惟一路径就是显式的提交(commit)mutation。这样使得咱们能够不便地追踪每一个状态地变动,从而让咱们可能实现一些工具帮忙咱们更好地理解咱们的利用
  • Store

    • 每一个Vuex利用的外围就是store(仓库)。“store”基本上就是一个容器,它蕴含着你的利用中大部分的状态(state)
  • State

    • 驱动利用的数据源,用于保留所有组建的公共数据
  • Getter

    • 能够将getter了解为store的计算属性,getters的返回值会依据它的依赖被缓存起来,且只有当它的依赖值产生了扭转才会被从新计算
  • Mutation

    • mutations对象中保留着更改数据的回调函数,该函数名官网规定叫type,第一个参数式state,第二个参数payload,也就是自定义的参数。mutation必须是同步函数。mutation对象里的办法须要应用store.commiit调用
  • Action

    • Action提交的是mutation而不是间接变更状态。action能够蕴含任意异步操作。
    • action对象里的办法须要store.dispatch调用
    • Action函数承受一个与store实例具备雷同办法的属性的context对象,因而你能够调用context.commit提交一个mutation,或者通过context.state和context.getters来获取state和getters

hash和history了解

hash模式:
即地址栏 URL 中的 # 符号(此 hash 不是密码学里的散列运算)。比方这个 URL: http://www.abc.com/#/hello ,hash 的值为 #/hello。它的特点在于:hash 尽管呈现在 URL 中,但不会被包含在 HTTP 申请中,对后端齐全没有影响,因而扭转 hash 不会从新加载页面。
history模式:
利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 办法。(须要特定浏览器反对)这两个办法利用于浏览器的历史记录栈,在以后已有的 back、forward、go 的根底之上,它们提供了对历史记录进行批改的性能。只是当它们执行批改时,尽管扭转了以后的 URL,但浏览器不会立刻向后端发送申请。

vue3新个性

  • 2020.9.19,尤大正式公布了Vue3.0版本。代号One Piece
  • 此框架新的次要版本提供了更好的性能,更小的捆绑包体积,更好的TypeScript集成,用于解决大规模用例的新API,并为框架将来的长期迭代奠定了松软的根底
  • Vue3.0中引入了Proxy

    • Proxy是ES6中的新增个性,用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)
    • Proxy能够了解为,在指标对象志强假如一层拦挡。外界对该对象的拜访,都必须先通过这层拦挡,因而提供了一种机制,能够对外界的拜访进行过滤和改写,批改某些操作的默认行为,
    • 这样咱们能够不间接操作对象自身,而是通过操作对象的代理对象来间接操作对象
    • Proxy这个词的原意是代理,用在这里示意由它来代理某些操作,能够译为代理器
  • 组合API(Composition API)

    • 当组件变得越来越大时,逻辑关注点的列表也会增长。这可能会导致组件难以浏览和了解,且碎片化使得了解和保护简单组件变得艰难
    • 选项的拆散覆盖了潜在的逻辑问题。
    • 此外,在解决单个逻辑关注点时,咱们必须一直地“跳转”相干代码地选项块
    • 如果可能将同一个逻辑关注点相干的代码配置在一起会更好,于是组合API应运而生
    • 应用composition api 地地位被称为setup
  • 引入createAPP

从技术上讲,Vue2没有app的概念,咱们定义的应用程序只是通过new Vue()创立的根Vue实例。从同一个Vue构造函数创立的每个根实例共享雷同的全局配置,因而全局配置使得在测试期间很容易意外地净化其余测试用例。用户须要认真存储原始全局配置,并在每次测试后复原。有些api没有复原办法,这使得设计插件的测试特地辣手

  • 组件上v-model用法已更改

    • 自定义v-model时,prop和工夫默认名称已更改

      • prop: value -> modelValue
      • enent: input -> update: modelValue
    • .sync和组件的model选项已移除,可用v-model作为代替
    • 当初能够在同一个组件上应用多个v-model进行双向绑定
    • 当初能够定义v-model修饰符

      • 比方自定义v-model.capiyalize,绑定为字符串第一个字母的大写
  • <template v-for>和非 v-for节点上key用法已更改

    • Vue2.x倡议在v-if/v-else/v-else-if的分支中应用key,Vue3.x中依然能失常工作,但不再倡议,因而没有为条件分支提供key时,也会主动生成惟一的key
    • Vue2.x中<template>标签不能领有key,在Vue3.x中key则应该被设置在<template>标签上
  • 同一元素上应用的v-if和v-for优先级已更改

    • Vue3.x中v-if会领有比v-for更高的优先级

      • 因为语法上存在歧义,倡议防止在同一元素桑同时应用两者,比方利用计算属性筛选出列表
  • v-bind=“object” 当初排序敏感

    • Vue2.x如果一个元素同时定义了v-bind=“object”和一个雷同的独自的property,那么这个独自的property总是会笼罩object中的绑定
    • Vue3.x申明绑定的程序决定了它们如何合并
  • v-for中的ref不再注册ref数组

    • Vue2中,在v-for里应用ref属性时,从$refs中获取的响应属性会是一个ref数组
    • Vue3中则将ref绑定到一个更灵便的函数上(ele)=>{..//保留ele的操作}