1. 对于MVVM的理解
MVVM是model-view-viewModel的缩写
model代表的是数据模型,可以定义数据的修改和操作业务逻辑
view代表的是ui组件,可以将数据模型转化ui展现出来
viewModel可以操作数据模型,处理用户交互等。它是将model和view连接起来的一个对象,view和model本身是没有任何联系的。但model和viewmodel之间交互式双向的,所以view的改变会反应到model上,而model的改变也会反应到view上
2. vue的生命周期
定义:vue的生命周期指的是组件从创建到销毁的一系列过程。
beforeCreat(创建前) 数据观测还未开始 初始化还未开始
created(创建后) 已完成数据观测,初始化完成。但$el 属性还未显示出来
beforeMount(载入前) 相关的render函数首次被调用,实例已完成以下配置:编译模板,把data里面的数据和模板生成html。但此时还未挂载到页面上
mounted(载入后) 编译好的html替换el属性指向DOM对象,完成模板中的html渲染
beforeUpdate(更新前) 在数据更新前调用
updated(更新后) 在数据更新后调用
beforeDestroy(销毁前) 实例销毁前调用
destoryed(销毁后) 实例销毁后调用 所有实例销毁,所有事件监听器移除
3. vue的生命周期作用
vue生命周期中有许多事件钩子,可以利用这些事件钩子更好的操作业务逻辑
4. 第一次加载页面会触发哪些事件钩子
beforeCreate created beforeMount mounted
5. DOM渲染在哪个周期完成
mounted
6. vue实现双向数据绑定原理
vue数据的双向绑定是通过数据劫持结合发布者-订阅者模式来实现。通过Object.defineProperty重写data的get和set函数来实现
-
实现过程
- 首先对数据劫持我们需要设置一个监听器Obeserve来监听所有属性
- 如果属性上发生变化了,就需要告诉订阅者watcher是否需要更新
- 因为订阅者有很多个,所以需要一个消息订阅器(Dep)来专门收集这些订阅者,然后在监听器(Obeserve)和订阅者(watcher)之间进行统一管理
- 我们还需要一个指令解析器(compile),对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者(watcher),并替换模板数据绑定相应的函数,此时当订阅者watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新试图
7. Object.defineProperty()
Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。有三个参数:
- obj:要定义属性的对象
- prop:要定义或修改的属性名称
- descriptor:将被定义或修改的属性描述符
在对象中添加一个属性与数据描述符实例:
let o = {}
Object.defineProperty(o,'a'{
vaule:37,
writable:true, //value能被赋值运算符改变
configurable:true, //属性描述符能够改变,该属性能从对应的对象上删除
enumerable:true //属性能够出现在对象枚举属性中
})
在对象中添加一个属性与存取描述符实例:
var o;
Object.defineProperty(o,'b'{
get:function(){
return o;
},
set:function(newVal){
o = newVal
},
configurable:true, //属性描述符能够改变,该属性能从对应的对象上删除
enumerable:true //属性能够出现在对象枚举属性中
})
o.b = 38
8. Object.defineProperty()来进行数据劫持有什么缺点
有一些对属性的操作,使用这种无法拦截。比如通过下标方式修改数组数据,vue内部通过重写函数解决了这个问题。在vue3.0中已经不使用这种方法了,而是通过proxy对对象进行代理,重而实现数据劫持。
9. 什么是Virtual DOM?为什么Virtual DOM比原生DOM快?
我对Virtual DOM的理解是:
- 首先对我们将要插入到文档中的DOM树进行结构分析,然后使用js对象将其表示出来
- 当页面的状态发生改变,对页面的DOM结构进行调整的时候,首先根据变更的状态,重新构建起一棵对象树
- 将这棵新的对象树和旧的对象树进行比较,记录下两棵树的差异。最后将记录有差异的地方应用到真正的DOM树中,这样视图就更新了。
我认为Virtual DOM这种方法对于我们需要大量操作DOM的时候,能够很好的提高操作效率。通过在操作前确定需要做最小的修改,所以比原生DOM快。
10. 如何比较两个DOM树的差异
两个树的完全diff算法的时间复杂度为0(n^3),但是在前端中,我们很少跨层级的移动元素,所以只需要比较同一层级的元素,这样就可以将算法的时间复杂度降低为0(n).
使用diff算法首先会对新旧两棵树进行一个深度优先遍历,这样每个节点都会有一个序号。在深度遍历的时候,每遍历到一个节点,就将这个节点和新的树中的节点进行比较。如果有差异,则将这个差异记录到一个对象中
在对列表元素进行对比的时候,由于TagName是重复的,所以不能使用这个来比较。我们需要给每个子节点加上一个key,列表对比的时候使用key来进行比较。这样我们才能复用老的DOM树的节点
11. vue组件参数传递方式
-
父子组件间通信
- 子组件通过props来接收父组件的数据。父组件在子组件上注册监听事件,子组件通过emit来触发事件向父组件发送数据
- 通过ref给子组件设置一个名字。父组件通过
this.$refs子组件名来获得子组件数据,子组件通过this.$parent来获得父组件数据 - 通过provider/inject,在父组件中通过provider提供变量,子组件通过inject来将变量注入到组件中。无论子组件多深,子组件都能通过inject来获得父组件中provider中的数据
-
兄弟组件间通信
- 使用eventBus,创建一个事件中心,相当于中转站。用它来传递和接收事件
- 通过
$parent.$refs来获取到兄弟组件
-
任意组件之间
- 使用eventBus
- vuex
12. vue的路由实现
hash模式和history模式
hash:在浏览器“#”符号 以及后面的字符都称之为hash。用window.location.hash读取。hash虽然在url中,但不被包括在http请求中。hash不会重载页面
history:。可以对浏览器历史记录栈进行修改以及监听到状态的改变
13. vue与react angular的区别
与angular的区别
相同:都支持指令、都支持过滤器、都支持双向数据绑定、都不支持低端浏览器
不同:angular学习成本更高,添加了更多特性。而vue提供的API比较直观简单。angular依赖对数据做脏检查,所以watcher越多越慢,而vue依赖追踪观察,且使用异步队列更新,所有数据都是独立触发
与react区别
相同:中心思想相同,一切都是组件,组件实例之间可以嵌套,都提供合理的钩子函数,都是以插件方式加载,在组件开发中都支持mixins特性
不同:react采用的virtual DOM会对渲染的结果做脏检查,vue在模板中提供了指令,过滤器等,可以非常方便快捷的操作virtual DOM
14. vue路由的钩子函数
beforeEach afterEach
beforeEach有三个参数,to代表的是要进入的路由对象,from代表的是要离开的路由对象。next是一个必须要执行的函数,如果不传参就执行下一个钩子函数,传入false就终止跳转,传入路径跳转到相应的路由。
15. vue-cli如何新增自定义指令
用directives创建局部指令、用Vue.directive创建全局指令
16. vue如何自定义一个过滤器
用fliter
17. 对keep-alive的理解
keep-alive是vue的一个内置组件,可以使被包含的组件保留状态,或避免重新渲染
18. 让css只在当前起作用
在style标签加入scoped
19. $route和$router的区别
$route是“路由信息对象”,包括path,params.query等路由信息参数。而$router是路由实例对象包括了路由的跳转方法、钩子函数等
20. vue.js的核心驱动是什么
数据驱动、组件系统
21. vue常用的几种指令
v-if v-else v-on v-for v-bind v-show
22. vue常用的修饰符
.prevent(提交事件不再重载页面) .stop(阻止事件冒泡) .caputre(事件侦听,事件发生时调用)
23. vue中key值作用
vue中key值作用可以分为两种情况
- v-if使用key值。由于vue会尽可能高效的渲染元素,通常会复用已有元素,而不是重新开始渲染。比如切换相同的input元素,前后用户输入的内容不会被清除掉,这是不符合需求的,因此可以通过key标识一个独立的元素,使用key的元素不会被复用
- v-for使用key值。用v-for更新渲染过的列表,它会默认使用就地复用的策略。如果数据的顺序发生改变,就会跟DOM元素的元素顺序不匹配。因此通过为每个列表项提供一个key值,便于vue跟踪元素身份,高效的更新渲染虚拟DOM
24. vue中mixin和mixins的区别
mixin用于全局混入,会影响到每个组件实例
mixins是如果多个组件有相同的业务逻辑,就可以将这些逻辑剥离出来,通过mixins混入代码。比如上拉下拉加载数据等逻辑。另外,mixins混入的钩子函数会先于组件的钩子函数执行,并且在遇到同名选项时也会选择性的进行合并。
25. computed和wacth的区别
- conmputed和watch都是以vue的依赖追踪机制为基础的。它们试图处理这样一件事:当某一个数据(依赖数据)发生变化的时候,所有依赖这个数据的相关数据会自动发生变化,也就是自动调用相关的函数去实现数据的变动
computed
- 是计算值
- computed擅长处理场景是:一个数据受多个数据影响(多对一)
- 支持缓存,只有依赖数据发生变化,才会重新计算
- 不支持异步。当里面有异步操作时,无法监听数据的变化
watch
- 是观察动作
- wacth擅长的处理场景是:一个数据影响多个数据(一对多)
- 不支持缓存,数据改变会直接触发相应操作
- wacth支持异步
26. vue等单页面应用及其优缺点
优点:
- 用户体验好,快,内容的改变不需要重新加载整个页面,对服务器压力较小
- 前后端分离
- 完全前端组件化,前端开发不再以页面为单位,更多采用组件化思想,代码结构和组织方式更加规范化,便于修改维护
缺点:
- 首次加载页面耗时较长
- 不利于SEO,单页页面,数据在前端渲染,就意味着没有SEO
- 页面导航不可用
- 不支持低版本浏览器
27. slot插槽
1. 单个插槽
当子组件只有一个没有属性的插槽时,父组件传入整个内容片段插入到插槽的所在位置,并替换插槽本身
2. 具名插槽
slot有一个name属性来配置如何分发内容,将父组件模板中slot位置,和子组件slot元素产生关联。便于插槽内容对应传递
3. 作用域插槽
可以访问组件内部数据的可复用插槽。在父组件中的template上使用slot-scope属性。
28. v-show和v-if的区别
v-show控制元素的隐藏和显示,是css切换 v-if是销毁元素和创建元素
29. 绑定class的方法
1. 对象方法
:class="{'active': isActive, 'red': isRed}"
2. 数组方法
:class="[class1,class2]"
3. 行内
:style="{color:color. fontSize:fontSize+'px'}"
30. vuex是什么
一个专为vue.js开发的状态管理模式,它采用集中存储管理应用的所有组件状态,并以相应的规则保证状态以一种可预测的方式发生改变
它有五大核心属性 state、getter、mutation、action、module
state:存储数据,存储状态。用this.$store.state访问
getter:可以认为是store的计算属性。它的返回值会根据它的依赖被缓存起来。
mutation: 更改store中的状态的唯一方法是提交mutation
action: 提交mutation,可以包含任何异步操作
module: 将store分割成各个模块
31. v-model的原理
比如一个输入框v-model了一个message。p标签绑定了这个message,当输入框的数据改变,p标签文本也会改变。其实就是帮忙监听了input事件。并把这个input事件所携带的值传给v-model属性。这样组件内部的值就给到了父组件
其他相关面试题
-
javascript
-
html+css
-
ES6/服务端与网络/前端性能优化/SEO/GIT/WEBPACK/移动端
-
JS原型、原型链、构造函数、实例、继承