yihan12 / Frontend-interview

记录一些前端面试相关题目
2 stars 0 forks source link

部分Vue2基础题 #26

Open yihan12 opened 10 months ago

yihan12 commented 10 months ago

Vue

Vue 借鉴了 angular 的模板和数据绑定技术;又借鉴了 react 的组件化和虚拟 DOM 技术

前言

面试前的临时抱佛脚,也能系统的梳理下所掌握的知识。

面试题

1.vue 的生命周期,生命周期的理解。

#### 答案: > **创建**=>**挂载**=>**更新**=>**销毁**(也就是我们常说的**八个阶段**:`创建前/后`,`挂载前/后`,`更新前/后`,`销毁前/后`)。 > > 含义:Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载 Dom===>渲染、更新===>渲染销毁等一系列过程,称之为 Vue 的生命周期。 > > 作用:Vue 的生命周期有多个事件钩子,让我们在控制整个 Vue 实例的过程时更容易形成好的逻辑。 > > 第一次页面加载会触发的钩子函数:`beforeCreate`、`created`、`beforeMount`、`mounted`。 > > Dom 渲染在哪个周期就已经完成:`mounted`。 > > Vue 的页面请求一般放在哪个生命周期:`created`和`mounted`(区别:mounted 周期中 Dom 已经渲染完成,再去请求数据,就会有空壳 Dom 的情况,会影响布局;而 created 周期中操作 Dom 节点会找不到 Dom)。 如下图(vue 生命周期官网): ![vue生命周期](https://cn.vuejs.org/images/lifecycle.png) 上图理解: 首先需要我们去执行一个实例`new Vue()`,首先执行了 init(init 是 vue 组件默认去执行的),这时是事件和生命钩子的初始化(`Init Events&Lifecycle`); 在实例初始化之后(`Init Events&Lifecycle`)调用了 beforeCreate,此时事件已经好了,也能开始生命周期了(读取配置项,加载生命周期的方法)。 > **说明:这个时候 this 不能使用,data 中的数据、methods 的方法,以及 watcher 中的事件都不能获得**; 接着初始化 inject、provide、state 属性(设置 data、methods、computed...等配置项),也就是`Init injections(注射)&reactivity(反应性)`。在实例调用完成后他会立即调用 created。在这一步,实例已经完成以下配置:数据观测(data observer)、属性和方法的运算、watch/event 事件回调;然而挂载阶段还没开始,$el 属性目前不可见。所以在 init 的时候,事件已经调用了,因此在 beforeCreate 的时候不要修改 data 里面赋值的数据,最早也要在 created 里面做(添加一些行为)。 > **说明:created 这个时候可以操作 vue 中的数据和方法,但是还不能对 dom 节点进行操作** 当 created 完成之后,它会去判断,instance(实例)里面是否含有 el 对象`has 'el' option`。如果没有的话,它就会挂载`when vm.$mounted(el) is called`,然后走下一步,判断是否有模板`has 'template' option`;如果有的话,他就会直接跳到下一步,判断是否有模板`has 'template' option`。 如果有模板'template',就会把 template 解析成一个 render function。通过 render 函数去渲染创建 Dom 树`compile template into render function`;如果没有模板'template',就编译 el 对象外层 html 作为模板`compile el's outerHtml as template`。 beforeMount 再有了 render 函数的时候才会执行,此时$el 和 data 都初始化了,但是在挂载前为虚拟的 Dom 节点。 > **说明:$el 属性已经存在,是虚拟 Dom,只是数据未挂载到模板中** 然后继续执行 render 函数,当执行完 render 函数之后,也就是 el 被新创建的 vm.$el替换`Create vm.$el and replace 'el' with it`,并且挂载到实例上去之后就会调用 mounted 这个钩子。 在 mounted 挂载完成,dom 树已经完成渲染到页面,可进行 dom 操作。但是它不会承诺所有的子组件也都一起被挂载,如果希望等到整个视图都渲染完毕,可以用 vm.$nextTick()。 > **说明:挂载完毕,这时 Dom 节点被渲染到文档内,dom 操作在此时能正常进行** 当数据有更新,就会调用 beforeUpdate,然后虚拟 dom 重新渲染补丁,以最小 dom 开支来重新渲染 dom`Virtual Dom re-render and patch`。 > **说明:beforeUpdate 是指 view 层的数据变化前,不是 data 中数据改变前触发,因为 Vue 是数据驱动的。这里适合在更新之前访问现有 Dom,比如手动移除已添加的事件监听器** 然后就是 updated 执行。由于数据更改导致的虚拟 Dom 重新渲染和打补丁,在这之后会调用该钩子。当该钩子被调用时,组件 Dom 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况,应该避免在此期间更改状态。如果要更改相应状态,最好使用计算属性或 watcher 取而代之。 > **注意:updated 不会承诺所有的子组件也都会被重构。如果你希望整个视图都重绘完毕,可以用 vm.$nectTick()替换掉 uopdated** > **说明: view 层的数据更新后,data 中的数据通 beforeUpdate,都是更新完以后的。** beforeDestroy:实例在销毁之前调用,在这还能访问实例的数据`when vm.$destory() is called`。 当组件销毁时,beforeDestroy 执行,清除 watcher、子组件、事件监听器等`Teardown watchers,child components and event listeners`。 > **说明:实例在组件销毁之前调用,在这一步,实例完全可用** destroyed:Vue 实例销毁后调用,调用后,Vue 实例指示的所有东西会解绑,所有事件监听器会被移除,所有子实例也会被销毁。 > **说明:执行 destroy 方法后,对 data 改变不会触发周期函数,此时,Vue 实例已经解除事件监听和 dom 绑定,但是 Dom 结构依然存在**


