VUE部分

1.对vue设计原则的理解

  • 渐进式JavaScript框架:与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue也完全能够为复杂的单页应用提供驱动
  • 易用性:vue提供数据响应式、声明式模板语法和基于配置的组件系统等核心特性。这些使我们只需要关注应用的核心业务即可,只要会写js、html和css就能轻松编写vue应用
  • 灵活性:渐进式框架的最大优点就是灵活性,如果应用足够小,我们可能仅需要vue核心特性即可完成功能;随着应用规模不断扩大,我们才可能逐渐引入路由、状态管理、vue-cli等库和工具,不管是应用体积还是学习难度都是一个逐渐增加的平和曲线
  • 高效性:超快的虚拟DOM和diff算法使我们的应用拥有最佳的性能表现。追求高效的过程还在继续,vue3中引入Proxy对数据响应式改进以及编译器中对于静态内容编译的改进都会让vue更加高效

2.Vue的基本原理

当一个Vue实例创建时,Vue会遍历data中的属性,用 Object.defineProperty(vue3.0使用proxy)将它们转为getter/setter,并且在内部追踪相关依赖,在属性被访问和修改时通知变化。每个组件实例都有相应的watcher程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新。

3.双向数据绑定的原理

Vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变

简单介绍一下Object.defineProperty()方法:

1、Object.defineProperty(obj, prop, descriptor) ,这个语法内有三个参数,分别为 obj (要定义其上属性的对象); prop (要定义或修改的属性); descriptor (具体的改变方法)

2、简单地说,就是用这个方法来定义一个值。当调用时我们使用了它里面的get方法。当给这个属性赋值时,就调用了它里面的set方法;

首先在vue初始化的时候,就对data数据进行了劫持监听,其中就是监听器Observe,用来监听所有属性的setter,getter。

若有属性发生变化就需要告诉订阅者Watcher看是否需要更新。

因为订阅者Watcher有多个,所以需要一个消息订阅器Dep来专门收集这些订阅者,在监听器Observe和订阅者Watcher之间进行统一管理。

还需要有一个指令解析器Compile,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令(如 v-model,v-on ...)对应的节点绑定更新函数,添加监听数据的订阅者Watcher,一旦数据有变动,收到通知,更新视图

当订阅者Watcher接收到相应属性的变化通知,就会执行对应的更新函数,从而去更新视图

主要分为以下几个步骤:

  • 实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者
  • 实现一个订阅者Watcher,每个Watcher都绑定一个更新函数,Watcher可以收到属性的变化通知并执行相应的函数,从而更新视图
  • 实现一个消息订阅器Dep,主要收集订阅者,当Observe监听到发生变化,就通知Dep,再去通知Watcher去触发更新
  • 实现一个解析器Compile,可以扫描和解析每个节点的相关指令,若节点存在指令,则Compile初始化这类节点的模板数据(使其显示在视图上),以及初始化相应的订阅者
  • MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化->视图更新;视图交互变化(input)->数据model变更的双向绑定效果。

4.MVVM、MVC、MVP的区别

MVC、MVP和MVVM是三种常见的软件架构设计模式,主要通过分离 关注点的方式来组织代码结构,优化开发效率。

(1)MVC

MVC通过分离Model、View和Controller的方式来组织代码结构。其中View负责页面的显示逻辑,Model负责存储页面的业务数据,以及对相应数据的操作。并且View和Model应用了观察者模式,当Model层发生改变的时候它会通知有关View层更新页面。

Controller层是View层和Model层的纽带,它主要负责用户与应用的响应操作,当用户与页面产生交互的时候,Controller中的事件触发器就开始工作了,通过调用Model层,来完成对Model的修改,然后Model层再去通知View层更新。

(2)MVVM

MVVM分为Model、View、ViewModel:

Model代表数据模型,数据和业务逻辑都在Model层中定义;

View代表UI视图,负责数据的展示;

ViewModel负责监听Model中数据的改变并且控制视图的更新,处理用户交互操作;

