共计 9111 个字符,预计需要花费 23 分钟才能阅读完成。
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 的作用
次要作用:
- key 的次要作用就是用来进步渲染性能的!
key 属性能够防止数据凌乱的状况呈现(如果元素中蕴含了有长期数据的元素,如果不必 key 就会产生数据凌乱)
- vue 很大的一个特点就是双向数据绑定,数据一旦扭转,页面就渲染新的数据出现在页面。
- 而为了在削减数据时缩小渲染值,复用未扭转值,从而提高效率。
- v-for 默认应用复用策略,列表数据批改的时候,他会依据 key 值去判断某个值是否批改,如果批改就重现渲染这一项,否则就复用。
- 最好是应用数值中不会变动的项作为 key,对应到我的项目中,即每条数据都有一个惟一的 id,来标识这条数据的唯一性。
Vue 双向绑定原理
MVVM
- M(MODEL,模型层),
- V(View,视图层)
- VM(ViewModel,V 与 M 连贯的桥梁,也能够看作为控制器)
- 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 区别
- 监听数据变动的实现原理不同
- Vue 通过 getter/setter 以及一些函数的劫持,能准确晓得数据变动
- React 默认是通过比拟援用的形式(diff)进行的,如果不优化可能导致大量不必要的 VDOM 的从新渲染。
为什么 React 不准确监听数据 变动?
- 因为 Vue 和 React 设计理念上的区别,Vue 应用的是可变数据,而 React 更强调数据的不可变,两者没有好坏之分,Vue 更加简略,React 构建大型利用的适宜更加好。
- 数据流的不同
- Vue1.0 中能够实现两种双向绑定:父子组件之间,props 能够双向绑定;组件与 DOM 之间能够通过 v -model 双向绑定。
- Vue2.x 中去掉了父子组件双向绑定(然而提供了一个语法糖主动帮你通过事件的形式批改),并且 Vue2.x 曾经不激励组件对本人的 props 进行任何批改了
- React 始终不反对双向绑定,提倡的是单向数据流,称之为 onChange/setState()模式。不过因为咱们个别都会用 Vuex 以及 Redux 等单向数据流的状态治理框架,因而很多时候咱们感触不到这一点区别
- HoC 和 mixin
- Vue 组合不同性能的形式是通过 mixin,Vue 中组件是一个被包装的函数,并不简略的就是咱们定义组件的时候传入的对象或者函数。比方咱们定义的模板怎么被编译的?比方申明的 props 怎么承受到的?这些都是 Vue 创立组件实例的时候隐式干的事。因为 Vue 默默帮咱们做了这么多事儿,所以咱们本人如果间接把组件的申明包装以下,返回一个 HoC, 那么这个被包装的组件就无奈失常工作了
- React 组合不同性能的形式是通过 HoC(高阶组件)。React 最早也是应用 mixins 的,不过起初他们感觉这种形式侵入太强会导致很多问题,就弃用了 mixinx 转而应用 HoC。高阶组件实质就是高阶函数,React 的组件是一个纯正的函数,所以高阶函数对 React 来说非常简单。
- 组件通信的区别
Vue 中有三种形式能够实现组件通信:
- 父组件通过 props 向子组件传递数据或者回调,尽管能够传递回调,但咱们个别只传数据
- 子组件通过事件向父组件发送音讯
- 通过 V2.2.0 中新增的 provide/inject 来实现父组件向子组件注入数据,能够逾越多个层级
React 中也有对应的三种形式:
- 父组件通过 props 能够向子组件传递数据或者回调
- 能够通过 context 进行跨层级的通信,这其实和 provide/inject 起到的作用差不多
- React 自身并不反对自定义事件,而 Vue 中子组件向父组件传递音讯有两种形式:事件和回调函数,但 Vue 更偏向于应用事件。
- 在 React 中咱们都是应用回调函数的,这可能是他们二者最大的区别
- 模板渲染形式的不同
- 在表层上,模板语法的不同,React 是通过 JSX 渲染模板。而 Vue 是通过一种拓展的 HTML 语法进行渲染,但其实这只是表面现象,比拟 React 并不必须依赖 JSX
在深层上,模板的原理不同。这才是本质区别:
- React 切实组件 JS 代码中,通过原生 JS 实现模板中的常见语法,比方插值,条件,循环等,都是通过 JS 语法实现的,更加纯正更加原生。
- 而 Vue 是在和组件 JS 代码拆散的独自的模板中,通过指令来实现的,比方条件语句就须要 V -IF 来实现。对于这一点,这样的作法显得有些独特,会把 HTML 弄得很乱
比方阐明 React 的益处:
- React 中 render 函数是反对闭包个性的,所以咱们 import 的组件在 render 中能够间接调用。
- 然而在 Vue 中,因为模板中应用的数据都必须挂载在 this 上进行一次中专,所以咱们 import 一个组件完了之后,还须要再 components 中再申明下,这样显得很奇怪但又不得不这样做
- 渲染过程不同
- Vue 能够更快的计算出 VDOM 的差别,这是因为它在渲染过程中,会跟踪每一个组件的依赖关系,不须要从新渲染整个组件库
- React 再利用的状态被扭转时,全副子组件都会从新渲染,通过 shouldComponentUpdate 这个生命周期办法能够进行管制,但 Vue 将此视为默认的优化
- 如果利用中交互简单,须要解决大量的 UI 变动,那么应用 VDOM 是一个好主见,如果更新元素不频繁,那么 VDOM 并不一定实用,性能很可能还不如间接操控 DOM
- 框架实质不同
Vue 实质时 MVVM 框架,由 MVC 倒退而来
React 是前端组件化框架,由后端组件化发展而来
- 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 和单纯的全局对象有以下两点不同:
- Vuex 的状态存储时响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应的失去高效更新
- 不能间接扭转 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 的操作}