- 1. 基本问题
- 1.1. Vue.js 的特点
- 1.2. Vue.js 双向绑定的原理
- 1.3. Vue.js 3.0 放弃defineProperty, 使用Proxy的原因
- 1.4. Vue 2 中给 data 中的对象属性添加一个新的属性时会发生什么?如何解决?
- 1.5. Computed和Watch的区别
- 1.6. Computed 和 Methods 的区别
- 1.7. 虚拟DOM,diff算法
- 1.8. 为何需要Virtual DOM?
- 1.9. 过滤器 (Filter)
- 1.10. 常见的事件修饰符及其作用
- 1.11. v-show指令和v-if指令的区别是什么?
- 1.12. v-model 是如何实现的,语法糖实际是什么
- 1.13. data为什么是一个函数而不是对象
- 1.14. Vue template 到 render 的过程
- 1.15. Vue data 中某一个属性的值发生改变后,视图会立即同步执行重新渲染吗?
- 1.16. axios是什么
- 1.17. sass是什么?如何在vue中安装和使用?
- 1.18. Vue.js页面闪烁
- 1.19. 如何解决数据层级结构太深的问题
- 1.20. 在 Vue. js开发环境下调用API接口,如何避免跨域
- 1.21. 批量异步更新策略
- 1.22. vue 的 nextTick 方法的实现原理
- 1.23. Vue 组件 data 为什么必须是函数 ?
- 1.24. v-if和v-for一起使用的弊端及解决办法
- 1.25. vue常用指令
- 1.26. 组件传值方式有哪些
- 1.27. vue-loader是什么?使用它的用途有哪些?
- 2. 组件 Component
- 3. Vuex
- 4. Router
1. 基本问题
1.1. Vue.js 的特点
- 易用: 简单,易学,上手快
- 灵活: (渐进式)不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩。
- 高效: 20kB min+gzip 运行大小;超快虚拟 DOM;最省心的优化
- 双向绑定:开发效率高
- 基于组件的代码共享
- Web项目工程化,增加可读性、可维护性
1.2. Vue.js 双向绑定的原理
Vue.js 2.0 采用数据劫持(Proxy 模式)结合发布者-订阅者模式(PubSub 模式)的方式,通过 Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
每个组件实例都有相应的watcher程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新。
Vue.js 3.0, 放弃了Object.defineProperty ,使用更快的ES6原生 Proxy (访问对象拦截器, 也称代理器)
步骤:
需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是: ①在自身实例化时往属性订阅器(dep)里面添加自己 ②自身必须有一个update()方法 ③待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
1.3. Vue.js 3.0 放弃defineProperty, 使用Proxy的原因
Object.defineProperty缺陷
- 监控到数组下标的变化时,开销很大。所以Vue.js放弃了下标变化的检测;
- Object.defineProperty只能劫持对象的属性,而Proxy是直接代理对象。Object.defineProperty需要遍历对象的每个属性,如果属性值也是对象,则需要深度遍历。而 Proxy 直接代理对象,不需要遍历操作。
- Object.defineProperty对新增属性需要手动进行Observe。vue2时需要使用 vm.$set 才能保证新增的属性也是响应式
- Proxy支持13种拦截操作,这是defineProperty所不具有的
- Proxy 作为新标准,长远来看,JS引擎会继续优化 Proxy,但 getter 和 setter 基本不会再有针对性优化
1.4. Vue 2 中给 data 中的对象属性添加一个新的属性时会发生什么?如何解决?
视图并未刷新。这是因为在Vue实例创建时,新属性并未声明,因此就没有被Vue转换为响应式的属性,自然就不会触发视图的更新,这时就需要使用Vue的全局 api $set():this.$set(this.obj, 'new_property', 'new_value')
1.5. Computed和Watch的区别
- computed 计算属性 : 依赖其它属性值,并且 computed 的值有缓存,只有它依赖的 属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。
- watch 侦听器 : 更多的是观察的作用,无缓存性,类似于某些数据的监听回调,每 当监听的数据变化时都会执行回调进行后续操作。
运用场景:
- 当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算。
- 当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率, 并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
- 多个因素影响一个显示,用Computed;一个因素的变化影响多个其他因素、显示,用Watch;
1.6. Computed 和 Methods 的区别
- computed: 计算属性是基于它们的依赖进行缓存的,只有在它的相关依赖发生改变时才会重新求值对于 method ,只要发生重新渲染,
- method 调用总会执行该函数
1.7. 虚拟DOM,diff算法
(1)让我们不用直接操作DOM元素,只操作数据便可以重新渲染页面
(2)虚拟dom是为了解决浏览器性能问题而被设计出来的
当操作数据时,将改变的dom元素缓存起来,都计算完后再通过比较映射到真实的dom树上
(3)diff算法比较新旧虚拟dom。如果节点类型相同,则比较数据,修改数据;如果节点不同,直接干掉节点及所有子节点,插入新的节点;如果给每个节点都设置了唯一的key,就可以准确的找到需要改变的内容,否则就会出现修改一个地方导致其他地方都改变的情况。比如A-B-C-D, 我要插入新节点A-B-M-C-D,实际上改变的了C和D。但是设置了key,就可以准确的找到B C并插入
1.8. 为何需要Virtual DOM?
- 具备跨平台的优势
- 操作 DOM 慢,js运行效率高。我们可以将DOM对比操作放在JS层,提高效率。
- 提升渲染性能
1.9. 过滤器 (Filter)
在Vue中使用filters来过滤(格式化)数据,filters不会修改数据,而是过滤(格式化)数据,改变用户看到的输出(计算属性 computed ,方法 methods 都是通过修改数据来处理数据格式的输出显示。
使用场景: 比如需要处理时间、数字等的的显示格式;
1.10. 常见的事件修饰符及其作用
.stop
:等同于 JavaScript 中的 event.stopPropagation() ,防止事件冒泡;.prevent
:等同于 JavaScript 中的 event.preventDefault() ,防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);.capture
:当元素发生冒泡时,先触发带有该修饰符的元素。若有多个该修饰符,则由外而内触发。如 div1中嵌套div2中嵌套div3.capture中嵌套div4,那么执行顺序为:div3=》div4=》div2=》div1.self
:只会触发自己范围内的事件,不包含子元素;.once
:只会触发一次。
1.11. v-show指令和v-if指令的区别是什么?
v-show 仅仅控制元素的显示方式,将 display 属性在 block 和 none 来回切换;而v-if会控制这个 DOM 节点的存在与否。当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。
1.12. v-model 是如何实现的,语法糖实际是什么
- 作用在表单元素上
v-model="message"
等同于v-bind:value="message" v-on:input="message=$event.target.value"
- 作用在组件上, 本质是一个父子组件通信的语法糖,通过prop和$.emit实现, 等同于
:value="message" @input=" $emit('input', $event.target.value)"
1.13. data为什么是一个函数而不是对象
JavaScript中的对象是引用类型的数据,当多个实例引用同一个对象时,只要一个实例对这个对象进行操作,其他实例中的数据也会发生变化。
而在Vue中,我们更多的是想要复用组件,那就需要每个组件都有自己的数据,这样组件之间才不会相互干扰。
所以组件的数据不能写成对象的形式,而是要写成函数的形式。数据以函数返回值的形式定义,这样当我们每次复用组件的时候,就会返回一个新的data,也就是说每个组件都有自己的私有数据空间,它们各自维护自己的数据,不会干扰其他组件的正常运行。
1.14. Vue template 到 render 的过程
- 调用parse方法将template转化为ast(抽象语法树, abstract syntax tree)
- 对静态节点做优化。如果为静态节点,他们生成的DOM永远不会改变,这对运行时模板更新起到了极大的优化作用。
- 生成渲染函数. 渲染的返回值是VNode,VNode是Vue的虚拟DOM节点,里面有(标签名,子节点,文本等等)
1.15. Vue data 中某一个属性的值发生改变后,视图会立即同步执行重新渲染吗?
不会立即同步执行重新渲染。
Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。
Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化, Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。
如果同一个watcher被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。
然后,在下一个的事件循环”tick”中,Vue 刷新队列并执行实际(已去重的)工作。
1.16. axios是什么
易用、简洁且高效的http库, 支持node端和浏览器端,支持Promise,支持拦截器等高级配置。
1.17. sass是什么?如何在vue中安装和使用?
sass是一种CSS预编译语言安装和使用步骤如下。
- 用npm安装加载程序( sass-loader、 css-loader等加载程序)。
- 在 webpack.config.js中配置sass加载程序。
1.18. Vue.js页面闪烁
Vue. js提供了一个v-cloak指令,该指令一直保持在元素上,直到关联实例结束编译。当和CSS一起使用时,这个指令可以隐藏未编译的标签,直到实例编译结束。用法如下。
1 | [v-cloak]{ |
1.19. 如何解决数据层级结构太深的问题
在开发业务时,经常会岀现异步获取数据的情况,有时数据层次比较深,如以下代码: span 'v-text="a.b.c.d"></span>
, 可以使用vm.$set手动定义一层数据: vm.$set("demo",a.b.c.d)
1.20. 在 Vue. js开发环境下调用API接口,如何避免跨域
config/ index.js内对 proxyTable项配置代理。
1.21. 批量异步更新策略
Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。
换句话说,只要观察到数据变化,就会自动开启一个队列,并缓冲在同一个事件循环中发生的所以数据改变。在缓冲时会去除重复数据,从而避免不必要的计算和 DOM 操作。
1.22. vue 的 nextTick 方法的实现原理
- vue 用异步队列的方式来控制 DOM 更新和 nextTick 回调先后执行
- microtask 因为其高优先级特性,能确保队列中的微任务在一次事件循环前被执行完毕
1.23. Vue 组件 data 为什么必须是函数 ?
因为组件是可以复用的,JS 里对象是引用关系,如果组件 data 是一个对象,那么子组件中的 data 属性值会互相污染。
所以一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。
1.24. v-if和v-for一起使用的弊端及解决办法
由于v-for的优先级比v-if高,所以导致每循环一次就会去v-if一次,而v-if是通过创建和销毁dom元素来控制元素的显示与隐藏,所以就会不停的去创建和销毁元素,造成页面卡顿,性能下降。
解决办法:
- 在v-for的外层或内层包裹一个元素来使用v-if
- 用computed处理
1.25. vue常用指令
- v-model 多用于表单元素实现双向数据绑定(同angular中的ng-model)
- v-bind 动态绑定 作用: 及时对页面的数据进行更改
- v-on:click 给标签绑定函数,可以缩写为@,例如绑定一个点击函数 函数必须写在methods里面
- v-for 格式: v-for=”字段名 in(of) 数组json” 循环数组或json(同angular中的ng-repeat)
- v-show 显示内容 (同angular中的ng-show)
- v-hide 隐藏内容(同angular中的ng-hide)
- v-if 显示与隐藏 (dom元素的删除添加 同angular中的ng-if 默认值为false)
- v-else-if 必须和v-if连用
- v-else 必须和v-if连用 不能单独使用 否则报错 模板编译错误
- v-text 解析文本
- v-html 解析html标签
- v-bind:class 三种绑定方法 1、对象型 ‘{red:isred}’ 2、三元型 ‘isred?”red”:”blue”‘ 3、数组型 ‘[{red:”isred”},{blue:”isblue”}]’
- v-once 进入页面时 只渲染一次 不在进行渲染
- v-cloak 防止闪烁
- v-pre 把标签内部的元素原位输出
1.26. 组件传值方式有哪些
- 父传子:子组件通过props[‘xx’] 来接收父组件传递的属性 xx 的值
- 子传父:子组件通过 this.$emit(‘fnName’,value) 来传递,父组件通过接收 fnName 事件方法来接收回调
- 其他方式:通过创建一个bus,进行传值
- 使用Vuex
1.27. vue-loader是什么?使用它的用途有哪些?
2. 组件 Component
2.1. vue中如何编写可复用的组件 (编写组件的原则)
- 以组件功能命名
- 只负责ui的展示和交互动画,不要在组件里与服务器打交道(获取异步数据等)
- 可复用组件不会因组件使用的位置、场景而变化。尽量减少对外部条件的依赖。
2.2. 如何让CSS只在当前组件中起作用?
在每一个Vue.js组件中都可以定义各自的CSS、 JavaScript代码。如果希望组件内写的CSS只对当前组件起作用,只需要在Style标签添加Scoped属性,即。
2.3. keep-alive是什么?
如果需要在组件切换的时候,保存一些组件的状态防止多次渲染,就可以使用 keep-alive 组件包裹需要保存的组件。
两个重要属性,include 缓存组件名称,exclude 不需要缓存的组件名称。
2.4. 如何在 Vue. js动态插入图片
对“src”属性插值将导致404请求错误。应使用 v-bind:src (简写:src
)格式代替。
2.5. 父子组件的生命周期顺序
- 加载渲染过程:
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted - 子组件更新过程:父beforeUpdate->子beforeUpdate->子updated->父updated
- 父组件更新过程:父beforeUpdate->父updated
- 销毁过程:父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
3. Vuex
3.1. vuex的核心概念
- state => 基本数据
- getters => 从基本数据派生的数据
- mutations => 修改数据,同步
- actions => 修改数据,异步 (Action 提交的是 mutation,而不是直接变更状态)
- modules => 模块化Vuex
3.2. vuex是什么?怎么使用?哪种功能场景使用它?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理器,采用集中式存储管理应用的所有组件的状态,主要是为了多页面、多组件之间的通信。
Vuex有5个重要的属性,分别是 State、Getter、Mutation、Action、Module,由 view 层发起一个 Action 给 Mutation,在 Mutation 中修改状态,返回新的状态,通过 Getter暴露给 view层的组件或者页面,页面监测到状态改变于是更新页面。如果你的项目很简单,最好不要使用 Vuex,对于大型项目,Vuex 能够更好的帮助我们管理组件外部的状态,一般可以运用在购物车、登录状态、播放等场景中。
3.3. 多个组件之间如何拆分各自的state,每块小的组件有自己的状态,它们之间还有一些公共的状态需要维护,如何思考这块
- 公共的数据部分可以提升至和他们最近的父组件,由父组件派发
- 公共数据可以放到vuex中统一管理,各组件分别获取
4. Router
4.1. vue-router路由的两种模式
vue-router中默认使用的是hash模式
- hash模式, 带#。如:http://localhost:8080/#/pageA。改变hash,浏览器本身不会有任何请求服务器动作的,但是页面状态和url已经关联起来了。
- history模式,不带#, 如:http://localhost:8080/ 正常的而路径,并没有#。基于HTML5的 pushState、replaceState实现
4.2. vue-router如何定义嵌套路由
通过children 数组:
1 | const router = new VueRouter({ |
4.3. vue-router有哪几种导航钩子?
- 全局导航钩子:router.beforeEach(to,from,next)
- 组件内的钩子beforeRouteEnter (to, from, next) beforeRouteUpdate (to, from, next) beforeRouteLeave (to, from, next)
- 单独路由独享组件 beforeEnter: (to, from, next)
4.4. $route和$router的区别
- $route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。
- $router是“路由实例”对象包括了路由的跳转方法,钩子函数等
4.5. 路由之间跳转的方式
- 声明式(标签跳转)
- 编程式( js跳转)
4.6. active-class是哪个组件的属性
vue-router 模块 的router-link组件