Model和View并无直接关联,而是通过ViewModel来进行联系的,Model和ViewModel之间有着双向数据绑定的联系。因此当Model中的数据改变时会触发View层的刷新,View中由于用户交互操作而改变的数据也会在Model中同步。

这种模式实现了Model和View的数据自动同步,因此开发者只需要专注于数据的维护操作即可,而不需要自己操作DOM。

(3)MVP

MVP模式与MVC唯一不同的在于Presenter和Controller。在MVC模式中使用观察者模式,来实现当Model层数据发生变化的时候,通知View层的更新。这样View层和Model层耦合在一起, 当项目逻辑变得复杂的时候,可能会造成代码的混乱,并且可能会对代码的复用性造成一些问题。MVP的模式通过使用Presenter来实现对View层和Model层的解耦。MVC中的Controller只知道Model的接口,因此它没有办法控制View层的更新,MVP模式中,View层的接口暴露给了Presenter因此可以在Presenter中将Model的变化和View的变化绑定在一起,以此来实现View和Model的同步更新。这样就实现了对View和Model的解耦,Presenter还包含了其他的响应逻辑。

5.slot是什么?有什么作用?原理是什么?

slot又名插槽,是Vue的内容分发机制,组件内部的模板引擎使用slot元素作为承载分发内容的出口。插槽slot是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。slot又分三类:

  • 默认插槽:又名匿名插槽,当slot没有指定name属性值的时候一个默认显示插槽,一个组件内只有有一个匿名插槽
  • 具名插槽:带有具体名字的插槽,也就是带有name属性的slot,一个组件可以出现多个具名插槽
  • 作用域插槽:默认插槽、具名插槽的一个变体,可以是匿名插槽,也可以是具名插槽,该插槽的不同点是在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽

实现原理:当子组件vm实例化时,获取到父组件传入的slot标签的内容,存放在vm.slot中,默认插槽为vm.slot.default,具名插 槽为vm.slot.xxx,xxx为插槽名,当组件执行渲染函数时候,遇到slot标签,使用slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。

6.$nextTick原理及作用

nextTick的核心是利用了如Promise、MutationObserver、setImmediate、setTimeout的原生JavaScript方法来模拟对应的微/宏任务的实现,本质是为了利用JavaScript的这些异步回调任务队列来实现Vue框架中自己的异步回调队列

nextTick不仅是Vue内部的异步队列的调用方法,同时也允许开发者在实际项目中使用这个方法来满足实际应用中对DOM更新数据时机的后续逻辑处理

Vue采用了数据驱动视图的思想,但是在一些情况下,仍然需要操作DOM。有时候,可能遇到这样的情况,DOM1的数据发生了变化,而DOM2需要从DOM1中获取数据,那这时就会发现DOM2的视图并没有更新,这时就需要用到了nextTick了

由于Vue的DOM操作是异步的,所以,在上面的情况中,就要将DOM2获取数据的操作写在$nextTick

所以,在以下情况下,会用到nextTick:

  • 在数据变化后执行的某个操作,而这个操作需要使用随数据变化而变化的DOM结构的时候,这个操作就需要在nextTick()的回调函数中
  • 在vue生命周期中,如果在created()钩子进行DOM操作,也一定要放在nextTick()的回调函数中(因为在created()钩子函数中,页面的DOM还未渲染)

7.Vue单页应用与多页应用的区别

SPA单页面应用(SinglePageWebApplication),指只有一个主页面的应用,一开始只需要加载一次js、css等相关资源。所有内容都包含在主页面,对每一个功能模块组件化。单页应用跳转,就是切换相关组件,仅仅刷新局部资源

MPA多页面应用(MultiPageApplication),指有多个独立页面的应用,每个页面必须重复加载js、css等相关资源。多页应用跳转,需要整页资源刷新

8.Vue中封装的数组方法有哪些,其如何实现页面更新

在Vue中,对响应式处理利用的是Object.defineProperty对数据进行拦截,而这个方法并不能监听到数组内部变化,数组长度变化,数组的截取变化等,所以需要对这些操作进行hack,让Vue能监听到其中的变化。

9.Vuedata中某一个属性的值发生改变后,视图会立即同步执 行重新渲染吗?