2.MVVM 和 MVC 的区别

#### 答案: mvc 和 mvvm 其实区别并不大,都是一种设计思想。主要是 mvc 的 controller 演变成 mvvm 的 viewModel。mvvm 主要解决了 mvc 中的大量的 Dom 操作是页面的渲染性能降低,加载速度变慢,影响用户体验。和当 model 频繁发生变化,开发者需要主动更新到 view。


3.vue 的优点是什么

#### 答案: - 1.低耦合:视图`View`可以独立`Model`变化和修改,一个`ViewModel`可以绑定到不同的`View`上,当`View`变化的时候`Model`可以不变,当`Model`变化的时候`View`也可以不变。 - 2.可重用性:可以把一些视图逻辑放在一个`ViewModel`里面,让很多`View`重用这段视图逻辑。 - 3.独立开发:开发人员可以专注于业务逻辑和数据开发`ViewModel`,设计人员可以专注于页面设计,使用 Expression Blend 可以容易设计界面并生成 xml 代码。 - 4.可测试:界面素来是比较难于测试的,而现在测试可以针对`ViewModel`来写。


4.vue 组件间的参数传递

#### 答案: - 父组件与子组件传值: > 父组件传给子组件:子组件通过`props`方法接收数据; > 子组件传给父组件:`$emit`方法传递。 - 兄弟组件间传值: > `eventBus`:就是创建一个实践中心,相当于中转站,可以用它来传递事件和接收事件; > `vuex`:适合比较大项目,具体看需求。


5.vue 路由的实现:Hash 模式和 History 模式

#### 答案: - **Hash 模式**:是一种把前路由的路径用井号#拼接在真实 URL 后面的模式。当#后面的路径发生变化时,浏览器不会重新发起请求,而是会触发`haschange`事件。 特点:hash 虽然在 URL 中,但是不被包括在 HTTP 请求中;用来指导浏览器动作,对服务端的安全无用,hash 不会重加载页面;可以为hash的改变添加监听事件。 优点:浏览器的兼容性比较好,支持 IE8。 缺点:路径在井号#后面,比较丑。 读取:`window.location.hash`。 - **History 模式**:history 采用 HTML5 的新特性;且提供两个方法:`pushState()`,`replaceState()`可以对浏览器历史记录栈进行修改,以及`popState`事件监听到状态变更。 监听 popState 事件,该事件能监听到:用户点击浏览器前进后退的动作;手动调用 history 的`back`,`forward`和`go`方法。不能监听到:history 的`pushState()`、`replaceState()`。 优点:理解比较正规,没有井号。 缺点:兼容性不如 hash,且需要服务器支持,否则一刷新就 404 了。


