vue.js面试题(套题)
| 选择题 | 填空题 | 问答题 | 编程题 | 试题难度 | 
|---|---|---|---|---|
| 0 | 0 | 54 | 0 | 比较难 | 
问答题
- 1、说说你对 SPA 单页面的理解,它的优缺点分别是什么?
- SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。 - 优点: - 用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;
- 基于上面一点,SPA 相对对服务器压力小;
- 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;
 - 缺点: - 初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载;
- 前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;
- SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。
 
- 2、v-if 和v-show有何不同 / 通常什么场景下使用v-if,是么时候使用v-show?
- v-if是正的dom渲染,v-show是通过display:none来做隐藏和显示的 - v-if是在渲染开始来决定要不要渲染的元素,后期基本上不做变化的 - v-show是在渲染后,用户可能会频繁做状态改变的情况 - 以上是我的理解 
- 3、Class 与 Style 如何动态绑定?
- Class 可以通过对象语法和数组语法进行动态绑定: - 对象语法:
 - <div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div> data: { isActive: true, hasError: false } 复制代码- 数组语法:
 - <div v-bind:class="[isActive ? activeClass : '', errorClass]"></div> data: { activeClass: 'active', errorClass: 'text-danger' } 复制代码- Style 也可以通过对象语法和数组语法进行动态绑定: - 对象语法:
 - <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> data: { activeColor: 'red', fontSize: 30 } 复制代码- 数组语法:
 - <div v-bind:style="[styleColor, styleSize]"></div> data: { styleColor: { color: 'red' }, styleSize:{ fontSize:'23px' } }
- 4、怎样理解 Vue 的单向数据流?
- 所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。 - 额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。 - 有两种常见的试图改变一个 prop 的情形 : - 这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。 在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值:
 - props: ['initialCounter'], data: function () { return { counter: this.initialCounter } } 复制代码- 这个 prop 以一种原始的值传入且需要进行转换。 在这种情况下,最好使用这个 prop 的值来定义一个计算属性
 - props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
- 5、计算属性的理解以及它的应用场景?/ watch和computed的区别?
- 我的理解是这样的,计算属性就是用于计算,并且将结果返回,如果计算属性依赖的属性有变化就会重新计算,否则使用缓存的结果。watch是监听响应式数据的变化,从而执行某一些操作. - 计算属性是可以绑定到模板的,而watch不可以。从这里就看出,计算属性需要有处理结果,watch专注数据变化的业务逻辑处理。 
- 6、直接给一个数组项赋值,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) 
- 当你利用索引直接设置一个数组项时,例如:
- 7、谈谈你对 Vue 生命周期的理解?
- Vue生命周期是从Vue实例创建到销毁的过程。这个过程提供了8个生命周期钩子函数。 - (1)beforeCreate 创建前 - 组件实例被创建,this指向了当前实例,但组件属性还没有创建,不能使用data,computed,methods - 可以在这个阶段初始化非响应式变量 - (2)created 创建后 - 组件实例已经完全创建,属性可以正常访问了,但dom还没有挂载,所以$el,$ref 还不可用 。 - 在这几个阶段可以进行接口请求数据。 - (3)beforeMount 挂载前 - render 函数被调用,$el有值了,但数据还没有挂载到页面,模板字符串还没有被替换 - (4)mounted 挂载后 - dom渲染完成,可以进行dom操作了,$ref属性可以访问了 - (5)beforeUpdate 更新前 - 响应式数据有更新时调用 - (6)update 更新后 - 虚拟dom重新渲染和打补丁之后调用,dom已经渲染完成 - (7)beforeDestory 销毁前 - 组件销毁前调用,通常可以在这个阶段关闭计时器 - (8)destoryed 销毁后 - 组件销毁后调用 - 如果有使用keep-alive来缓存组件,那么组件在失活时会调用deactivated函数,激活会调用activated函数 
- 8、Vue 的父组件和子组件生命周期钩子函数执行顺序?
- Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分: - 加载渲染过程
- 父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
- 子组件更新过程
- 父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
- 父组件更新过程
- 父 beforeUpdate -> 父 updated
- 销毁过程
- 父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
 
