Vue相关问题整理

1. Vue的优点

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

2. Vue初始化过程

初始化根组件时进行了选项合并操作,将全局配置合并到根组件的局部配置上;初始化每个子组件时做了一些性能优化,将组件配置对象上的一些深层次属性放到 vm.$options 选项中,以提高代码的执行效率;初始化组件实例的关系属性,比如 parent、children、root、refs等;处理自定义事件;调用 beforeCreate 钩子函数;初始化组件的 inject 配置项,得到 ret[key] = val 形式的配置对象,然后对该配置对象进行响应式处理,并代理每个 key 到 vm 实例上;数据响应式,处理 props、methods、data、computed、watch 等选项,解析组件配置项上的 provide 对象,将其挂载到 vm._provided 属性上;调用 created 钩子函数,如果发现配置项上有 el 选项,则自动调用 $mount 方法,也就是说有了 el 选项,就不需要再手动调用 $mount 方法,反之,没提供 el 选项则必须调用 $mount方法;接下来则进入挂载阶段。

3. 对MVVM的理解

MVVM 由 Model、View、ViewModel 三部分构成,Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来;ViewModel 是一个同步View 和 Model的对象。在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

4. Vue数据双向绑定原理

实现mvvm的数据双向绑定,是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来给各个属性添加setter,getter并劫持监听,在数据变动时发布消息给订阅者,触发相应的监听回调。就必须要实现以下几点:
(1)实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者;
(2)实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数;
(3)实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图;

5. Vue的响应式原理

什么是响应式,也即是说,数据发生改变的时候,视图会重新渲染,匹配更新为最新的值。Object.defineProperty 为对象中的每一个属性,设置 get 和set 方法,每个声明的属性,都会有一个专属的依赖收集器 subs,当页面使用到某个属性时,触发 ObjectdefineProperty - get函数,页面的 watcher 就会被放到属性的依赖收集器 subs中,在数据变化时,通知更新;当数据改变的时候,会触发Object.defineProperty - set函数,数据对象会遍历自己的依赖收集器 subs,逐个通知 watcher,视图开始更新。

6. vue中组件的data为什么是一个函数?而new Vue 实例里,data 可以直接是一个对象?

我们知道,Vue组件其实就是一个Vue实例。JS中的实例是通过构造函数来创建的,每个构造函数可以new出很多个实例,那么每个实例都会继承原型上的方法或属性。Vue的data数据其实是Vue原型上的属性,数据存在于内存当中。Vue为了保证每个实例上的data数据的独立性,规定了必须使用函数,而不是对象。因为使用对象的话,每个实例(组件)上使用的data数据是相互影响的,这当然就不是我们想要的了。对象是对于内存地址的引用,直接定义个对象的话组件之间都会使用这个对象,这样会造成组件之间数据相互影响。使用函数后,使用的是data()函数,data()函数中的this指向的是当前实例本身,就不会相互影响了。而 new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。

7. Vue中data的属性可以和methods中方法同名吗,为什么?

可以同名,methods的方法名会被data的属性覆盖;调试台也会出现报错信息,但是不影响执行;原因:源码定义的initState函数内部执行的顺序:props > methods > data > computed > watch。

8. Vue中created与mounted区别

在created阶段,实例已经被初始化,但是还没有挂载至el上,所以我们无法获取到对应的节点,但是此时我们是可以获取到vue中data与methods中的数据的;在mounted阶段,vue的template成功挂载在$el中,此时一个完整的页面已经能够显示在浏览器中,所以在这个阶段,可以调用节点了。

9. Vue中computed与method的区别

相同点:如果作为模板的数据显示,二者能实现响应的功能,唯一不同的是methods定义的方法需要执行。
不同点:1.computed 会基于响应数据缓存,methods不会缓存;2.diff之前先看data里的数据是否发生变化,如果没有变化computed的方法不会执行,但methods里的方法会执行;3.computed是属性调用,而methods是函数调用。

10. Vue中对mixins的理解和使用

mixins是一种分发 Vue 组件中可复用功能的非常灵活的方式。混合对象可以包含任意组件选项。当组件使用混合对象时,所有混合对象的选项将被混入该组件本身的选项。而mixins引入组件之后,则是将组件内部的内容如data等方法、method等属性与父组件相应内容进行合并。相当于在引入后,父组件的各种属性方法都被扩充了。