6.vue 路由跳转

#### 答案: 声明式(标签跳转) ```javascript


7.v-if 和 v-show 的区别

#### 答案: - `v-if`:用于条件性渲染一块内容,这块内容只会在指令表达式返回`true`的时候被渲染。 - `v-show`:`v-show`的元素始终会被渲染保留在 DOM 中。`v-show`只是简单的切换元素 css 的 display。 区别: 1.`v-show`是 css 显隐切换,v-if 是完整的销毁和重新创建; 2.使用频繁切换的时候用`v-show`,运行较少改变时用`v-if`; 3.`v-if`是条件渲染,当 false 的时候不会渲染,页面也不会有 html 标签生成,`v-show`则是不管为 true 或者 false,html 元素都存在,只是 css 样式 display 的显隐; 4.当我们需要经常切换某个元素的显隐时,使用`v-show`更加节省性能,当只需要一次切换时,使用`v-if`更加合理。


8.computed 和 watch 的区别

#### 答案: - `computed`: > `computed`是计算属性,也就是计算值,更多用于计算值的场景; > 具有缓存性,`computed`的值在`getter`执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取`computed`的值时重新调用对应的`getter`来计算; > `computed`更适用于比较消耗性能的场景。 - `watch`: > `watch`更多的是[观察]的作用,类似某些数据的监听回调,用于观察 props 和$emit 或者本组件的值,当数据变化时来执行回调进行后续操作; > 无缓存性,页面重新渲染时值不变化也会执行。 小结: > 当需要进行数值计算时,而且依赖于其他数据,可以把这个数据设计为`computed`; > 当需要在某个数据变化做一些事情,使用`watch`来观察这个数据的变化。


9.keep-alive 组件的作用

#### 答案: ``包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重复渲染。 > 比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情...这样的话列表和详情就会是一个很高频率打开的页面,那么对列表组件使用``进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染。 - 常用的两个属性include\exclude允许组件有条件的进行缓存。 - 两个生命周期activated\deactivated,用来得知当前组件是否处于活跃状态。 - keep-alive中还运用了LRU(最近最少使用)的算法,选择最近最久未使用的组件予以淘汰。


10.Vue 组件的 data 为什么必须是函数

#### 答案: > vue 组件的 data 值不能为对象,因为对象时引用类型,组件可能会被多个实例引用; > 组件中的 data 写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的 data,类似于每个实例创建一个私有的数据空间,让各个组件实例维护各自的数据; > 如果 data 值是对象,将导致多个实例共享一个对象,其中一个组件改变 data 的属性值,其他实例也会受到影响。


11.Vue.nextTick 和 vm.$nextTick 的作用

#### 答案: **官方**: > 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。 Vue 在更新 DOM 时时异步的,当数据发生变化时,Vue 将开启一个一步更新的队列,视图需要等队列的所有数据变化完成之后,再统一进行更新; 如果我们一直在修改相同的数据,异步操作队列还会去重; 等待同一事件循环的所有数据变化完成之后,会将队列中的事件拿来进行处理,进行 Dom 更新。 如果想在修改数据后立刻得到更新后的 DOM 结构,可以使用`Vue.nextTick()` 总结:主要思路就是采用微服务优先的方式调用异步方法去执行 nextTick 包装的方法。


12.Vue 指令有哪些,作用

