本文主要从下边几个方面复习Vue知识点:
1. MVC && MVVM
2. 数据双向绑定
3. Vue的生命周期
4. 虚拟dom的实现原理
5. vue-router
6. Proxy
7. vuex复制代码
MVC && MVVM
M -- model层,代表数据模型
V -- view层,代表视图层,UI展示
C -- control层,控制层,处理复杂的业务逻辑
VM-- viewModel层,一个同步view和model的对象,其实可以理解为数据双向绑定
Vue就是一种MVVM模式的框架
v-show、v-if的实现原理
v-show为false时,通过js设置display为none;为true时,设置display:''; 这样为了让js设置的display属性失效。
v-if是通过js手动添加或删除dom元素。
组件间通信
组件间通信总共分为一下几种:
1、父 --> 子:
父元素用属性的格式传进来,子元素用props属性接收;
// 父元素
<editor :name='data'></editor>
// 子元素
props: {
name: {
type: Object,
defalut: function(){
}
}
}
复制代码
2、子 --> 父:
在父组件绑定一个事件,自组件用$emit出发事件
扫描二维码关注公众号,回复:
6563527 查看本文章
3、兄弟组件:
4、组件嵌套比较深的时候:vuex
Vue数据双向绑定
所谓数据双向绑定,就是指视图层和数据层相互影响,比如input框输入数据,存储的数据发生相应的变化;当给存储数据的数据重新赋值时,input框的值也会变。
实现双向数据绑定主要是通过数据劫持+发布订阅者模式,劫持各个属性的set和get,在数据发生变化的时候发布给订阅者,触发相应的回调。
真正靠的是Object.defineProperty这个属性
说到这个原理,可以先来了解一下发布-订阅模式。
发布-订阅模式:
开始我对这个模式也有点不理解,但是看到
这个文章的一个比喻瞬间就理解了。
其实这个发布订阅模式就跟平时我们常见的订阅微信公众号的模式是一样的。
-
整个发布订阅模式就像一个平台,让用户可以发生订阅和发布的操作,也就类似于微信公众号平台
-
订阅者可以订阅多个操作,就像我们可以订阅多个公众号一样,但是需要提供给平台我们要订阅的名称,以及订阅者自己的一些信息。
-
作为发布者,其实就像一个公众号,他不关心具体的订阅者是谁,只要订阅了的用户都会收到发布的信息。整个发布操作需要告知平台,是哪个公众号需要发布,发布什么信息。
-
订阅者还可以取消订阅,那么平台需要知道,发起取消订阅的用户是哪个,还有取消的公众号的名称是什么。
那么一个简单的发布订阅模式就形成了,下边话不多说,直接上代码:
const SubPub = function() {
// 用Object格式,可以通过value存储订阅者的一些信息
// 订阅器 --- 类似于微信公众号这个平台,每一个元素类似于一个公众号,key值为公众号的名字,value值记录订阅公众号的人;
this._observer = {};
}
SubPub.prototype = {
// 订阅函数,需要提供我要订阅的公众号名称,以及自己的姓名
subscribe: function(type, callback) {
const self = this;
if(Type(callback) !== 'function') return;
if(!self._observer[type]) this._observer[type] = []
this._observer[type].push(callback);
return self;
},
// 发布函数,需要提供哪个公众号需要发布信息,以及发布的内容;
publish: function() {
const self = this;
const type = Array.prototype.shift.call(arguments); // 因为arguments不是数组,是一种类数组类型,所以没有shift、slice这些方法
//发布的内容
const theme = Array.prototype.slice.call(arguments);
const subs = self._observer[type];
if(!subs || !subs.length) return;
subs.forEach(sub => {
sub.apply(self, theme);
});
return this;
},
// 取消订阅,需要提供取消公众号的名字,和发起该取消操作的用户
removeSub: function(type, callback) {
const _subs = this._observer[type];
if(!_subs || !_subs.length) return;
_subs.map((item, index) => {
if(item === callback) {
_subs.splice(index, 1);
}
})
return this;
}
}
function Type(value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}
// 实例一个发布订阅器
let sp = new SubPub();
// 定义订阅者
const sub1 = function(data) {
console.log('sub1' + data);
}
const sub2 = function(data) {
console.log('sub2' + data);
}
const sub3 = function(data) {
console.log('sub3' + data);
}
// 发起订阅操作
sp.subscribe('click', sub1);
sp.subscribe('input',sub1);
sp.subscribe('qqq',sub1);
sp.subscribe('click', sub2);
sp.subscribe('input', sub3);
// 开启发布
sp.publish('click', '第一次发布click事件');
sp.publish('input', '第一次发布input事件');
sp.removeSub('click', sub1).publish('click', '第二次发布click事件');复制代码
Object.defineProperty的使用方法
接下来看一下Object.defineProperty的使用方法。
let obj = {};
let song = '七里香';
obj.singer = 'JayZhou';
Object.defineProperty(obj, 'music', {
configurable: true, // 可以配置对象, 为true的时候才可以删除属性
enumerable: false, // 是否可枚举
get () {
return song;
},
set (val) {
song = val;
}
});
console.log(obj.music); // {singer: '周杰伦', music: '七里香'}
obj.music = '听妈妈的话';
console.log(obj.music);
delete obj.music
console.log(obj);
for(var i in obj) {
console.log(i); // 只有singer 因为music是不可枚举的
}复制代码
缺点:
-
无法监听数组变化
Vue的MVVM模式实现原理:
-
observe:一个数据监听器,对数据对象的所有属性,包括子属性进行监听,如果发生变化,拿到最新值并通知订阅者
-
compile:一个指令解析器,对每个元素的节点指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的函数
-
watcher: 一个订阅者,它将作为连接数据监听器和指令解析器的一个桥梁。能够订阅每个属性的数据变化,收到数据变化的通知,执行回调函数,更新UI页面
-
Mvvm的入口函数,将三者整合
Vue的生命周期
vue的生命周期是指的从 创建 --> 挂载 --> 更新 --> 销毁 的过程。
总共分为8个步骤:
beforeCreate, created,
beforeMount, mounted,
beforeUpdate, updated,
beforeDestroy, destroyed
Vue虚拟DOM
所谓虚拟DOM,就是一个JS对象,用来存储DOM树结构。
过程:
-
创建dom树
-
利用diff算法进行对比,存储差异patches对象,按下边四种格式
-
节点类型改变
-
属性改变
-
文本改变
-
增加/移动/删除子节点
3. 渲染差异
-
遍历patches,把需要修改的节点取出来
-
局部更新dom,利用document.fragments来操作dom,进行浏览器一次性更新。
document.fragment:
是DOM节点,不是主DOM树的一部分。
通常用来创建文档片段,将元素附加到文档片段中,然后将文档片段附加到DOM树中。由于文档片段存在内存中,不在DOM树中,所以插入子元素的时候不会引发浏览器回流,所以性能更好
nextTick
用于执行dom渲染之后的回调,新版本默认是microtasks
vue-router
模式:hash、history
跳转方式:
-
this.$router.push()
-
<router-link to=''></router-link>
-
this.$router.replace()
占位:
<router-view></router-view>
默认情况下是hash模式,history需要后台配置,利用Html5的History API实现的,监听change变化。
router和route的区别:
$router:是VueRouter的一个实例,是一个全局的对象,主要实现路由的跳转使用。常用的router.push()和router.replace()方法。
push方法会像浏览器的history栈添加一个新纪录。
replace替换路由,没有历史记录。
route:是一个路由信息对象,每一个路由都有一个route对象,是一个局部对象。可以获取name、query、params、path等参数。
Proxy
定义:来自
MDN的定义:用于定义基本操作的自定义行为(如:属性查找、赋值、枚举、函数调用等);
另外
阮一峰解释的比较容易理解:在目标对象之前架设一层拦截,外界对象对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
语法:
let p = new Proxy(target, handler);复制代码
简单例子:
var proxy = new Proxy({}, {
get: function(target, key, receiver) {
console.log(`get ${key}`);
return Reflect.get(target, key, receiver);
},
set: function(target, key, value, receiver) {
console.log(`set ${key}`);
return Reflect.set(target, key, value, receiver);
}
});
proxy.name = 'jack';
// set name
console.log(proxy.name);
// get name
// jack复制代码
上边的例子是对一个空对象进行了拦截。
Vue3.0中要用Proxy代替defineProperty。proxy无论是从操作上还是底层功能上远强于defineProperty。
优点:
-
可以监听数组的变化,这个是defineProperty做不到的
-
直接监听对象,而不是对象的属性,而且会生成一个新对象
Vuex
什么是Vuex?
Vuex是vue的状态管理工具,采用集中存储所有组件的状态,并以相应的规则保证状态以一种可以预测的方式发生变化
Vuex的核心属性:
Vuex有五个核心属性:state、getter、mutation、action、module
- State:存储数据状态;可以通过this.$store.state访问;对应vue里的data;存放数据的方式是响应式的,vue组件可以从store中读取数据,如果数据变化,组件也会发生相应的更新。
- Getter:就相当于store的计算属性,他的返回值会根据他的依赖被缓存起来,且只有当它的依赖发生改变的时候才会被重新计算。
- Mutation:更改vuex的store的唯一方法就是提交mutation
- Action:包含任意异步操作,通过提交mutation间接改变状态。
- Module:将store分割成模块,每个模块都具备上边四种方法,甚至子模块
vuex数据传递流程
-
当组件进行数据修改时,调用dispatch来触发action里边的方法;
-
每个action里边都有一个commit方法,可以通过commit来修改mutations里边的方法进行数据修改
-
mutation中都会有一个state参数,这样可以通过mutation修改了state数据
-
数据修改完毕之后,页面发生改变
为什么用vuex?
-
当组件多层嵌套的时候,父子组件传递数据很麻烦。
-
增加代码的可读性和可维护性
-
数据是响应式的,减少数据的派发操作;
转载于:https://juejin.im/post/5d02016c6fb9a07ec27b9e50