不会立即同步执行重新渲染。Vue实现响应式并不是数据发生变化之后DOM立即变化,而是按一定的策略进行DOM的更新。Vue在更新DOM时是异步执行的。只要侦听到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更

如果同一个watcher被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和DOM操作是非常重要的。然后,在下一个的事件循环tick中,Vue刷新队列并执行实际(已去重的)工作

10.子组件可以直接改变父组件的数据吗?

子组件不可以直接改变父组件的数据。这样做主要是为了维护父子组件的单向数据流。每次父级组件发生更新时,子组件中所有的prop 都将会刷新为最新的值。如果这样做了,Vue会在浏览器的控制台中发出警告

Vue提倡单向数据流,即父级props的更新会流向子组件,但是反过来则不行。这是为了防止意外的改变父组件状态,使得应用的数据流变得难以理解,导致数据流混乱。如果破坏了单向数据流,当应用复杂时,debug的成本会非常高。

只能通过$emit派发一个自定义事件,父组件接收到后,由父组件修改

11.对React和Vue的理解,它们的异同

相似之处:

  • 都将注意力集中保持在核心库,而将其他功能如路由和全局状态管理交给相关的库
  • 都有自己的构建工具,能让你得到一个根据最佳实践设置的项目模板
  • 都使用了VirtualDOM(虚拟DOM)提高重绘性能
  • 都有props的概念,允许组件间的数据传递
  • 都鼓励组件化应用,将应用分拆成一个个功能明确的模块,提高复用性

不同之处:

(1)数据流:Vue默认支持数据双向绑定,而React一直提倡单向数据流

(2)虚拟DOM:Vue2.x开始引入"VirtualDOM",消除了和React在这方面的差异,但是在具体的细节还是有各自的特点:

Vue 宣称可以更快地计算出VirtualDOM的差异,这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树

对于React 而言,每当应用的状态被改变时,全部子组件都会重新渲染。当然,这可以通过PureComponent/shouldComponentUpdate这个生命周期方法来进行控制,但Vue将此视为默认的优化 (3)组件化:React与Vue最大的不同是模板的编写

Vue鼓励写近似常规HTML的模板。写起来很接近标准HTML元素,只是多了一些属性

React推荐你所有的模板通用JavaScript的语法扩展------JSX书写

具体来讲:React 中render函数是支持闭包特性的,所以import的组件在render中可以直接调用

但是在Vue 中,由于模板中使用的数据都必须挂在this上进行一次中转,所以import一个组件完了之后,还需要在components中再声明下

(4)监听数据变化的实现原理不同:

Vue通过getter/setter以及一些函数的劫持,能精确知道数据变化,不需要特别的优化就能达到很好的性能

React默认是通过比较引用的方式进行的,如果不优化(PureComponent/shouldComponentUpdate)可能导致大量不必要的vDOM的重新渲染。

这是因为Vue使用的是可变数据,而React更强调数据的不可变

(5)高阶组件:

react可以通过高阶组件(HOC)来扩展,而Vue需要通过mixins来扩展

高阶组件就是高阶函数,而React的组件本身就是纯粹的函数,所以高阶函数对React来说易如反掌。相反Vue.js使用HTML模板创建视图组件,这时模板无法有效的编译,因此Vue不能采用HOC来实现

(6)构建工具:两者都有自己的构建工具

React==>CreateReactAPP

Vue==>vue-cli

(7)跨平台:

React==>ReactNative

Vue==>Weex

12.Vue的优点

  • 轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十kb
  • 简单易学:国人开发,中文文档,不存在语言障碍,易于理解和学习
  • 双向数据绑定:保留了angular的特点,在数据操作方面更为简单
  • 组件化:保留了react的优点,实现了html的封装和重用,在构建单页面应用方面有着独特的优势
  • 视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作
  • 虚拟DOM:dom操作是非常耗费性能的,不再使用原生的dom操作节点,极大解放dom操作,但具体操作的还是dom不过是换了另一种方式
  • 运行速度更快:相比较于react而言,同样是操作虚拟dom,就性能而言,vue存在很大的优势