#### 答案: - `v-if`:条件渲染指令。用于条件渲染一块内容,这块内容只能只在表达式返回`true`时才会被渲染。 `v-show`渲染的元素会始终保留在 DOM 中,`v-show`的切换只是`display`的显隐。 - `v-for`:列表渲染指令。基于数组渲染一个列表。 - `v-bind`:属性绑定指令。给标签属性赋值。 `v-text`:属性绑定指令。显示原文本。 `v-html`:属性绑定指令。以标签内容显示。 - `v-on`:事件绑定指令。用来监听 DOM 事件,并在触发时运行一些 js 代码。 `v-on:click`、 `v-on:keydown`、 `v-on:mouseover`。 - `v-model`:双向数据绑定指令。给 value 赋值。


13.vue 和 react 的区别

#### 答案:


14.vuex 总结

#### 答案: vuex 是一种状态管理机制,将全局组件的共享状态抽取出来为一个`store`,以一个单例的模式存在,应用任何一个组件中都可以使用,vuex 更改`state`的唯一途径是通过`mutation`,`mutation`需要`commit`触发,`action`实际触发是`mutation`,其中`mutation`处理同步任务,`action`处理异步任务。 state:定义了应用状态的数据结构,可以在这里设置默认的初始状态。 getter:允许组件从 store 中获取数据,maoGetter 辅助函数仅仅是 store 中 getter 映射到局部计算属性。 mutation:唯一改变 store 状态的方法,且必须是同步函数。 action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。 module:允许将单一的 store 拆分成单个 store,且同时保存在单一的状态树中。


15.SPA 单页面理解,优缺点?

#### 答案: > SPA(single-page application)仅在 Web 页面初始化时加载响应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面重新加载。 优点: - 用户体验好,快,内容改变不需要重新加载整个页面,避免不必要的跳转和重复渲染; - SPA 相对服务器压力小; - 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理; 缺点: - 首屏(初次)加载慢:为实现单页 web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载; - 不利于 SEO:由于所有的内容在一个页面动态替换显示,所以在 SEO 上有着天然的弱势。 - 前进后退路由管理:由于单页面在一个页面中显示所有的内容,所以不能用浏览器的前进后退功能,所有页面的切换需要进行堆栈处理


16.new Vue()发生了什么?

#### 答案: - `new Vue()`创建 Vue 实例,它内部执行了根实例的初始化过程。 - 具体包括以下操作: 选项合并 `$children`、`$refs`、`$slots`、`$createElement`等实例的方法初始化 自定义时间处理 数据响应式处理 生命钩子的调用(beforecreate created) 可能的挂载 - 总结:`new Vue()`创建了根实例并准备好数据和方法,未来执行挂载时,此过程还会递归的应用于它的子组件上,最终形成一个有紧密关系的组件实例树。


17.vue 性能优化

#### 答案: 1) 编码阶段: - 尽量减少 data 中的数据,data 中的数据都会增加 getter 和 setter,会收集对应的 watcher; - 如果需要使用 v-for 给每项元素绑定事件时使用事件代理; - SPA 页面采用 keep-alive 缓存组件; - 在更多情况下使用 v-if 替代 v-show; - key 保证唯一; - 使用路由懒加载、异步组件; - 防抖节流; - 第三方模块按需导入; - 长列表滚动到可视区动态加载; - 图片懒加载、不在 HTML 里缩放图像、使用雪碧图(CSS sprite)、使用字体图标(iconfont)、使用 WebP; - 降低重绘重排的频率和成本; - CSS 读写分离,不用 js 操作元素样式; 2. 用户体验: - 骨架屏; - PWA; - 使用缓存(客户端缓存,服务端缓存,服务端开启 gzip 压缩); 3)SEO 优化: - 预渲染; - 服务端渲染 SSR; 4)打包优化: - 压缩代码(注意:不要对图片文件进行 Gzip 压缩); - Tree Shaking/Scope Hoisting; - 使用 cdn 加载第三方模块; - 多线程打包 happypack; - splitChunks 抽离公共组件; - sourceaMap 优化


18.vue 的 MVVM