- 9、在哪个生命周期内调用异步请求?
- 可以在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。但是本人推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点: - 能更快获取到服务端数据,减少页面 loading 时间;
- ssr 不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性;
 
- 10、在什么阶段才能访问操作DOM?
- 在钩子函数 mounted 被调用前,Vue 已经将编译好的模板挂载到页面上,所以在 mounted 中可以访问操作 DOM。vue 具体的生命周期示意图可以参见如下,理解了整个生命周期各个阶段的操作,关于生命周期相关的面试题就难不倒你了。 
- 11、父组件可以监听到子组件的生命周期吗?
- 比如有父组件 Parent 和子组件 Child,如果父组件监听到子组件挂载 mounted 就做一些逻辑处理,可以通过以下写法实现: - // Parent.vue <Child @mounted="doSomething"/> // Child.vue mounted() { this.$emit("mounted"); } 复制代码- 以上需要手动通过 $emit 触发父组件的事件,更简单的方式可以在父组件引用子组件时通过 @hook 来监听即可,如下所示: - // Parent.vue <Child @hook:mounted="doSomething" ></Child> doSomething() { console.log('父组件监听到 mounted 钩子函数 ...'); }, // Child.vue mounted(){ console.log('子组件触发 mounted 钩子函数 ...'); }, // 以上输出顺序为: // 子组件触发 mounted 钩子函数 ... // 父组件监听到 mounted 钩子函数 ... 复制代码- 当然 @hook 方法不仅仅是可以监听 mounted,其它的生命周期事件,例如:created,updated 等都可以监听。 
- 12、谈谈你对 keep-alive 的了解?/ keep-alive有什么作用
- 用来缓存组件,缓存的组件实例不会被销毁,所以存在两种状态激活和不活跃状态,这两个状态可以通过active和deactivate两个钩子函数来监听。需要缓存的组件可以通过includes属性来指定,根据组件名称来做缓存。 - 当然缓存也存在问题,如果缓存的组件多了会导致系统运行变慢,不需要缓存的组件从includes上移除掉,来释放资源。 
- 13、组件中 data 为什么是一个函数?
- 组件是复用的,如果多个组件引用的数据是同一个对象,那么就会相互干扰。为此将data定义一个函数,通过函数返回组件需要的数据,确保每个组件的数据都是独一无二的,不是同一个引用,这样就互不干扰 
- 14、v-model 的原理?
- 我们在 vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件: - text 和 textarea 元素使用 value 属性和 input 事件;
- checkbox 和 radio 使用 checked 属性和 change 事件;
- select 字段将 value 作为 prop 并将 change 作为事件。
 - 以 input 表单元素为例: - <input v-model='something'> 相当于 <input v-bind:value="something" v-on:input="something = $event.target.value">- 如果在自定义组件中,v-model 默认会利用名为 value 的 prop 和名为 input 的事件,如下所示: - 父组件: <ModelChild v-model="message"></ModelChild> 子组件: <div>{{value}}</div> props:{ value: String }, methods: { test1(){ this.$emit('input', '小红') }, },