11. 为什么vue采用异步渲染

vue是组件级更新,当前组件里的数据变了,它就会去更新这个组件。当数据更改一次组件就要重新渲染一次,性能不高,为了防止数据一更新就更新组件,所以做了个异步更新渲染。(核心的方法就是nextTick)
源码实现原理:
当数据变化后会调用notify方法,将watcher遍历,调用update方法通知watcher进行更新,这时候watcher并不会立即去执行,在update中会调用queueWatcher方法将watcher放到了一个队列里,在queueWatcher会根据watcher的进行去重,多个属性依赖一个watcher,如果队列中没有该watcher就会将该watcher添加到队列中,然后通过nextTick异步执行flushSchedulerQueue方法刷新watcher队列。flushSchedulerQueue中开始会触发一个before的方法,其实就是beforeUpdate,然后watcher.run() 才开始真正执行watcher,执行完页面就渲染完成啦,更新完成后会调用updated钩子。

12. Vue 的异步更新机制是如何实现的?

Vue 的异步更新机制的核心是利用了浏览器的异步任务队列来实现的,首选微任务队列,宏任务队列次之。当响应式数据更新后,会调用 dep.notify 方法,通知 dep 中收集的 watcher 去执行 update 方法,watcher.update 将 watcher 自己放入一个 watcher 队列(全局的 queue 数组)。然后通过 nextTick 方法将一个刷新 watcher 队列的方法(flushSchedulerQueue)放入一个全局的 callbacks 数组中。如果此时浏览器的异步任务队列中没有一个叫 flushCallbacks 的函数,则执行 timerFunc 函数,将 flushCallbacks 函数放入异步任务队列。如果异步任务队列中已经存在 flushCallbacks 函数,等待其执行完成以后再放入下一个 flushCallbacks 函数。flushCallbacks 函数负责执行 callbacks 数组中的所有 flushSchedulerQueue 函数。flushSchedulerQueue 函数负责刷新 watcher 队列,即执行 queue 数组中每一个 watcher 的 run 方法,从而进入更新阶段,比如执行组件更新函数或者执行用户 watch 的回调函数。

13. 对$nextTick的理解

用法:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。所以为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。使用场景:在你更新完数据后,需要及时操作渲染好的 DOM时。

14. Vue中常用的一些指令

  1. v-model指令:用于表单输入,实现表单控件和数据的双向绑定。
  2. v-on:简写为@,基础事件绑定
  3. v-bind:简写为:,动态绑定一些元素的属性,类型可以是:字符串、对象或数组。
  4. v-if指令:取值为true/false,控制元素是否需要被渲染
  5. v-else指令:和v-if指令搭配使用,没有对应的值。当v-if的值false,v-else才会被渲染出来。
  6. v-show指令:指令的取值为true/false,分别对应着显示/隐藏。
  7. v-for指令:遍历data中存放的数组数据,实现列表的渲染。
  8. v-once: 通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。
vue的自定义指令

Vue除了核心功能默认内置的指令 ,Vue 也允许注册自定义指令。自定义指令是用来操作DOM的。尽管Vue推崇数据驱动视图的理念,但并非所有情况都适合数据驱动。自定义指令就是一种有效的补充和扩展,不仅可用于定义任何的DOM操作,并且是可复用的。添加自定义指令的两种方式,全局指令:通过 Vue.directive() 函数注册一个全局的指令;局部指令:通过组件的 directives 属性,对该组件添加一个局部的指令。

15. Vue生命周期

  • beforeCreate:初始化事件,进行数据的观测,此时数据已经和data属性进行绑定。
  • created:首先会判断对象是否有el选项。如果有的话就继续向下编译,如果没有el选项,则停止编译,也就意味着停止了生命周期,直到在该vue实例上调用vm.$mount(el),生命周期才会继续。
  • beforeMount:构建虚拟DOM,给vue实例对象添加$el成员,并且替换掉挂载的DOM元素。
  • mounted:渲染实际DOM。
  • beforeUpdate:根据数据变化重新构建虚拟DOM。
  • updated:渲染DOM。
  • beforeDestroy:销毁Vue实例所有的数据绑定、子组件以及事件监听器。
  • destroyed:Vue实例已被销毁,生命周期结束。