13.assets和static的区别

相同点:assets和static两个都是存放静态资源文件。项目中所需要的资源文件图片,字体图标,样式文件等都可以放在这两个文件下

不相同点:assets中存放的静态资源文件在项目打包时,也就是运行npm run build时会将assets中放置的静态资源文件进行打包上传,所谓打包简单点可以理解为压缩体积,代码格式化。而压缩后的静态资源文件最终也都会放置在static文件中跟着index.html一同上传至服务器。static中放置的静态资源文件就不会要走打包压缩格式化等流程,而是直接进入打包好的目录,直接上传至服务器。因为避免了压缩直接进行上传,在打包时会提高一定的效率,但是static中的资源文件由于没有进行压缩等操作,所以文件的体积也就相对于assets中打包后的文件体积较大点。在服务器中就会占据更大的空间

建议:将项目中template需要的样式文件js文件等都可以放置在assets中,走打包这一流程。减少体积。而项目中引入的第三方的资源文件如iconfoont.css等文件可以放置在static中,因为这些引入的第三方文件已经经过处理,不再需要处理,直接上传

14.delete和Vue.delete删除数组的区别

delete只是被删除的元素变成了empty/undefined,其他的元素的键值还是不变

Vue.delete直接删除了数组改变了数组的键值

15.Vue模版编译原理

vue中的模板template无法被浏览器解析并渲染,因为这不属于浏览器的标准,不是正确的HTML语法,所以需要将template转化成一个JavaScript函数,这样浏览器就可以执行这一个函数并渲染出对应的HTML元素,就可以让视图跑起来了,这一个转化的过程,就称为模板编译。模板编译又分三个阶段,解析parse,优化optimize,生成generate,最终生成可执行函数render

解析阶段:使用大量的正则表达式对template字符串进行解析,将标签、指令、属性等转化为抽象语法树AST

优化阶段:遍历AST,找到其中的一些静态节点并进行标记,方便在页面重渲染的时候进行diff比较时,直接跳过这一些静态节点,优化runtime的性能

生成阶段:将最终的AST转化为render函数字符串

16.vue初始化页面闪动问题

使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类 似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是还是有必要让解决这个问题的

首先:在css里加上以下代码:

如果没有彻底解决问题,则在根元素加上style="display: none;":style="{display:'block'}"

17.MVVM的优缺点?

优点:

  • 分离视图(View)和模型(Model),降低代码耦合,提⾼视图或者逻辑的重⽤性:⽐如视图(View)可以独⽴于Model变化和修改,⼀个ViewModel可以绑定不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。你可以把⼀些视图逻辑放在⼀个ViewModel⾥⾯,让很多view重⽤这段视图逻辑
  • 提⾼可测试性:ViewModel的存在可以帮助开发者更好地编写测试代码
  • ⾃动更新dom:利⽤双向绑定,数据更新后视图⾃动更新,让开发者从繁琐的⼿动dom中解放

缺点:

Bug很难被调试:因为使⽤双向绑定的模式,当你看到界⾯异常了,有可能是你View的代码有Bug,也可能是Model的代码有问题。数据绑定使得⼀个位置的Bug被快速传递到别的位置,要定位原始出问题的地⽅就变得不那么容易了

另外,数据绑定的声明是指令式地写 在View的模版当中的,这些内容是没办法去打断点debug的

⼀个⼤的模块中model也会很⼤,虽然使⽤⽅便了也很容易保证了数据的⼀致性,当时⻓期持有,不释放内存就造成了花费更多的内存,对于⼤型的图形应⽤程序,视图状态较多,ViewModel的构建和维护的成本都会⽐较⾼

18.v-if和v-for哪个优先级更高?如果同时出现,应如何优化?

v-for优先于v-if被解析,如果同时出现,每次渲染都会先执行循环再判断条件,无论如何循环都不可避免,浪费了性能

要避免出现这种情况,则在外层嵌套template,在这一层进行v-if判断,然后在内部进行v-for循环。如果条件出现在循环内部,可通过计算属性提前过滤掉那些不需要显示的项

