2W字!vue经典面试题,你值得收藏!
1.谈谈你对Vue的理解吧
* 双向绑定
* 虚拟DOM
2.谈谈什么是双向绑定?
* vue是MVVM模式,Model-View-ViewModel , Model 表示数据模型层。 view 表示视图层, ViewModel 是 View 和 Model 层的桥梁,数据绑定到 viewModel 层并自动渲染到页面中,视图变化通知 viewModel 层更新数据。
* 人话,数据层变化,视图层跟着变化。同理,视图层变化,数据层跟着变化。
vue双向绑定流程
1.new Vue()首先执行初始化,对data执行响应话处理,这个过程发生在Observe中。
2.同时对模板进行编译,找到其中动态绑定数据,从data中获取并初始化试图,这个过程发生在Compile中
3.同时定义一个更新函数和Watcher,将来对应数据变化时Watcher会调用更新函数。
4.由于data的某个key在一个视图中可能出现多次,所以每个key都需要一个管家Dep来管理多个Watcher
5.将来data中数据一旦发生变化,会首先找到对应Dep, 通知所有Watcher执行更新函数。
3.谈谈什么是虚拟DOM?
* 虚拟DOM(Virtual DOM)它是一层对真实DOM的抽象,以JavaScript对象(VNode节点)作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实树上。
* 在javascript对象中,虚拟DOM表现为一个Object对象。并且最少包含标签名(tag)、属性(attrs)、和子元素对象(children)三个属性。
* 虚拟DOM映射到真实DOM要经历VNode的create、diff、path等阶段。
* 创建虚拟DOM就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟DOM对象的节点真实DOM的属性--照应。
* 方便实现跨平台。
* 减少真实DOM操作,提高性能。
* 虚拟DOM包含了增删改查的功能。
4.谈谈vue中,key的原理
* v-for数组中,使用key给每个元素副本添加唯一标识。
* 修改数组中某个元素值时,避免重建整个列表,只需要修改一个DOM元素副本即可。
* 提高修改效率
5.vue2.x中如何监测数组变化?
使用`Object.defineProperty`数据劫持的方式,重写了数组的方法,Vue将`data`中的数组进行了原型链重写,指向了自己定义的数组原型对象。这样当调用数组`api`时,然后通知依赖更新。如果数组中包含着引用类型,会对数组中的引用类型再次递归遍历进行监控。这样就实现了监听数组变化。
6.说说nextTick的使用和原理?
* 在下次DOM更新循环结束之后执行延迟回调。
* vue`在更新`DOM`时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,试图需要等队列中所有数据变化完成之后,再统一进行更新。
7.vue2.x组件通信方式有哪些?
- props
- $emit/$on
- $children/$parent
- $attrs/$listeners
- ref
- $root
- eventbus
8.vue2使用的v指令有哪些?
v-show、v-if、v-bind、v-for、v-on、v-html、v-cloak、v-text、v-model、v-pre
9.vue2常用的修饰符有哪些?分别有什么应用场景?
* lazy 光标离开标签,才将值赋值给value
* trim 自动过滤用户输入的首空格字符,而中间的空格不会过滤
* number 自动将用户的输入值转为数值类型
* stop 阻止了事件冒泡,相当于调用了event.stopPropagation方法
* prevent 阻止了事件的默认行为,相当于调用了event.preventDefault方法
* self 只当在event.target是当前元素自身时触发处理函数
* once 事件只执行一次
* capture 用于事件捕获
* keyCode 监听特定键盘按下
10.vue2中v-model原理及自定义组件的使用
v-model可以看成value+input方法的语法糖。原生的v-model,会根据标签的不同生成不同的事件和属性。解析一个指令来。
** 自定义**
父组件写入v-model属性,子组件里面放prop和event
//父组件
<Child v-model="checked"></Child>
//子组件
export default {
name: 'MyComp',
props: ['checked'],
model: {
prop: 'checked',
event: 'change'
}
}
11.vue2中computed和watch区别
computed
* vue会将首次计算属性计算出的结果,缓存起来,反复使用!避免重复计算
* computed用于处理复杂的逻辑运算: 一个数据受一个或者多个数据影响。例如:
* 在computed中的,属性都有一个get和set方法,当数据变化时,调用set方法。
watched
用来处理一个属性改变影响多个数据。用于监控路由、input输入框值的特殊处理等。
监听数据:data、props、computed内的数据
watch支持异步。
监听函数有两个参数,第一个参数是最新的值,第二个参数是输入之前的值,顺序一定是新值,旧值
不支持缓存,监听的数据改变,直接会触发相应的操作。
12.说说你对slot的理解?slot使用场景有哪些?
slot艺名插槽,花名"占坑",slot在组件模板中占好位置,当使用该组件标签的时候,组件标签里面的内容就会自动填坑(替换组件模板中slot位置),作为承载分发内容的出口。
slot分为以下3种:
- 默认插槽,父组件在使用的时候,直接在子组件的标签内写入内容即可
- 具名插槽,子组件用name属性来表示插槽的名字,父组件在使用在默认插槽的基础上加上slot属性,值为子组件插槽name属性值
- 作用域插槽,子组件在作用域上绑定属性来将子组件的信息传给父组件使用,这些属性会被挂在父组件v-slot接受的对象上。父组件中在使用时通过v-slot:(简写: #) 获取子组件的信息,在内容中使用。
13.vue-router有几种模式,有什么区别?
有两种模式:hash模式和history模式
hash模式
* hash模式是一种把前端路由的路径用井号#拼接在真实URL后面的模式。当井号#后面的路径发生改变时,浏览器并不会重新发起请求,而是会触发hashchange事件
* 优点:浏览器兼容性较好,连IE8都支持。
* 缺点:路径在井号#的后面,比较丑。
history模式
history API是H5提供的新特性,主要有history.pushState()和history.replaceState(),允许开发者直接更改前端路由,即更改浏览器URL地址不会重新发起请求。
优点:路径比较正规,没有#
缺点:兼容性不如hash, 且需要服务端支持,否则一刷新页面就404了,以最常用的Nginx为例,只需要在配置的location/中增加一行:try_files $uri/index.html
14.Vue项目中如何解决跨域问题?
- JSONP
- CORS
- Proxy
CORS
CORS是一个系统,它由一系列传输的HTTP头组成,这些HTTP头决定浏览器是否阻止前端javascript代码获取跨域请求的响应。
Proxy
Proxy是代理,是一种特殊的网络服务,允许一个(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。一些网关、路由器等网络设备具备网络代理功能。一般认为代理服务有利于保障网络终端的隐私或安全,防止攻击。
方案一:
如果是通过vue-cli脚手架工具搭建项目,我们可以通过webpack为我们起一个本地服务器作为请求的代理对象。
在vue.config.js文件devServer添加proxy属性。
方案二:
通过配置nginx实现代理
15.怎么定义动态路由?怎么获取传过来的动态参数?
* 很多时候,我们需要将给定匹配模式的路由映射到同一个组件,这种情况就需要定义动态路由。
* 例如,我们可能有一个User组件,它应该对所有用户进行渲染,但用户ID不同。在Vue Router中,我们可以在路径中使用一个动态字段来实现,例如:{path:'/users/id', component: User},其中:id就是路径参数。
* 路径参数用冒号:表示。当一个路由被匹配时,它的params的值将在每个组件中以this.$route.params的形式暴露出来。
16.如果让你从零开始写一个vue路由,说说你的思路。
vue路由原理: 用户点击跳转链接内容切换,页面不刷新
1.定一个creatRouter函数,返回路由实例,实例内部做几件事情
* 保存用户传入的配置项
* 监听hash事件或者popstate事件
* 回调里面根据path匹配对应路由
2.将路由定义成Vue插件,即使用install方法,内部做两件事情:
* 实现两个全局组件:router-link和router-view,分别实现页面跳转和内容显示
* 定义两个全局变量: $route和$outer, 组件内可以访问当前路由和路由器实例。
17.vuex有几种属性,它们存在的意义分别是什么?
vuex是一种状态管理模式,存在的目的是共享可复用的组件状态。
有5种属性,分别是State、Getter、Mutation、Action、Module。
State
- State是Vuex的单一状态树。
Getter
- 有时候我们需要从store中的state中派生出一些状态,例如对列表进行过滤并计数。
- Getter类似于Vue的computed对象。是根据业务逻辑来处理State,使得生成业务所需的属性。
Mutations
- Mutations是唯一用来更改Vuex中状态的方法。
- Vuex中的mutations非常类似于事件:每个mutations都有一个字符串的事件类型(type)和一个回调函数(handler)。
Action
Action类似于mutation,不同在于:
- Action提交的是mutation, 而不是直接变更状态。
- Action可以包含任意操作。
Module
- 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿。为了解决以上问题,Vuex允许我们将store分割成模块(module)。每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块---从上至下进行同样方式的分割。
- Module是将Vuex模块化的对象,目的是更好的维护。
18.vue2与vue3区别
- 1.vue2使用选项式Api,是将data和methods包括后面的watch,computed等分开管理
- 2.vue3使用组合式Api,是将相关逻辑放到了一起(类似于原生js开发)。
- 3.vue3使用了setup语法糖,可以让变量方法不用再写return。
- 4.vue2data的数据都具有响应式,页面会随着data中的数据变化而变化,vue3中使用ref和reactive函数来使变量成响应是的数据。
- 5.vue2和vue3的生命周期有差异。
vue2 | vue3 | 描述 |
---|---|---|
beforeCreate | setup() | 组件实例创建前 |
created | setup() | 组件实例创建后 |
beforeMount | onBeforeMount | 组件挂载之前 |
mounted | onMounted | 组件挂载到实例上去 |
beforeUpdate | onBeforeUpdate | 组件数据发生变化,更新之前 |
updated | onUpdated | 组件数据更新之后 |
beforeDestory | onBeforeUnmount | 组件实例销毁之前 |
destoryed | onUnmounted | 组件实例销毁之后 |
- 6.vue3除了使用watch, 还引入了副作用监听函数watchEffect,相当于将watch的依赖源和回调函数合并,当任何你有用到的响应式依赖更新时,该回调函数变会重新执行。不同于watch的是watchEffect的回调函数会被立即执行,即({ immediate: true })
- 7.vue2和vue3组件通信
方式 | vue2 | vue3 |
---|---|---|
父传子 | props | props |
子传父 | $emit | emits |
父传子 | $attrs | attrs |
子传父 | $listeners | 无(合并到attrs方式上) |
父传子 | provide | provide |
子传父 | inject | inject |
子组件访问父组件 | $parent | 无 |
父组件访问子组件 | $ref | expose & ref |
兄弟传值 | EventBus | mitt |
- vue3移除了sync的写法,取而代之的是v-model: event的形式。
父组件使用
v-model:changePval="msg"
,子组件发送update:changePval
事件进行修改父组件的值。
8.vue2使用Es5是Object.defineProperty对数据劫持,结合发布订阅的方式实现。vue3使用Es6的new Proxy代理, 使用ref或者reactive将数据转化为响应式数据。
19.Vue3.0里为什么要用 Proxy API 替代 defineProperty API ?
Object.defineProperty
- 只能遍历对象属性进行劫持
- 检测不到对象属性的添加和删除
- 数组API方法无法监听到
- 需要对每个属性进行遍历监听,如果嵌套对象,需要深层监听,造成性能问题。
Proxy - 直接可以劫持到整个对象,并返回一个新对象,我们可以只操作新的对象达到响应式目的。
- 可以直接监听到数组的变化
- 不兼容IE。
20.Vue3.0 性能提升主要是通过哪几方面体现的?
编译阶段
- diff算法优化
vue3在diff算法中想比vue2增加静态标记,其作用是为了发生变化的地方添加一个flag标记,下次发生变化的时候直接找该地方进行比较。
- 静态提升
vue3中对不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用
- 事件监听缓存
默认情况下绑定事件行为会被视为动态绑定,所以每次都会去追踪它的变化。开启缓存后,没有了静态标记。也就是说下次diff算法的时候直接使用。
- SSR优化
当静态内容打到一定量级时候,会用createStaticVNode方法在客户端去生成一个static node, 这些静态node,会被直接innerHtml,就不需要创建对象,然后根据对象渲染。
源码体积
- 想比vue2,vue3整体体积变小了,除了移出一些不常用的API,在重要的是Tree shanking
- 任何一个函数,如ref、reactived、computed等,仅仅在用到的时候才打包,没用到的模块都会被摇掉,打包的整体体积变小了。
响应式系统
- vue2中采用defineProperty来劫持整个对象,然后进行深度遍历所有属性,给每个属性添加getter和setter,实现响应式
- vue3采用proxy重写了响应式系统,因为proxy可以对整个对象进行监听,所以不需要深度遍历。