16.Vue组件通信有哪些方式

① 父传子:props。父组件通过 props 向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed;
② 父传子孙:provide 和 inject。父组件定义provide方法return需要分享给子孙组件的属性,子孙组件使用 inject 选项来接收指定的我们想要添加在这个实例上的 属性;
③ 子传父:通过事件形式。子组件通过 $emit()给父组件发送消息,父组件通过v-on绑定事件接收数据。
④ 父子、兄弟、跨级:eventBus.js。这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来(emit)触发事件和(emit)触发事件和(emit)触发事件和(on)监听事件,巧妙而轻量地实现了任何组件间的通信。
⑤ 通信插件:PubSub.js;
⑥ Vuex。vuex 是 vue 的状态管理器,存储的数据是响应式的。只需要把共享的值放到vuex中,其他需要的组件直接获取使用即可。

17. router和route的区别

router为VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,例如history对象。经常用的跳转链接就可以用this.$router.push,和router-link跳转一样。route相当于当前正在跳转的路由对象。。可以从里面获取name, path, params, query等。

18. vue-router有几种钩子函数?

① 全局路由:全局导航钩子主要有两种钩子:前置守卫(beforeEach)、后置钩子(afterEach);
② 路由独享的钩子:单个路由独享的导航钩子,它是在路由配置上直接进行定义的;
③ 组件内的导航钩子:组件内的导航钩子主要有这三种:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。他们是直接在路由组件内部直接进行定义的。

19. vue-router路由传参

router-link 进行页面按钮式路由跳转传参;this.$router.push进行编程式路由跳转传参。

20. keep-alive

keep-alive是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
钩子函数: ”activated “组件渲染后调用 ”deactivated“组件销毁后调用
原理:Vue.js内部将DOM节点抽象成了一个个的VNode节点,keep-alive组件的缓存也是基于VNode节点的而不是直接存储DOM结构。它将满足条件(pruneCache与pruneCache)的组件在cache对象中缓存起来,在需要重新渲染的时候再将vnode节点从cache对象中取出并渲染。
配置属性: include 字符串或正则表达式。只有名称匹配的组件会被缓存 exclude 字符串或正则表达式。任何名称匹配的组件都不会被缓存 max 数字、最多可以缓存多少组件实例。

21. Vuex是什么?怎么使用?

Vuex是实现组件全局状态(数据)管理的一种机制,可以方便实现组件之间的数据共享;Vuex集中管理共享的数据,易于开发和后期维护;能够高效的实现组件之间的数据共享,提高开发效率;存储在Vuex的数据是响应式的,能够实时保持页面和数据的同步;
Vuex重要核心属性包括:state, mutations, action, getters, modules。
state:Vuex 使用单一状态树,即每个应用将仅仅包含一个store 实例,但单一状态树和模块化并不冲突。存放的数据状态,不可以直接修改里面的数据。
mutations:mutations定义的方法动态修改Vuex 的 store 中的状态或数据。
action:actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action。
getters:类似vue的计算属性,主要用来过滤一些数据。
modules:项目特别复杂的时候,可以让每一个模块拥有自己的state、mutation、action、getters, 使得结构非常清晰,方便管理。

22. Vuex和单纯的全局对象有什么区别?

Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

23. 为什么 Vuex 的 mutation 中不能做异步操作?

每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来,然后就可以实现 time-travel 了。如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。

24. axios 是什么,其特点和常用语法

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。前端最流行的 ajax 请求库,react/vue 官方都推荐使用 axios 发 ajax 请求。
特点:
基于 promise 的异步 ajax 请求库,支持promise所有的API;浏览器端/node 端都可以使用,浏览器中创建XMLHttpRequests;支持请求/响应拦截器,支持请求取消;可以转换请求数据和响应数据,并对响应回来的内容自动转换成 JSON类型的数据;批量发送多个请求;安全性更高,客户端支持防御 XSRF,就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。

25. 对SSR有了解吗,它主要解决什么问题?