19.对Vue组件化的理解

  • 组件是独立和可复用的代码组织单元。组件系统是Vue核心特性之一,它使开发者使用小型、独立和通常可复用的组件构建大型应用
  • 组件化开发能大幅提高应用开发效率、测试性、复用性等
  • 组件使用按分类有:页面组件、业务组件、通用组件
  • vue的组件是基于配置的,我们通常编写的组件是组件配置而非组件,框架后续会生成其构造函数,它们基于VueComponent,扩展于Vue
  • vue中常见组件化技术有:属性prop,自定义事件,插槽等,它们主要用于组件通信、扩展等
  • 组件应该是高内聚、低耦合的
  • 遵循单向数据流的原则

20.说一下Vue的生命周期

Vue实例有⼀个完整的生命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom->渲染、更新->渲染、卸载等⼀系列过程,称这是Vue的生命周期

  • beforeCreate(创建前):数据观测和初始化事件还未开始,此时data的响应式追踪、event/watcher都还没有被设置,也就是说不能访问到data、computed、watch、methods上的方法和数据
  • created(创建后):实例创建完成,实例上配置的options包括data、computed、watch、methods等都配置完成,但是此时渲染的节点还未挂载到DOM,所以不能访问到$el属性
  • beforeMount(挂载前):在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。此时还没有挂载html到页面上
  • mounted(挂载后):在el被新创建的vm.$el替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互
  • beforeUpdate(更新前):响应式数据更新时调用,此时虽然响应式数据更新了,但是对应的真实DOM还没有被渲染
  • updated(更新后):在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。此时DOM已经根据响应式数据的变化更新了。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用
  • beforeDestroy(销毁前):实例销毁之前调用。这一步实例仍然完全可用,this仍能获取到实例
  • destroyed(销毁后):实例销毁后调用,调用后,Vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务端渲染期间不被调用
  • 另外还有keep-alive独有的生命周期,如果为一个组件包裹了keep-alive,那么它会多出两个生命周期:deactivated、activated。同时,beforeDestroy和destroyed就不会再被触发了,因为组件不会被真正销毁。当组件被换掉时,会被缓存到内存中、触发deactivated生命周期;当组件被切回来时,再去缓存里找这个组件、触发activated钩子函数

21.Vue子组件和父组件执行顺序

加载渲染过程:

1.父组件beforeCreate

2.父组件created

3.父组件beforeMount

4.子组件beforeCreate

5.子组件created

6.子组件beforeMount

7.子组件mounted

8.父组件mounted

更新过程:

1.父组件beforeUpdate

2.子组件beforeUpdate

3.子组件updated

4.父组件updated

销毁过程:

1.父组件beforeDestroy

2.子组件beforeDestroy

3.子组件destroyed

4.父组件destoryed

22.created和mounted的区别

created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图

mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作

23.一般在哪个生命周期请求异步数据

可以在钩子函数created、beforeMount、mounted中进行调用,因为在这三个钩子函数中,data已经创建,可以将服务端端返回的数据进行赋值

推荐在created钩子函数中调用异步请求,因为在created钩子函数中调用异步请求有以下优点:

能更快获取到服务端数据,减少页面加载时间,用户体验更好

SSR不支持beforeMount、mounted钩子函数,放在created中有助于一致性

24.路由的hash和history模式的区别

Vue-Router有两种模式:hash模式和history模式。默认的路由模式是hash模式

1.hash模式是开发中默认的模式,它的URL带着一个#,例如: www.abc.com/#/vue, 它的hash值就是#/vue

hash值会出现在URL里面,但是不会出现在HTTP请求中,对后端完全没有影响。所以改变hash值,不会重新加载页面。这种模式的浏览器支持度很好,低版本的IE浏览器也支持这种模式。hash路由被称为是前端路由,已经成为SPA(单页面应用)的标配

2.history模式的URL中没有#,它使用的是传统的路由分发模式,即用户在输入一个URL时,服务器会接收这个请求,并解析这个URL,然后做出相应的逻辑处理。特点:当使用history模式时,URL就像这样: abc.com/user/id。 相比hash模式更加好看。但是,history 模式需要后台配置支持。如果后台没有正确配置,访问时会返回404

