主题
Vue
1. 对于 MVVM 的理解
MVVM
是 Model-View-ViewModel
的缩写
Model
代表数据模型,也可以在Model
中定义数据修改和操作的业务逻辑。View
代表UI
组件, 它负责将数据模型转化成UI
展现出来。ViewModel
监听模型数据的改变和控制视图行为 、处理用户交互, 简单理解就是⼀个同步View
和Model
的对象, 连接Model
和View
- 在
MVVM
架构下,View
和Model
之间并没有直接的联系, 而是通过ViewModel
进行交互,Model
和ViewModel
之间的交互是双向的, 因此View
数据的变化会同步到Model
中, 而Model
数据的变化也会立即反应到View
上。 ViewModel
通过双向数据绑定把View
层和Model
层连接了起来, 而View
和Model
之间的同步⼯作完全是自动的, ⽆需⼈为⼲涉, 因此开发者只需关注业务逻辑,不需要手动操作DOM
,不需要关注数据状态的同步问题, 复杂的数据状态维护完全由MVVM
来统⼀管理
- 在
2. 请详细说下你对 vue 生命周期的理解
总共分为 8
个阶段 创建前/后, 载⼊前/后,更新前/后,销毁前/后
- 创建前/后: 在
beforeCreate
阶段,vue
实例的挂载元素el
和数据对象data
都为undefined
, 还未初始化 。在created
阶段,vue
实例的数据对象data
有了,el
还没有 - 载⼊前/后:在
beforeMount
阶段,vue
实例的$el
和data
都初始化了,但还是挂载之前为虚拟的dom
节点,data.message
还未替换 。在mounted
阶段,vue
实例挂载完成,data.message
成功渲染 - 更新前/后: 当
data
变化时,会触发beforeUpdate
和updated
方法 - 销毁前/后:在执行
destroy
方法后,对data
的改变不会再触发周期函数,说明此时vue
实例已经解除了事件监听以及和dom
的绑定,但是dom
结构依然存在
什么是 vue 生命周期?
Vue 实例从创建到销毁的过程,就是生命周期 。从开始创建 、初始化数据 、编译模板 、挂载 Dom→ 渲染 、更新 → 渲染 、销毁等⼀系列过程,称之为 Vue 的生命周期。
vue 生命周期的作用是什么?
它的生命周期中有多个事件钩⼦ ,让我们在控制整个 Vue 实例的过程时更容易形成好的逻辑。
vue 生命周期总共有几个阶段?
它可以总共分为 8 个阶段:创建前/后 、载⼊前/后 、更新前/后 、销毁前/销毁后。
第⼀次页面加载会触发哪几个钩子?
会触发下面这⼏个 beforeCreate
、 created
、 beforeMount
、 mounted
。
DOM 渲染在哪个周期中就已经完成?
DOM
渲染在 mounted
中就已经完成了
3. Vue 实现数据双向绑定的原理:Object.defineProperty()
vue
实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的⽅式, 通过Object.defineProperty()
来劫持各个属性的setter
,getter
,在数据变动时发布消息给订阅者,触发相应监听回调 。当把⼀个普通Javascript
对象传给Vue
实例来作为它的data
选项时,Vue
将遍历它的属性,用Object.defineProperty()
将它们转为getter/setter
。用户看不到getter/setter
,但是在内部它们让Vue
追踪依赖,在属性被访问和修改时通知变化vue
的数据双向绑定 将MVVM
作为数据绑定的⼊⼝ ,整合Observer
,Compile
和Watcher
三者, 通过Observer
来监听自⼰的model
的数据变化, 通过Compile
来解析编译模板指令 (vue
中是用来解析), 最终利用
watcher
搭起observer
和Compile
之间的通信桥梁, 达到数据变化 — >视图更新;视图交互变化 (input
) — > 数据model
变更双向绑定效果。
4. Vue 组件间的参数传递
- 父组件与子组件传值
父组件传给⼦组件:⼦组件通过 props
⽅法接受数据;
⼦组件传给父组件: $emit
⽅法传递参数
- 非父子组件间的数据传递,兄弟组件传值
eventBus
,就是创建⼀个事件中心,相当于中转站, 可以用它来传递事件和接收事件 。项目比较⼩时,用这个比较合适 ( 虽然也有不少⼈推荐直接用 VUEX
, 具体来说看需求)
5. Vue 的路由实现: hash 模式 和 history 模式
hash
模式:在浏览器中符号“#”
,#以及#后面的字符称之为hash
,用window.location.hash
读取 。特点:hash
虽然在URL
中,但不被包括在HTTP
请求中 ;用来指导浏览器动作,对服务端安全⽆用,hash
不会重加载页面 。history
模式:history
采用HTML5
的新特性;且提供了两个新⽅法:pushState()
,replaceState()
可以对浏览器历史记录栈进⾏修改, 以及popState
事件的监听到状态变更
6. vue 路由的钩子函数
首页可以控制导航跳转, beforeEach
, afterEach
等,⼀ 般用于页面 title
的修改 。⼀些需要登录才能调整页面的重定向功能。
beforeEach
主要有 3 个参数to
,from
,next
。to
:route
即将进⼊的目标路由对象。from
:route
当前导航正要离开的路由。next
:function
⼀定要调用该⽅法resolve
这个钩⼦ 。执⾏效果依赖next
⽅法的调用参数 。可以控制网页的跳转
7. vuex 是什么?怎么使用? 哪种功能场景使用它?
- 只用来读取的状态集中放在
store
中; 改变状态的⽅式是提交mutations
, 这是个同步的事物; 异步逻辑应该封装在action
中 - 在
main.js
引⼊store
, 注⼊ 。新建了⼀个目录store
,… export
- 场景有:单页应用中, 组件之间的状态 、音乐播放 、登录状态 、加⼊购物车
vuex
state
:Vuex
使用单⼀状态树,即每个应用将仅仅包含⼀个store
实例,但单⼀状态树和模块化并不冲突 。存放的数据状态,不可以直接修改里面的数据mutations
:mutations
定义的⽅法动态修改Vuex
的store
中的状态或数据getters
:类似vue
的计算属性, 主要用来过滤⼀些数据。action
:actions
可以理解为通过将mutations
里面处里数据的⽅法变成可异步的处理数据的⽅法, 简单的说就是异步操作数据 。view
层通过store.dispath
来分发action
modules
:项目特别复杂的时候, 可以让每⼀个模块拥有自⼰的state
、mutation
、action
、getters
,使得结构非常清晰, ⽅便管理
8. v-if 和 v-show 区别
v-if
按照条件是否渲染, v-show
是 display
的 block
或 none
;
9. $route 和 $router 的区别
$route
是“路由信息对象”, 包括 path
, params
, hash
, query
, fullPath
, matched
, name
等路由信息参数。
而 $router
是“路由实例”对象包括了路由的跳转方法,钩⼦函数等
10. 如何让 CSS 只在当前组件中起作用?
将当前组件的 <style>
修改为 <style scoped>
11. <keep-alive></keep-alive>
的作用是什么?
<keep-alive></keep-alive>
包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染
比如有⼀个列表和⼀个详情,那么用户就会经常执⾏打开详情=>返回列表=>打开详情 …这样的话列表和详情都是⼀个频率很高的页面,那么就可以对列表组件使用 <keep-alive></keep-alive>
进⾏缓存, 这样用户每次返回列表的时候,都能从缓存中快速渲染, 而不是重新渲染
12. 指令 v-el 的作用是什么?
提供⼀个在页面上已存在的 DOM
元素作为 Vue
实例的挂载目标.可以是 CSS
选择器,也可以是⼀个 HTMLElement
实例,
13. 在 Vue 中使用插件的步骤
- 采用
ES6
的import
...from
... 语法或CommonJS
的require()
方法引⼊插件 - 使用全局方法
Vue.use( plugin )
使用插件,可以传⼊⼀个选项对象Vue.use(MyPlugin, { someOption: true })
14. 请列举出 3 个 Vue 中常用的生命周期钩子函数?
created
: 实例已经创建完成之后调用,在这⼀步,实例已经完成数据观测, 属性和方法的运算,watch/event
事件回调. 然而, 挂载阶段还没有开始,$el
属性目前还不可⻅mounted
:el
被新创建的vm.$el
替换, 并挂载到实例上去之后调用该钩⼦ 。如果root
实例挂载了⼀个文档内元素, 当mounted
被调用时vm.$el
也在文档内。activated
:keep-alive
组件激活时调用
15. vue-cli 工程技术集合介绍
问题⼀: 构建的 vue-cli
工程都到了哪些技术,它们的作用分别是什么?
vue.js
:vue-cli
工程的核心, 主要特点是 双向数据绑定和组件系统。vue-router
:vue
官方推荐使用的路由框架。vuex
:专为Vue.js
应用项目开发的状态管理器, 主要用于维护vue
组件间共用的⼀些变量和方法。axios
( 或者fetch
、ajax
): 用于发起GET
、或POST
等http
请求, 基于Promise
设计。vuex
等:⼀个专为vue
设计的移动端 UI 组件库。- 创建⼀个
emit.js
文件,用于vue
事件机制的管理。 webpack
:模块加载和vue-cli
工程打包器。
问题二:vue-cli
工程常用的 npm
命令有哪些?
- 下载
node_modules
资源包的命令:
shell
npm install
- 启动
vue-cli
开发环境的npm
命令:
shell
npm run dev
vue-cli
生成 生产环境部署资源 的npm
命令:
shell
npm run build
- 用于查看
vue-cli
生产环境部署资源文件大小的npm
命令:
shell
npm run build --report
在浏览器上自动弹出⼀个 展示 vue-cli
工程打包后 app.js
、manifest.js
、 vendor.js
文件里面所包含代码的页面 。可以具此优化 vue-cli
生产环境部署的静态资源,提升页面的加载速度
16. NextTick
nextTick
可以让我们在下次 DOM
更新循环结束之后执行延迟回调,用于获得更新后的 DOM
17. vue 的优点是什么?
- 低耦合 。视图 (
View
) 可以独立于Model
变化和修改,⼀个ViewModel
可以绑定到不同的"View"
上, 当View
变化的时候Model
可以不变, 当Model
变化的时候View
也可以不变 - 可重用性 。你可以把⼀些视图逻辑放在⼀个
ViewModel
里面,让很多view
重用这段视图逻辑 - 可测试 。界面素来是比较难于测试的, 而现在测试可以针对
ViewModel
来写
18. 路由之间跳转?
声明式 (标签跳转)
vue
<router-link :to="index" />
编程式 ( js 跳转)
js
router.push("index");
19. 实现 Vue SSR
其基本实现原理
app.js
作为客户端与服务端的公用入口, 导出Vue
根实例,供客户端entry
与服务端entry
使用 。客户端entry
主要作用挂载到DOM
上, 服务端entry
除了创建和返回实例, 还进行路由匹配与数据预获取webpack
为客服端打包⼀个Client Bundle
, 为服务端打包⼀个Server Bundle
。- 服务器接收请求时,会根据
url
,加载相应组件, 获取和解析异步数据,创建⼀个读取Server Bundle
的BundleRenderer
,然后生成html
发送给客户端。 - 客户端混合,客户端收到从服务端传来的
DOM
与自⼰的生成的DOM
进行对比, 把不相同的DOM
激活,使其可以能够响应后续变化, 这个过程称为客户端激活 。为确保混合成功,客户端与服务器端需要共享同⼀套数据 。在服务端, 可以在渲染之前获取数据,填充到stroe
里, 这样,在客户端挂载到DOM
之前, 可以直接从 store 里取数据 。首屏的动态数据通过window.__INITIAL_STATE__
发送到客户端
Vue SSR
的实现, 主要就是把 Vue
的组件输出成⼀个完整 HTML
, vue-server-renderer
就是干这事的
Vue SSR
需要做的事多点 ( 输出完整 HTML
), 除了 complier
-> vnode
, 还需如数据获取填充至 HTML
、客户端混合 ( hydration
) 、缓存等等 。 相比于其他模板引擎( ejs
, jade
等), 最终要实现的目的是⼀样的,性能上可能要差点
20. Vue 组件 data 为什么必须是函数
每个组件都是 Vue
的实例。
组件共享 data
属性, 当 data
的值是同⼀个引用类型的值时, 改变其中⼀个会影响其他
21. Vue computed 实现
建立与其他属性 ( 如: data
、 Store
) 的联系;
属性改变后, 通知计算属性重新计算
实现时, 主要如下:
- 初始化
data
, 使用Object.defineProperty
把这些属性全部转为getter/setter
。 - 初始化
computed
, 遍历computed
里的每个属性,每个computed
属性都是⼀个watch
实例 。每个属性提供的函数作为属性的getter
,使用Object.defineProperty
转化。 Object.defineProperty
getter
依赖收集 。用于依赖发生变化时,触发属性重新计算。- 若出现当前
computed
计算属性嵌套其他computed
计算属性时, 先进行其他的依赖收集
22. Vue complier 实现
模板解析这种事,本质是将数据转化为⼀段 html
, 最开始出现在后端, 经过各种处理吐给前端 。随着各种 mv*
的兴起,模板解析交由前端处理。
总的来说, Vue complier
是将 template
转化成⼀个 render
字符串
可以简单理解成以下步骤:
parse
过程,将template
利用正则转化成AST
抽象语法树 。optimize
过程,标记静态节点,后diff
过程跳过静态节点,提升性能。generate
过程,生成render
字符串
23. 怎么快速定位哪个组件出现性能问题
用 timeline
工具 。 大意是通过 timeline
来查看每个函数的调用时常,定位出哪个函数的问题,从而能判断哪个组件出了问题