- 15、vue组件通信方式有哪些 / vue组件之间传值的方式 / 页面之间传值的方式
- 父子组件之间的通信的单向流的,通过props传给子组件,子组件是不能直接修改props的内容。如果子组件需要传数据到父组件就通过$emit定义事件,通过事件参数的方式传递 - 组件之间传递数据可以vuex或者定义的全局变量来实现。当然也可以用本地存储但在项目开发我们很少这样做,毕竟本地存储的数据大小有限。 
- 16、vuex / 通常什么情况下会使用到状态管理?/ 你使用过 Vuex 吗
- vuex是状态管理插件,组件之间通信时使用,vuex是具有响应式的全局共享数据的作用。 - 有五大核心属性 分别是 state、getters、mutations、actions、modules 。 
- 17、使用过 Vue SSR 吗?说说 SSR?
- Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序。 - 即:SSR大致的意思就是vue在客户端将标签渲染成的整个 html 片段的工作在服务端完成,服务端形成的html 片段直接返回给客户端这个过程就叫做服务端渲染。 - 服务端渲染 SSR 的优缺点如下: - (1)服务端渲染的优点: - 更好的 SEO: 因为 SPA 页面的内容是通过 Ajax 获取,而搜索引擎爬取工具并不会等待 Ajax 异步完成后再抓取页面内容,所以在 SPA 中是抓取不到页面通过 Ajax 获取到的内容;而 SSR 是直接由服务端返回已经渲染好的页面(数据已经包含在页面中),所以搜索引擎爬取工具可以抓取渲染好的页面;
- 更快的内容到达时间(首屏加载更快): SPA 会等待所有 Vue 编译后的 js 文件都下载完成后,才开始进行页面的渲染,文件下载等需要一定的时间等,所以首屏渲染需要一定的时间;SSR 直接由服务端渲染好页面直接返回显示,无需等待下载 js 文件及再去渲染等,所以 SSR 有更快的内容到达时间;
 - (2) 服务端渲染的缺点: - 更多的开发条件限制: 例如服务端渲染只支持 beforCreate 和 created 两个钩子函数,这会导致一些外部扩展库需要特殊处理,才能在服务端渲染应用程序中运行;并且与可以部署在任何静态文件服务器上的完全静态单页面应用程序 SPA 不同,服务端渲染应用程序,需要处于 Node.js server 运行环境;
- 更多的服务器负载:在 Node.js 中渲染完整的应用程序,显然会比仅仅提供静态文件的 server 更加大量占用CPU 资源 (CPU-intensive - CPU 密集),因此如果你预料在高流量环境 ( high traffic ) 下使用,请准备相应的服务器负载,并明智地采用缓存策略。
 