25.Vue-router跳转和location.href有什么区别

使用location.href=/url来跳转,简单方便,但是刷新了页面

使用history.pushState(/url),无刷新页面,静态跳转;引进router,然后使用router.push(/url)来跳转,使用了diff 算法,实现了按需加载,减少了dom的消耗。其实使用router跳转和使用history.pushState()没什么差别的,因为vue-router就是用了history.pushState(),尤其是在history模式下

26.Vuex的原理

Vuex是一个专为Vue.js应用程序开发的状态管理模式。每一个Vuex应用的核心就是store(仓库)。"store"基本上就是一个容器,它包含着你的应用中大部分的状态(state)

Vuex的状态存储是响应式的。当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应地得到高效更新

改变store中的状态的唯一途径就是显式地提交(commit) mutation。这样可以方便地跟踪每一个状态的变化

Vuex为VueComponents建立起了一个完整的生态圈,包括开发中的API调用一环

(1)核心流程中的主要功能:

Vue Components是vue组件,组件会触发(dispatch)一些事件或动作,也就是图中的Actions;

在组件中发出的动作,肯定是想获取或者改变数据的,但是在vuex中,数据是集中管理的,不能直接去更改数据,所以会把这个动作提交(Commit)到Mutations中;

然后Mutations就去改变(Mutate)State中的数据;

当State中的数据被改变之后,就会重新渲染(Render)到Vue Components中去,组件展示更新后的数据,完成一个流程

(2)各模块在核心流程中的主要功能:

Vue Components:Vue组件。HTML页面上,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。

dispatch:操作行为触发方法,是唯一能执行action的方法。

actions:操作行为处理模块。负责处理Vue Components接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以支持action的链式触发。

commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。

mutations:状态改变操作方法。是Vuex修改state的唯一推荐方法,其他修改方式在严格模式下将会报错。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。

state:页面状态管理容器对象。集中存储Vue components中data对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。

getters:state对象读取方法。图中没有单独列出该模块,应该被包含在了render中,Vue Components通过该方法读取全局state对象

总结:Vuex实现了一个单向数据流,在全局拥有一个State存放数据,当组件要更改State中的数据时,必须通过Mutation提交修改信息,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上

27.Vuex和localStorage的区别

(1)最重要的区别:

vuex存储在内存中

localstorage则以文件的方式存储在本地,只能存储字符串类型的数据,存储对象需要JSON的stringify和parse方法进行处理。读取内存比读取硬盘速度要快

(2)应用场景:

Vuex是一个专为Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。vuex用于组件之间的传值

localstorage是本地存储,是将数据存储到浏览器的方法,一般是在跨页面传递数据时使用

Vuex能做到数据的响应式,localstorage不能

(3)永久性:

刷新页面时vuex存储的值会丢失,localstorage不会

注意:对于不变的数据确实可以用localstorage可以代替vuex,但是当两个组件共用一个数据源(对象或数组)时,如果其中一个组件改变了该数据源,希望另一个组件响应该变化时,localstorage无法做到

28.Vue3.0有什么更新

(1)监测机制的改变:

3.0将带来基于代理Proxy的observer实现,提供全语言覆盖的反应性跟踪。消除了Vue 2当中基于Object.defineProperty的实现所存在的很多限制

Vue2在添加或删除对象的属性时,Vue检测不到。因为添加或删除的对象没有在初始化进行响应式处理,只能通过$set来调用Object.defineProperty()处理

Vue3使用Proxy来监控数据的变化。Proxy是ES6中提供的功能,其作用为:用于定义基本操作的自定义行为(如属性查找,赋值,枚 举,函数调用等)。相对于Object.defineProperty(),其有以下特点:

  • Proxy直接代理整个对象而非对象属性,这样只需做一层代理就可以监听同级结构下的所有属性变化,包括新增属性和删除属性
  • Proxy可以监听数组的变化

(2)只能监测属性,不能监测对象:

检测属性的添加和删除