Server-Side Rendering 我们称其为SSR,意为服务端渲染指由服务侧完成页面的 HTML 结构拼接的页面处理技术,发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的过程;
解决了以下两个问题:
seo:搜索引擎优先爬取页面HTML结构,使用ssr时,服务端已经生成了和业务想关联的HTML,有利于seo;首屏呈现渲染:用户无需等待页面所有js加载完成就可以看到页面视图(压力来到了服务器,所以需要权衡哪些用服务端渲染,哪些交给客户端)。
缺点:
复杂度:整个项目的复杂度提高;性能会受到影响;服务器负载变大,相对于前后端分离务器只需要提供静态资源来说,服务器负载更大,所以要慎重使用。

26. 做过哪些Vue的性能优化?

编码阶段尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher。v-if和v-for不能连用。如果需要使用v-for给每项元素绑定事件时使用事件代理。SPA 页面采用keep-alive缓存组件。在更多的情况下,使用v-if替代v-show。key保证唯一。使用路由懒加载、异步组件。防抖、节流。第三方模块按需导入。长列表滚动到可视区域动态加载。图片懒加载。SEO优化。服务端渲染SSR。预渲染。打包优化。压缩代码。使用cdn加载第三方模块。splitChunks抽离公共文件。

27. Vue动态路由

动态路由,动态即不是写死的,是可变的。我们可以根据自己不同的需求加载不同的路由,做到不同的实现及页面的渲染。动态的路由存储可分为两种,一种是将路由存储到前端。另一种则是将路由存储到数据库。动态路由的使用一般结合角色权限控制一起使用。
好处:使用动态路由可以跟灵活,无需手工维护,我们可以使用一个页面对路由进行维护。如果将路由存储到数据库,还可以增加安全性。
如何实现:一般我们在登录的时候,根据登录用户的角色返回此角色可以访问的页面的路由,前端将路由存储到vuex(vuex存储的数据必须可持久的,不要一刷新页面就不见),我们在路由前置守卫处动态添加拿到的路由,对页面进行渲染。

28. computed 与 watch

watch

属性监听,是一个对象,键是需要观察的属性,值是对应回调函数,主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作,监听属性的变化,需要在数据变化时执行异步或开销较大的操作时使用。

computed

计算属性,属性的结果会被缓存,当computed中的函数所依赖的属性没有发生改变的时候,那么调用当前函数的时候结果会从缓存中读取。除非依赖的响应式属性变化时才会重新计算,主要当做属性来使用 computed中的函数必须用return返回最终的结果 computed更高效,优先使用。data 不改变,computed 不更新。

使用场景

computed:当一个属性受多个属性影响的时候使用,例:购物车商品结算功能。
watch:当一条数据影响多条数据的时候使用,例:搜索数据。

29. v-if 和 v-for 的优先级

v-for的优先级是高于v-if的,如果两者同时出现的话,那每次循环都会执行v-if,会很浪费性能,我们正确的做法应该是再v-for的外面新增一个模板标签template,在template上使用v-if。

30. v-for 中 key 的作用

  1. key的作用是为了在diff算法执行时更快的找到对应的节点,提高diff速度,更高效的更新虚拟DOM;
  2. Vue在patch过程中判断两个节点是否是相同节点,key是一个必要条件,渲染一组列表时,key往往是唯一标识,所以如果不定义key的话,Vue只能认为比较的两个节点是同一个,哪怕它们实际上不是,这导致了频繁更新元素,使得整个patch过程比较低效,影响性能;
  3. 从源码中可以知道,Vue判断两个节点是否相同时主要判断两者的key和元素类型等,因此如果不设置key,它的值就是undefined,则可能永 远认为这是两个相同的节点,只能去做更新操作,这造成了大量的dom更新操作,明显是不可取的。

31. Vue2 和 Vue3 区别

属性监听:

defineProperty: 遍历对象,劫持对象的每一个属性; Proxy: 劫持整个对象,并返回一个代理对象;

对数组方法的支持:

defineProperty: push...等不能监听;Proxy: 可以监听;

兼容:

defineProperty(ES5)兼容性比Proxy(ES6)好。