#### 答案: ViewModel:做了两件事情达到数据绑定,首先将模型转换为视图,即将后台传递的数据转化成所看到的的页面,实现方式数据绑定;二是将视图转化成模型,即将所看的页面转化成后端数据 ,实现方式是 DOM 事件监听。 MVC 和 MVVM 最大的区别是:实现了 view 和 model 的自动同步,也就是当 model 属性改变时,我们不需要手动操作 DOM 元素,来改变 view 的显示,而是改变属性后,该属性对应的 view 层会自动改变(对应 vue 数据驱动的思想) 整体看来,MVVM 比 MVC 精简得多,不仅简化了业务与界面的依赖 ,还解决了数据频繁更新的问题,不用再用选择器操作 DOM 元素。因为在 MVVM 中,View 不知道 Model 的存在,View 和 ViewModel 也观察不到 View,这种低耦合模式提高代码的可重用性。


19.为什么官方说 vue 没有完全遵循 MVVM 思想

#### 答案: 严格的 MVVM 要求 View 不能和 Model 直接通信,而 vue 提供了$refs 这个属性,让 Model 可以直接操作 View,违反了这一规定,所以 View 没有完全遵循 MVVM


20.vue 八种组件通信方式

#### 答案: 1.`props`/`$emit` > 父组件传给子组件:父组件 ':/v-bind',子组件通过`props`方法接收数据; > 子组件传给父组件:`$emit`方法传递,父组件'@'接受。 2.`$children`/`$parent` 指定已创建的实例之父实例,在两者之间建立父子关系,子实例可以用`this.$parent`访问父实例,子实例被推入父实例的`$children` 数组中。 `this.$parent`/`this.$children[0]` > 注意:节制的使用`$parent`和`$children`-它们的主要目的是作为访问组件的应急方法更推荐`props`和`events`实现父子组件通信。 3.`provide`/`inject` 父组件通过`provide`提供变量,然后子组件通过`inject`来注入变量,(官方不推荐在实际业务中使用,但是写组件库时很常见)。 4.`ref`/`refs` `ref`被用来给元素或者子组件注册引用信息,引用信息将会注册在父组件的`$refs`对象上。如果在普通的 DOM 元素上使用,引用指向 DOM 元素;如果用在子组件上,引用就会指向组件实例。 > 注意:`$refs`不是响应式的,因此不应该试图用它在模板中做数据绑定。 5.`eventBus` `eventBus`(又称为事件总线) 兄弟组件数据传递,这种情况下可以使用事件总线的方式。在 vue 中可以使用它来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向事件中心注册发送事件或接收事件,所以组件都可以通知其他组件。 > 当项目较大时,就容易造成难以维护的灾难。 1)初始化 ```javascript // event-bus.js import Vue from "vue"; export const EventBus = new Vue(); ``` 2)发送事件 ```javascript import { EventBus } from "./event-bus.js"; EventBus.$emit("addition", { num: this.num++, }); ``` 3)接收事件 ```javascript import { EventBus } from "./event-bus.js"; EventBus.$on("addition", (param) => { this.count = this.count + param.num; }); ``` 4)移除事件监听者 ```javascript import { EventBus } from "./event-bus.js"; EventBus.$off("addition", {}); ``` 6.`Vuex` 解决了`多个视图依赖同一状态`和`来自不同视图的行为需要变更同一状态`的问题。 7.`localStorage`/`sessionStorage` 8.`$attrs`和`$listeners`


21.vue 内置指令