检测数组索引和长度的变更

支持Map、Set、WeakMap和WeakSet

(3)模板:

作用域插槽,2.x的机制导致作用域插槽变了,父组件会重新渲染,而3.0把作用域插槽改成了函数的方式,这样只会影响子组件的重新渲染,提升了渲染的性能

同时,对于render函数的方面,vue3.0也会进行一系列更改来方便习惯直接使用api来生成vdom

(4)对象式的组件声明方式:

vue2.x中的组件是通过声明的方式传入一系列option,和TypeScript的结合需要通过一些装饰器的方式来做,虽然能实现功能,但是比较麻烦

3.0修改了组件的声明方式,改成了类式的写法,这样使得和TypeScript的结合变得很容易

(5)其它方面的更改:

支持自定义渲染器,从而使得weex可以通过自定义渲染器的方式来扩展,而不是直接fork源码来改的方式

支持Fragment(多个根节点)和Protal(在dom其他部分渲染组 建内容)组件,针对一些特殊的场景做了处理

基于treeshaking优化,提供了更多的内置功能

(6)虚拟DOM:

静态节点提升:将静态节点与动态节点分离,有效提高了渲染性能

快速标记和补丁:Vue 3.0中采用了更加高效的标记和补丁方式,使得页面渲染更加快速和稳定

更小的bundle大小:Vue 3.0使用了tree-shaking和基于ES2015的模块系统,使得框架的bundle大小更加的小。

(7)生命周期:

vue3.0与vue2.0之间生命周期函数在销毁的时候有变化:

beforeDestroy-->beforeUnmount

destroyed-->unmounted

(8)v-model 升级:

变更:在自定义组件上使用v-model时,属性以及事件的默认名称变了

变更:v-bind的.sync修饰符在 Vue 3 中又被去掉了, 合并到了v-model里

新增:同一组件可以同时设置多个 v-model

新增:开发者可以自定义 v-model修饰符

29.DIFF算法的原理

首先,对比节点本身,判断是否为同一节点,如果不为相同节点,则删除该节点重新创建节点进行替换

如果为相同节点,进行patchVnode,判断如何对该节点的子节点进行处理,先判断一方有子节点一方没有子节点的情况(如果新的children没有子节点,将旧的子节点移除)

比较如果都有子节点,则进行updateChildren,判断如何对这些新老节点的子节点进行操作(diff核心)

匹配时,找到相同的子节点,递归比较子节点

在diff中,只对同层的子节点进行比较,放弃跨级的节点比较,使得时间复杂从O(n3)降低至O(n),也就是说,只有当新旧children都为多个子节点时才需要用核心的Diff算法进行同层级比较

30.Vue中key的作用

vue中key值的作用可以分为两种情况来考虑:

(1)v-if中使用key:由于Vue会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。因此当使用v-if来实现元素切换的时候,如果切换前后含有相同类型的元素,那么这个元素就会被复用。如果是相同的input元素,那么切换前后用户的输入不会被清除掉,这样是不符合需求的。因此可以通过使用key来唯一的标识一个元素,这个情况下,使用key的元素不会被复用。这个时候key的作用是用来标识一个独立的元素

(2)v-for中使用key:用v-for更新已渲染过的元素列表时,它默认使用"就地复用"的策略。如果数据项的顺序发生了改变,Vue不会移动DOM元素来匹配数据项的顺序,而是简单复用此处的每个元素。因此通过为每个列表项提供一个key值,来以便Vue跟踪元素的身份,从而高效的实现复用。这个时候key的作用是为了高效的更新渲染虚拟DOM

key是为Vue中vnode的唯一标记,通过这个key,diff操作可以更准确、更快速

更准确:因为带key就不是就地复用了,在sameNode函数a.key===b.key对比中可以避免就地复用的情况。所以会更加准确

更快速:利用key的唯一性生成map对象来获取对应节点,比遍历方式更快

相关推荐
正小安30 分钟前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch2 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光2 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   2 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   2 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web2 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常2 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇3 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr3 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho4 小时前
【TypeScript】知识点梳理(三)
前端·typescript