Vue 是一套用于构建用户界面的渐进式框架。Vue 的设计受到了 MVVM 的启发,因此常使用
vm
(ViewModel 的缩写) 这个变量名表示 Vue 实例。Vue 的两个核心是数据驱动和组件系统。[1]
MVVM 是什么?
MVVM 全称 Model–View–ViewModel,是一种软件架构模式。
-
Model
模型,是指代表真实状态内容的领域模型(面向对象),或指代表内容的数据访问层(以数据为中心)。 -
View
视图,是用户在屏幕上看到的结构、布局和外观(UI)。 -
ViewModel
视图模型,是暴露公共属性和命令的视图的抽象。用于把Model
和View
关联起来。ViewModel
负责把Model
的数据同步到View
显示出来,还负责把View
的修改同步回Model
。
总结起来就是,在 MVVM 架构下,View
和 Model
之间并没有直接的联系,而是通过 ViewModel
进行交互,Model
和 ViewModel
之间的交互是双向的,View
数据的变化会同步到 Model
中,而 Model
数据的变化也会立即反应到 View
上。因此开发者只需关注业务逻辑,不需要手动操作DOM
, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
Vue 是如何实现数据双向绑定的?
Vue 的数据双向绑定,最明显的体现是 v-model
指令和 .sync
修饰符。首先 Vue 的设计受到了 MVVM 的启发,这种模式的主要特点就是数据与视图的双向同步。Vue 实现数据双向绑定主要是采用数据劫持结合发布者-订阅者模式的方式,具体实现就是整合 Observer,Compile 和 Watcher 三者。
-
Observer:数据监听器,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者,内部就是通过
ES5
的Object.defineProperty()
方法实现。当把一个普通 Javascript 对象传给 Vue 实例的data
选项时,Vue 将遍历它的属性,用Object.defineProperty()
劫持各个属性的setter
和getter
。Object.defineProperty()
的简单用法:
let obj = {};
Object.defineProperty(obj, "a", {
get: function () {
console.log(`我被读取了`);
return val;
},
set: function (val) {
console.log(`我被设置了:${val}`);
},
});
// 在给 obj 设置 a 属性的时候,会触发 set 方法
obj.a= "1"; // expected output: 我被设置了:1
// 在读取 obj 的 a 属性的时候,会触发 get 方法
var val = obj.a; // expected output: 我被读取了
-
Watcher:订阅者,作为连接 Observer 和 Compile 的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数。
-
Compile:指令解析器, 它的作用对每个元素节点的指令进行扫描和解析,根据指令模板( Vue 中就是
mustache
语法{{}}
)替换数据,以及绑定相应的更新函数。
Vue 实例的生命周期钩子都有哪些?
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。[2]
-
beforeCreate
实例初始化之前,$el
和data
都为undefined
。 -
created
实例创建完成,data
已经绑定。 -
beforeMount
将<template>
和data
生成虚拟DOM
节点,可以访问到$el
,但还没有渲染到html
上。 -
mounted
实例挂载完成,渲染到html
页面中。 -
beforeUpdate
data
更新之前,虚拟DOM
重新渲染之前。 -
updated
由于data
更新导致的虚拟DOM
重新渲染之后。 -
activated
keep-alive
专用,实例被激活时调用。 -
deactivated
keep-alive
专用,实例被移除时调用。 -
beforeDestroy
实例销毁之前(实例仍然可用)。 -
destroyed
实例销毁之后。所有的事件监听器会被移除,所有的子实例也会被销毁,但DOM
节点依旧存在。该钩子在服务器端渲染期间不被调用。
第一次页面加载会触发哪几个钩子?
beforeCreate
created
beforeMount
mounted
组件系统是 Vue 的核心之一,那么 Vue 的组件是如何进行通信的?
-
父子组件通信
- 通过
props
传参 - 通过
$emit
触发 - 通过
$refs
调用子组件方法
- 通过
-
兄弟组件通信
- 状态管理
vuex
-
Local Storage
、Seeion Storage
或Cookies
- 事件总线
EventBus
- 状态管理
// event-bus.js
import Vue from 'vue'
export default new Vue()
// 组件 A
import Bus from 'event-bus.js'
export default {
methods: {
handleClick(val) {
Bus.$emit('functionName', val)
}
}
}
// 组件 B
import Bus from 'event-bus.js'
export default {
created() {
Bus.$on('functionName', val=> {
console.log(val)
})
}
}
网友评论