#### 答案: `v-text`:更新元素的`textContent`。 `v-html`:更新元素的 innerHTML。容易导致 XSS 攻击,永不在用户提交内容上使用。 `v-show`:用于切换元素的`display`来进行显隐。 `v-if`/`v-else`/`v-else-if`:可以配合`template`使用;当和`v-for`使用的时候优先级比`v-if`高。 `v-for`:基于源数据多次渲染元素或模板块;优先级比`v-if`高,最好不用一起使用,尽量用计算属性去解决;注意增加唯一 key 值,不要使用 index 作为 key。 `v-on`:普通元素上用于监听 DOM 事件;缩写`@`;自定义元素组件上,监听子组件触发的自定义事件。 `v-bind`:缩写`:`,用于绑定属性;动态更新 html 元素上的属性。 `v-model`:在普通标签上,变成 value 和 input 的语法糖,并会处理拼音输入法问题;在组件上,也是处理 value 和 input 语法糖。 `v-slot`:缩写`#`;提供具名插槽,或需要接收 prop 的默认插槽。 `v-pre`:跳过这个元素和子元素的编译过程,以此来加快整个项目的编译速度。 `v-cloak`:这个指令保持在元素上直到关联实例结束编译--解决初始化慢,导致页面闪动的最佳实践。 `v-once`:定义它的元素和组件只渲染一次,包括元素组件的所有子节点,首次渲染后,不在随数据变化重新渲染,将被视为静态内容。


22.怎样理解 vue 单向数据流

#### 答案: 所有的prop都使得其父子prop之前都形成了一个单向下行的绑定:数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数据进行修改。这样会防止子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。


23.vue2.0 响应式原理

#### 答案: 数据劫持+观察者模式 对象内部通过 defineReactive 方法,使用`Object.defineProperty`将属性进行劫持(只会劫持已存在的属性),数组则是重写数组方法来实现。当页面使用对应属性时,每个属性都拥有自己的 dep 属性,存在它所依赖的 watcher(依赖收集),当属性变化后会通知自己对应的 watcher 去更新。 > 对象的新增或删除属性无法被 set 监听到,只有对象本身存在的属性修改才会被劫持。


24.vue 如何检测数组发生变化

#### 答案: 数组考虑性能原因没有用`defineProperty`对数组每一项进行拦截,而是对七对数组方法(push,shift,pop,splice,unshift,sort,reverse)进行重写。 所以 vue 修改数组的索引和长度是无法监控的,需要通过以上 7 种变异方法修改数组才会触发数组对应的 watcher 进行更新。


25.vue3.0 部分知识点

#### 答案: 1)响应式原理的改变,Proxy 取代 Object.defineProperty 2)组件选项声明方式 Composition api setup 3)模板语法变化 slot 具名插槽语法,自定义指令 v-moddel 升级 4)支持 Fragment(多根节点)和 Protal 组件


26.vue 父子组件生命钩子函数周期执行顺序

#### 答案: 加载渲染过程: > 父 beforeCreate->父 created->父 beforeMount->子 beforecreate->子 created->子 beforeMount->子 mounted->父 mounted。 子组件更新过程: > 父 beforeUpdate->子 beforeUpdate->子 updated->父 updated 父组件更新过程: > 父 beforeUpdate->父的 updated 销毁过程: > 父 beforeDestory->子 beforeDestory->子 destroyed->父 destroyed


27.虚拟 DOM 是什么,有什么优缺点

#### 答案: 由于浏览器操作 DOM 是很昂贵的。频繁操作 DOM 会产生性能问题。 > 本质是用一个原生的 JS 对象去描述一个 DOM 节点,是真实 DOM 的一层抽象。 优点: 1)保证性能下限:框架的虚拟 DOM 需要适配任何上层 api 可能产生的操作。不需要手动操作 DOM,还能保持不错的性能,保证性能下限。 2)无需手动操作 DOM。我们无需手动操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和数据双向绑定帮我们可预期更新视图,极大提高我们的开发效率。 3)跨平台:虚拟 DOM 本质上是 javascript 对象,而 DOM 与平台强相关,相比之下,虚拟 DOM 可以进行更方便的跨平台操作,例如服务器渲染,weex 开发等等。 缺点: 1)无法进行极致优化,虽然虚拟 DOM+合理的优化,足以应用大部分应用的性能需求,但在一些性能要求极高的应用中,虚拟 DOM 无法针对性的极致优化。 2)首次渲染大量 DOM 时,由于多了一层虚拟 DOM 的计算,会比 innerHTML 插入慢。


28.v-model 原理