32. webpack 常用 Loader

  • raw-loader:加载文件原始内容(utf-8)
  • file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体)
  • source-map-loader:加载额外的 Source Map 文件,以方便断点调试
  • svg-inline-loader:将压缩后的 SVG 内容注入代码中
  • image-loader:加载并且压缩图片文件
  • json-loader 加载 JSON 文件(默认包含)
  • babel-loader:把 ES6 转换成 ES5
  • ts-loader: 将 TypeScript 转换成 JavaScript
  • awesome-typescript-loader:将 TypeScript 转换成 JavaScript,性能优于 ts-loader
  • sass-loader:将SCSS/SASS代码转换成CSS
  • css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
  • style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS
  • postcss-loader:扩展 CSS 语法,使用下一代 CSS,可以配合 autoprefixer 插件自动补齐 CSS3 前缀
  • vue-loader:加载 Vue.js 单文件组件

33. webpack 常用的 Plugin

  • define-plugin:定义环境变量 (Webpack4 之后指定 mode 会自动配置)
  • ignore-plugin:忽略部分文件
  • html-webpack-plugin:简化 HTML 文件创建 (依赖于 html-loader)
  • web-webpack-plugin:可方便地为单页应用输出 HTML,比 html-webpack-plugin 好用
  • uglifyjs-webpack-plugin:不支持 ES6 压缩 (Webpack4 以前)
  • terser-webpack-plugin: 支持压缩 ES6 (Webpack4)
  • webpack-parallel-uglify-plugin: 多进程执行代码压缩,提升构建速度
  • mini-css-extract-plugin: 分离样式文件,CSS 提取为独立文件,支持按需加载 (替代extract-text-webpack-plugin)
  • serviceworker-webpack-plugin:为网页应用增加离线缓存功能
  • clean-webpack-plugin: 目录清理

34. webpack loader 和 plugin 的区别

Loader 本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。 因为 Webpack 只认识 JavaScript,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。
Plugin 就是插件,基于事件流框架 Tapable,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
Loader 在 module.rules 中配置,作为模块的解析规则,类型为数组。每一项都是一个 Object,内部包含了 test(类型文件)、loader、options (参数)等属性。
Plugin 在 plugins 中单独配置,类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入。

35. 怎样理解 Vue 的单向数据流?

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。
这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。

36. 直接给一个数组项赋值,Vue 能检测到变化吗?

由于 JavaScript 的限制,Vue 不能检测到以下数组的变动:

  • 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue;
  • 当你修改数组的长度时,例如:vm.items.length = newLength。

为了解决第一个问题,Vue 提供了以下操作方法:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// vm.$set,Vue.set的一个别名
vm.$set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

为了解决第二个问题,Vue 提供了以下操作方法:

// Array.prototype.splice
vm.items.splice(newLength)

37. Vue 的父组件和子组件生命周期钩子函数执行顺序?

Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分:

  • 加载渲染过程 :
    父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
  • 子组件更新过程 :
    父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
  • 父组件更新过程 :
    父 beforeUpdate -> 父 updated
  • 销毁过程 :
    父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed

38. 父组件可以监听到子组件的生命周期吗?

比如有父组件 Parent 和子组件 Child,如果父组件监听到子组件挂载 mounted 就做一些逻辑处理,可以通过以下写法实现:

// Parent.vue


// Child.vue
mounted() {
  this.$emit("mounted");
}

以上需要手动通过 $emit 触发父组件的事件,更简单的方式可以在父组件引用子组件时通过 @hook 来监听即可,如下所示:

//  Parent.vue


doSomething() {
   console.log('父组件监听到 mounted 钩子函数 ...');
},

//  Child.vue
mounted(){
   console.log('子组件触发 mounted 钩子函数 ...');
},    

// 以上输出顺序为:
// 子组件触发 mounted 钩子函数 ...
// 父组件监听到 mounted 钩子函数 ...

当然 @hook 方法不仅仅是可以监听 mounted,其它的生命周期事件,例如:created,updated 等都可以监听。

39. v-model 的原理?

我们在 vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

  • text 和 textarea 元素使用 value 属性和 input 事件;
  • checkbox 和 radio 使用 checked 属性和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

40. 虚拟 DOM 的优缺点?

优点:
  • 保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;
  • 无需手动操作 DOM: 我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;
  • 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。
缺点:
  • 无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。

41. 虚拟 DOM 实现原理?

虚拟 DOM 的实现原理主要包括以下 3 部分:

  • 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
  • diff 算法 — 比较两棵虚拟 DOM 树的差异;
  • pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。

你可能感兴趣的:(前端vue.js)