- 18、路由的原理 / vue的路由模式?/ hash 和 history 路由模式区别?
- 路由模式常见的的有两种,history模式和hash模式。 - history模式实现的原理是通过HTML5提供的api,如pushState,replaceState。改变网址但不请求服务器来渲染不同的组件 - hash模式实现的原理是监听window的hashchange事件来渲染不同的组件 - 项目上线后,history模式刷新会出现404错误,这个需要后台服务器配置404重定向到index.html页面来解决 
- 19、什么是 MVVM?
- Model–View–ViewModel (MVVM) 是一个软件架构设计模式,由微软 WPF 和 Silverlight 的架构师 Ken Cooper 和 Ted Peters 开发,是一种简化用户界面的事件驱动编程方式。由 John Gossman(同样也是 WPF 和 Silverlight 的架构师)于2005年在他的博客上发表 - MVVM 源自于经典的 Model–View–Controller(MVC)模式 ,MVVM 的出现促进了前端开发与后端业务逻辑的分离,极大地提高了前端开发效率,MVVM 的核心是 ViewModel 层,它就像是一个中转站(value converter),负责转换 Model 中的数据对象来让数据变得更容易管理和使用,该层向上与视图层进行双向数据绑定,向下与 Model 层通过接口请求进行数据交互,起呈上启下作用。如下图所示: - (1)View 层 - View 是视图层,也就是用户界面。前端主要由 HTML 和 CSS 来构建 。 - (2)Model 层 - Model 是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,对于前端来说就是后端提供的 api 接口。 - (3)ViewModel 层 - ViewModel 是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的 Model 数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。需要注意的是 ViewModel 所封装出来的数据模型包括视图的状态和行为两部分,而 Model 层的数据模型是只包含状态的,比如页面的这一块展示什么,而页面加载进来时发生什么,点击这一块发生什么,这一块滚动时发生什么这些都属于视图行为(交互),视图状态和行为都封装在了 ViewModel 里。这样的封装使得 ViewModel 可以完整地去描述 View 层。 - MVVM 框架实现了双向绑定,这样 ViewModel 的内容会实时展现在 View 层,前端开发者再也不必低效又麻烦地通过操纵 DOM 去更新视图,MVVM 框架已经把最脏最累的一块做好了,我们开发者只需要处理和维护 ViewModel,更新数据视图就会自动得到相应更新。这样 View 层展现的不是 Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与 Model 层交互,这就完全解耦了 View 层和 Model 层,这个解耦是至关重要的,它是前后端分离方案实施的重要一环。 - 我们以下通过一个 Vue 实例来说明 MVVM 的具体实现,有 Vue 开发经验的同学应该一目了然: - (1)View 层 - <div id="app"> <p>{{message}}</p> <button v-on:click="showMessage()">Click me</button> </div>- (2)ViewModel 层 - var app = new Vue({ el: '#app', data: { // 用于描述视图状态 message: 'Hello Vue!', }, methods: { // 用于描述视图行为 showMessage(){ let vm = this; alert(vm.message); } }, created(){ let vm = this; // Ajax 获取 Model 层的数据 ajax({ url: '/your/server/data/api', success(res){ vm.message = res; } }); } })- (3) Model 层 - { "url": "/your/server/data/api", "res": { "success": true, "name": "IoveC", "domain": "www.cnblogs.com" } }
- 20、v-model的原理 / 你是怎么理解v-model的 / 自定义v-model
- v-model是双向绑定,但表单的数据改变了,通过改变事件监听内容改变,然后更新响应式数据。但数据改变了通过vue的响应式系统来更新界面上的数据。 - 所以我们在自定义v-model时,需要定义prop和event,prop定义响应式数据,用于更新界面数据,event用来定义界面内容改变事件,更新v-model绑定的内容。 - 参考代码如下: - Vue.component('base-checkbox', { model: { prop: 'checked', event: 'change' }, props: { checked: Boolean }, template: ` <input type="checkbox" v-bind:checked="checked" v-on:change="$emit('change', $event.target.checked)" > ` })- 组件使用 - <base-checkbox v-model="lovingVue"></base-checkbox> 
- 21、Vue 框架怎么实现对象和数组的监听?
- 如果被问到 Vue 怎么实现数据双向绑定,大家肯定都会回答 通过 Object.defineProperty() 对数据进行劫持,但是 Object.defineProperty() 只能对属性进行数据劫持,不能对整个对象进行劫持,同理无法对数组进行劫持,但是我们在使用 Vue 框架中都知道,Vue 能检测到对象和数组(部分方法的操作)的变化,那它是怎么实现的呢?我们查看相关代码如下: - /** * Observe a list of Array items. */ observeArray (items: Array<any>) { for (let i = 0, l = items.length; i < l; i++) { observe(items[i]) // observe 功能为监测数据的变化 } } /** * 对属性进行递归遍历 */ let childOb = !shallow && observe(val) // observe 功能为监测数据的变化- 通过以上 Vue 源码部分查看,我们就能知道 Vue 框架是通过遍历数组 和递归遍历对象,从而达到利用 Object.defineProperty() 也能对对象和数组(部分方法的操作)进行监听。 
- 22、Proxy 与 Object.defineProperty 优劣对比 / defineProperty 和 proxy 的区别?
- vue2是基于Object.defineProperty来做的响应式系统,vue3是基于Proxy来做的响应式系统。 - defineProperty 不能监听到数组下标变化和对象新增属性,Proxy 可以;defineProperty 是劫持对象属性,Proxy 是代理整个对象,所以defineProperty需要遍历对象属性来做监听,Proxy则不用,性能提升很大,且首次渲染更快,这也就是为什么vue3采用Proxy的原因。 
- 23、Vue 怎么用 vm.$set() 解决对象新增属性不能响应的问题 ?
- 受现代 JavaScript 的限制 ,Vue 无法检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化,所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的。但是 Vue 提供了 - Vue.set (object, propertyName, value) / vm.$set (object, propertyName, value)来实现为对象添加响应式属性,那框架本身是如何实现的呢?- 我们查看对应的 Vue 源码: - vue/src/core/instance/index.js- export function set (target: Array<any> | Object, key: any, val: any): any { // target 为数组 if (Array.isArray(target) && isValidArrayIndex(key)) { // 修改数组的长度, 避免索引>数组长度导致splcie()执行有误 target.length = Math.max(target.length, key) // 利用数组的splice变异方法触发响应式 target.splice(key, 1, val) return val } // key 已经存在,直接修改属性值 if (key in target && !(key in Object.prototype)) { target[key] = val return val } const ob = (target: any).__ob__ // target 本身就不是响应式数据, 直接赋值 if (!ob) { target[key] = val return val } // 对属性进行响应式处理 defineReactive(ob.value, key, val) ob.dep.notify() return val }- 我们阅读以上源码可知,vm.$set 的实现原理是: - 如果目标是数组,直接使用数组的 splice 方法触发相应式;
- 如果目标是对象,会先判读属性是否存在、对象是否是响应式,最终如果要对属性进行响应式处理,则是通过调用 defineReactive 方法进行响应式处理( defineReactive 方法就是 Vue 在初始化对象时,给对象属性采用 Object.defineProperty 动态添加 getter 和 setter 的功能所调用的方法)
 
- 24、虚拟 DOM 的优缺点?
- 优点: - 保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;
- 无需手动操作 DOM: 我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;
- 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。
 - 缺点: - 无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。
 
- 25、虚拟 DOM 实现原理?
- 虚拟 DOM 的实现原理主要包括以下 3 部分: - 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
- diff 算法 — 比较两棵虚拟 DOM 树的差异;
- pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
 - 如果对以上 3 个部分还不是很了解的同学,可以查看本文作者写的另一篇详解虚拟 DOM 的文章《深入剖析:Vue核心之虚拟DOM》 
- 26、Vue 中的 key 有什么作用?
- 我的理解是给Vnode(虚拟节点)定义一个唯一的标志,这样在差异化比较的时候更加准确、快速,提升渲染的速度。 - 如果列表只适渲染,不用操作key可以不用,如果需要对列表拍些、删除等操作就很有必要带上key。 
- 27、你有对 Vue 项目进行哪些优化?
- 如果没有对 Vue 项目没有进行过优化总结的同学,可以参考本文作者的另一篇文章《 Vue 项目性能优化 — 实践指南 》,文章主要介绍从 3 个大方面,22 个小方面详细讲解如何进行 Vue 项目的优化。 - (1)代码层面的优化 - v-if 和 v-show 区分使用场景
- computed 和 watch 区分使用场景
- v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
- 长列表性能优化
- 事件的销毁
- 图片资源懒加载
- 路由懒加载
- 第三方插件的按需引入
- 优化无限列表性能
- 服务端渲染 SSR or 预渲染
 - (2)Webpack 层面的优化 - Webpack 对图片进行压缩
- 减少 ES6 转为 ES5 的冗余代码
- 提取公共代码
- 模板预编译
- 提取组件的 CSS
- 优化 SourceMap
- 构建结果输出分析
- Vue 项目的编译优化
 - (3)基础的 Web 技术的优化 - 开启 gzip 压缩
- 浏览器缓存
- CDN 的使用
- 使用 Chrome Performance 查找性能瓶颈
 
- 28、对于即将到来的 vue3.0 特性你有什么了解的吗?
- Vue 3.0 正走在发布的路上,Vue 3.0 的目标是让 Vue 核心变得更小、更快、更强大,因此 Vue 3.0 增加以下这些新特性: - (1)监测机制的改变 - 3.0 将带来基于代理 Proxy 的 observer 实现,提供全语言覆盖的反应性跟踪。这消除了 Vue 2 当中基于 Object.defineProperty 的实现所存在的很多限制: - 只能监测属性,不能监测对象
- 检测属性的添加和删除;
- 检测数组索引和长度的变更;
- 支持 Map、Set、WeakMap 和 WeakSet。
 - 新的 observer 还提供了以下特性: - 用于创建 observable 的公开 API。这为中小规模场景提供了简单轻量级的跨组件状态管理解决方案。
- 默认采用惰性观察。在 2.x 中,不管反应式数据有多大,都会在启动时被观察到。如果你的数据集很大,这可能会在应用启动时带来明显的开销。在 3.x 中,只观察用于渲染应用程序最初可见部分的数据。
- 更精确的变更通知。在 2.x 中,通过 Vue.set 强制添加新属性将导致依赖于该对象的 watcher 收到变更通知。在 3.x 中,只有依赖于特定属性的 watcher 才会收到通知。
- 不可变的 observable:我们可以创建值的“不可变”版本(即使是嵌套属性),除非系统在内部暂时将其“解禁”。这个机制可用于冻结 prop 传递或 Vuex 状态树以外的变化。
- 更好的调试功能:我们可以使用新的 renderTracked 和 renderTriggered 钩子精确地跟踪组件在什么时候以及为什么重新渲染。
 - (2)模板 - 模板方面没有大的变更,只改了作用域插槽,2.x 的机制导致作用域插槽变了,父组件会重新渲染,而 3.0 把作用域插槽改成了函数的方式,这样只会影响子组件的重新渲染,提升了渲染的性能。 - 同时,对于 render 函数的方面,vue3.0 也会进行一系列更改来方便习惯直接使用 api 来生成 vdom 。 - (3)对象式的组件声明方式 - vue2.x 中的组件是通过声明的方式传入一系列 option,和 TypeScript 的结合需要通过一些装饰器的方式来做,虽然能实现功能,但是比较麻烦。3.0 修改了组件的声明方式,改成了类式的写法,这样使得和 TypeScript 的结合变得很容易。 - 此外,vue 的源码也改用了 TypeScript 来写。其实当代码的功能复杂之后,必须有一个静态类型系统来做一些辅助管理。现在 vue3.0 也全面改用 TypeScript 来重写了,更是使得对外暴露的 api 更容易结合 TypeScript。静态类型系统对于复杂代码的维护确实很有必要。 - (4)其它方面的更改 - vue3.0 的改变是全面的,上面只涉及到主要的 3 个方面,还有一些其他的更改: - 支持自定义渲染器,从而使得 weex 可以通过自定义渲染器的方式来扩展,而不是直接 fork 源码来改的方式。
- 支持 Fragment(多个根节点)和 Protal(在 dom 其他部分渲染组建内容)组件,针对一些特殊的场景做了处理。
- 基于 treeshaking 优化,提供了更多的内置功能。
 
- 30、vue-router 有哪几种导航钩子?
- 全局导航钩子 - router.beforeEach(to, from, next), - router.beforeResolve(to, from, next), - router.afterEach(to, from ,next) - 组件内钩子 - beforeRouteEnter, - beforeRouteUpdate, - beforeRouteLeave - 单独路由独享组件 - beforeEnter 
- 32、route和router的区别
- route是"路由信息对象",包括path,params,hash,query,fullPath,matched,name等路由信息参数。 - router是“路由实例”对象包括了路由的跳转方法,钩子函数等。 
- 35、vue常用的修饰符?
- 答:.prevent: 提交事件不再重载页面;.stop: 阻止单击事件冒泡;.self: 当事件发生在该元素本身而不是子元素的时候会触发;.capture: 事件侦听,事件发生的时候会调用 
- 37、怎么定义 vue-router 的动态路由? 怎么获取传过来的值
- 采用命名参数,:name这样的格式,设置props:true,这样就可以,映射到组件props属性上。 
- 39、nextTick 是做什么的 / 谈谈你对nextTick的理解
- 这个在项目也是有用过的,nextTick就是在下次DOM更新后来调用一个回调函数。我的项目场景是当我单击分页加载数据后,需要动画滑动到顶部,由于每页数据数据不一样,那么滚动条距离到顶部也不一样,就需要等待表格数据渲染完成后在执行滚动到顶部的操作,那个动作就需要在nextTick的回调函数来执行。 
- 40、对比 jQuery ,Vue 有什么不同
- jQuery 专注视图层,通过操作 DOM 去实现页面的一些逻辑渲染;Vue 专注于数据层,通过数据的双向绑定,最终表现在 DOM 层面,减少了 DOM 操作。 - Vue 使用了组件化思想,使得项目子集职责清晰,提高了开发效率,方便重复利用,便于协同开发。 
- 42、Vue minix(混入)的用法
- vue中混入是是实现类继承的重要方式。通过混入重用某一个功能变得更加容易,灵活。可以通过混入来实现权限的控制这些功能。具体实用可参考官方文档。 
- 43、关于 Vue.use() 的理解
- Vue.use() 是Vue的一个全局注册方法,主要用来注册插件,默认第一个参数是它接受的参数类型必须是Function或者是Object,如果是个对象,必须提供install方法,install方法默认第一个参数为 Vue,其后的参数为注册时传入的arguments。如果是 Function 那么这个函数就被当做 install 方法。同一个插件 Vue.use 会自动阻止多次注册。除了在注册插件中使用 Vue.use 外,我们还可以在 directive注册、filters注册、components注册等条件下使用。 - 有的时候我们会遇到某些时候引入插件是并没有使用 Vue.use ,比如使用 axios 的时候,原因是 axios 没有 install 方法,所以也就不需要使用 Vue.use 来全局注册。 
- 45、路由权限控制是怎么实现的?
- 采用动态路由的方式实现,根据后台接口返回的用户权限信息,使用 router.addRoutes函数添加有权限的路由,然后在添加404,500这些路由信息。 - 参考地址:Vue实现两种路由权限控制方式 
- 46、权限按钮
- 使用自定义全局指令实现,在钩子函数inserted实现按钮的渲染逻辑,钩子函数传两个参数el和binding,el是绑定指令的元素对象,binding是绑定的对象信息,通过binding.value取得指令的内容与后台返回的的权限列表进行匹配,如果不匹配使用el.remove()移除元素。 
- 47、Vue2和Vue3的区别 / 为什么用vue3不用vue2 / 对vue3的了解
- 之前我们的项目是用vue2开发的,现在用的是vue3。我个人感受是vue3的响应式采用代理方式更方便,就不用为对数组或对象操作不会响应式的问题,而vue2需要考虑响应式的操作方法,比如采用索引的方式给数组赋值是不会响应式的,需要采用vue提供的方法set或是splice这样的函数。 - 其二,vue2编写代码采用的是选项式,我个感觉也挺不错的,vue3采用组合式的方式开发,代码灵活,刚开始不习惯,但后面习惯了也觉得挺好。 - 其三,vue3在开发中要手动引入需要的函数,如:ref,reactive,computed,而vue2都是写在对应的选项里。 - vue3通常结合ts来开发项目更具有可维护性和阅读性。 - 以上就是我在开发对比中最直接的感受。 
- 48、路由守卫有使用过吗
- 有用过的,在我们的项目里,对于页面权限的处理时放在全局前置守卫处理的,有权限的用户可以进入页面,没有权限的不能。还有就是进度加载,在全局前置守卫启动进度,在全局后置守卫结束进度。 - 【注意】等面试官细问再来回答是怎么做的 - 后台管理系统除了登录页面,其它页面都是需要用户登录才能够访问,在全局前置守卫需要判断用户登录状态,没有登录return false不允许进入页面,有登录return true,允许进入页面 
- 49、路由传参的方式有哪些?路由传参怎样让参数不显示在url上
- 路由传参大体上有2种,一种是params,另一种是query - query就是查询参数,在页面中通过$route.query来获取。 - params路径参数传递,参数信息会显示在url上,通过$route.params获取;如果不是路径参数传递,是不会显示在url上的,但也可以通过$route.params获取到数据,只是刷新后会丢失数据,但从4.1.4版本开始不再支持这种方式传递了! 
- 51、vue双向绑定的原理
- 我理解是这样的,双向绑定得益于vue.js的响应式系统,vue在实例化时,会对响应式的数据添加getter和setter来劫持读写操作的行为,当然vue3是采用代理对象实现,在结合发布-订阅模式,只要数据变动时发布消息给订阅者,触发响应的监听回调,从而对依赖的数据实时更新。 
- 52、有使用过插槽吗,通常用来干什么 / slot插槽
- 在使用element-ui组件时,会经常用到组件的一些插槽,比如表格自定义列。插槽就是用来定义组件内部的模板内容,通常有默认插槽、具名插槽、作用域插槽。 
- 53、vue项目首屏加载过慢如何解决
- 这种情况我首先会打开网络,查看网络请求的数量,文件请求的大小,网络请求的用时,针对网络请求的问题,我通常会这样做 - 路由懒加载,打包工具根据路由分割不同的代码块,访问的时候才去加载
- 对请求的文件进行压缩,减少体积
- 减少网络请求,和后台商量,将需要请求的数据合并到一个请求里完成
- 与渲染相关的文件先请求,对于后操作的文件可以等页面渲染出来后在请求
- 将图片视频等资源放到cdn服务
 
 
                            