#### 答案: v-model 只是语法糖而已 v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件。 > text 和 textarea 使用 value 和 input 事件 > checkbox 和 radio 使用 checked 和 change 事件 > select 将 value 作为 prop,并将 change 作为事件


29.v-for 为什么要加 key

#### 答案: 如果不使用 key,Vue 会使用最大限度减少动态元素并且尽可能尝试的修改/复用相同类型元素的算法。key 是 vue 中 vnode 的唯一标记,通过这个 key,我们 diff 操作更准确,更快速。 更准确:因为带 key 就不是就地复用了,在 sameNode 函数 a.key===b.key 对比中可以避免就地复用的情况,所以更加准确。 更快速:利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快。


30.vuex 页面刷新数据丢失怎么解决

#### 答案: 需要做 vuex 数据持久化,一般使用本地储存的方案来保存数据,可以自己设计储存方案,也可以使用第三方插件。 推荐使用 vuex-persist 插件,他就是为了 vuex 持久化而生的一个插件,不需要你手动存取 storage,而是将状态保存至 cookie 或者 localstorage 中。


31.vue.set方法原理

#### 答案: 修改vue视图不会发生变化的两种情况: - 在实例创建后,添加新的属性到实例上。(给响应式对象增加属性的时候) - 直接更改数组下标来更改数组的值。 原理: 因为响应式数据,我们给对象和数组本身增加了`__ob__`属性,代表的是Observer实例,当给对象新增不存在的属性,首先会把新的属性进行响应式跟踪,然后触发对象`__ob__`的dep收集到的watcher去更新,当修改数组索引时我们调用数组的splice去更新数组。


32.自定义指令

#### 答案: > 有些情况需要对DOM进行底层操作,这个时候会用到自定义指令。 > > 指令本质上是装饰器,是vue对HTML元素的扩展,给HTML元素增加自定义功能,vue编译DOM时,会找到指令对象,执行指令的相关方法。 五个生命周期:`bind`、`inserted`、`update`、`componentUpdated`、`unbind`。 1. `bind`:只调用一次,指令第一次绑定元素时调用。在这里可以进行一次性的初始化设置。 2. `inserted`:被绑定元素插入父节点时调用,(仅保证父节点存在,但不一定已被插入文档中)。 3. `update`:所在组件的VNode更新时调用,但是可能发生在其子Vnode更新之前,指令的值可能发生了变化,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新, 4. `componentUpdated`:指令所在的VNode及其子VNode全部更新后调用。 5. `unbind`:只调用一次,指令与元素解绑时调用。 原理:


33.vue 修饰符有哪些

#### 答案: 事件修饰符 - `.stop`:阻止事件继续传播 - `.prevent`:阻止标签默认行为 - `.capture`:使用事件捕获模式,即元素自身触发的事件现在此处处理,然后才交由内部元素处理。 - `.self`:只当在event.target是当前元素自身时触发处理函数 - `.once`:事件将只会触发一次 - `.passive`:告诉浏览器你不想阻止事件的默认行为 `v-model`修饰符 - `.lazy`:通过这个修饰符转变为change事件再同步 - `.number`:自动将用户输入的值变为数值类型 - `.trim`:自动过滤用户输入的首位空格 键盘事件修饰符 - `.enter` - `.tab` - `.delete` - `.esc` - `.space` - `.up` - `.down` - `.left` - `.right` 系统修饰键 - `.ctrl` - `.alt` - `.shift` - `.meta` 鼠标按钮修饰符 - `.left` - `.right` - `.middle`


34.vue 不能监听对数组的哪些操作,怎么解决

#### 答案: - 使用索引修改数组项时,解决:`Vue.set`、`vm.$set`、`splice` - 修改数组长度时 解决:`splice`


3.vue 内置指令

#### 答案: 严格的 MVVM 要求 View 不能和 Model 直接通信,而 vue 提供了$refs 这个属性,让 Model 可以直接操作 View,违反了这一规定,所以 View 没有完全遵循 MVVM