vue从使用到源码实现教程详解


Posted in Javascript onSeptember 19, 2016

搭建环境

项目github地址

项目中涉及了json-server模拟get请求,用了vue-router;

关于Vue生命周期以及vue-router钩子函数详解

生命周期

1.0版本

1.哪些生命周期接口

init
Created
beforeCompile
Compiled
Ready
Attatched
Detached
beforeDestory
destoryed

2.执行顺序

1. 不具有keep-alive

进入:

init->create->beforeCompile->complied->attatched->ready

移出:

beforeDestory->detached->destoryed;

2. 具有keep-alive

第一次的时候

进入:

init->create->beforeCompile->complied->attatched->ready

移出:

detached;

之后的每次

进入:

attatched

移出:

detached

钩子函数

3.钩子函数有哪些

data
activete
deactivate
canactivate
candeactivate

4.执行顺序

进入:

canactivate->actiavte->date

移出:

candeactivate->deactiavte

两者一起出现

5.对于一个组件A里面有子组件B,当这个组件A进行移入和移出操作时,组件之间的生命周期喝钩子函数的执行顺序参考如下:

例如

A.vue

<div>
<B></B>
</div>

备注:下面括号里的是嵌套的子组件

1. 不具有keep-alive:

移入:

1. canActivate;
2. init;
3. create;
4. beforeCompile;
5. (嵌套子组件:init,create,beforeCompile,compile);
6. compile;
7. activate;
8. data;
9. attached;
10. (子组件attached);
11. (子组件ready);
12. ready;

移出:

13. canDeactivate;
14. deactivate;
15. beforeDestroy;
16. (子组件beforeDestroy);
17. (子组件destoryed);
18. detached;
19. (子组件detached);
20. destoryed;

2. 具有keep-alive:

移入:

1. canActivate;
2. activate;
3. data;
4. attached;
5. (子组件attached);

移出:

6. canDeactivate;
7. deactivate;
8. detached;
9. (子组件detached);

6.钩子函数activate和data的执行顺序

涉及钩子函数异步 resolve 规则:

1.如果钩子返回一个 Promise,则钩子何时 resolve 取决于该 Promise 何时 resolve。

2.如果钩子既不返回 Promise,也没有任何参数,则该钩子将被同步 resolve。

3.如果钩子不返回 Promise,但是有一个参数(transition),则钩子会等到transition.next(),transition.abort()或是transition.redirect()之一被调用才 resolve。

4.在验证类的钩子,比如canActivate,canDeactivate以及全局 beforeEach 钩子中,如果返回值是一个布尔值 (Boolean),也会使得钩子同步 resolve。

vue从使用到源码实现教程详解 
vue从使用到源码实现教程详解 
vue从使用到源码实现教程详解

7.根据什么可以确保界面已经更新完成,也就是说挂在完成

执行生命周期attached说明已挂载

双向绑定与渲染机制

1.数据的监听和触发(订阅和发布observer)

src目录下observer:

1. array.js

2. dep.js;(实现一个发布订阅对象)

3. index.js;(利用Object.defineProperty这个API,并为此属性设计一个特殊的 getter/setter,然后在 setter 里触发一个函数,达到监听的效果);

下面是这部分的源码

Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
var value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
}
if (isArray(value)) {
for (var e, i = 0, l = value.length; i < l; i++) {
e = value[i]
e && e.__ob__ && e.__ob__.dep.depend()
}
}
}
return value
},
set: function reactiveSetter (newVal) {
var value = getter ? getter.call(obj) : val
if (newVal === value) {
return
}
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = observe(newVal)
dep.notify()
}
})

简化上面的监听与触发代码如下:

function notidy(obj,key){
console.log(key+" has changed");
console.log(key+" now is: "+obj[key]);
}
function ToData(key,val){
var ob=this;
Object.defineProperty(ob,key,{
enumerable:true,
configurable:true,
get:function(){
return val;
},
set:function(newval){
if(newval==val){
return;
}
val=newval;
notidy(this,key);
}
})
}

src目录下directive.js

在directive中可以看到一系列解析出来的属性,而directive的实例化可以在utils/lifecycle.js中看到。

下面这段代码在Directive.prototype._bind中

var watcher = this._watcher = new Watcher(
this.vm,
this.expression,
this._update, // callback
{
filters: this.filters,
twoWay: this.twoWay,
deep: this.deep,
preProcess: preProcess,
postProcess: postProcess,
scope: this._scope
}
)
// v-model with inital inline value need to sync back to
// model instead of update to DOM on init. They would
// set the afterBind hook to indicate that.
if (this.afterBind) {
this.afterBind()
} else if (this.update) {
this.update(watcher.value)
}
Directive.prototype.set = function (value) {
/* istanbul ignore else */
if (this.twoWay) {
this._withLock(function () {
this._watcher.set(value)
})
} else if (process.env.NODE_ENV !== 'production') {
warn(
'Directive.set() can only be used inside twoWay' +
'directives.'
)
}
}

src目录下Watch.js:

从下面的代码可以找到watcher对象通过addDep方法实现订阅

Watcher.prototype.addDep = function (dep) {
var id = dep.id
if (!this.newDepIds.has(id)) {
this.newDepIds.add(id)
this.newDeps.push(dep)
if (!this.depIds.has(id)) {
dep.addSub(this)
}
}
}

2.前面说那么多关于双向绑定,其实这也是VUE内部的渲染机制,总结如下

1. 通过 observer 对 data 进行了监听,并且提供订阅某个数据项的变化的能力

2. 把 template 解析成一段 document fragment,然后解析其中的 directive,得到每一个 directive 所依赖的数据项及其更新方法。比如 v-text="message" 被解析之后 (这里仅作示意,实际程序逻辑会更严谨而复杂):所依赖的数据项this.$data.message,以及相应的视图更新方法 node.textContent = this.$data.message

3. 通过 watcher 把上述两部分结合起来,即把 directive 中的数据依赖订阅在对应数据的 observer 上,这样当数据变化的时候,就会触发 observer,进而触发相关依赖对应的视图更新方法,最后达到模板原本的关联效果。

3.vue是如何改进了v-for具有相同数据渲染出错的?

数组的渲染

未使用track-by的数组渲染内部缓存的默认id是数组的值value,意味着如果数组中存在相同的值,通过id获取的是相同的一个fragement片段,最后通过insertBefore操作DOM由于是相同的一个实例,故不会生效。

<div>
<ul id='test'>
<li id="child1">child1</li>
<li id="child">child2</li>
</ul>
</div>
<script>
_element1=document.getElementById('child1');
_element2=document.getElementById('child2');
document.getElementById('test').insertBefore(_element1,_element2);
</script>

渲染的结果是child2在child1前面

使用track-by目的是自定义这个内部的id,使得数组中具有相同的值的几项都不会选择到相同的实例,对于使用track-by='$index'还是其他唯一区分的id值有一定的区别,各有好处。

使用$index使得反转的数据没有移动操作,而对于使用其他的id在顺序不一样的时候会有相应的移动操作。

对象的渲染

对象一般使用键作为内部缓存对象的id,通过track-by也可以自定义这个id提高性能。

vm.model = {
a: { id: 1, val: "model1"},
b: { id: 2, val: "model2"},
c: { id: 3, val: "model2"},
}

列表更新

vm.model = {
d: { id: 1, val: "model1"},
e: { id: 2, val: "model2"},
f: { id: 3, val: "model2"}
}

以上所述是小编给大家介绍的vue从使用到源码实现教程详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
jquery特效 幻灯片效果示例代码
Jul 16 Javascript
JavaScript插件化开发教程 (三)
Jan 27 Javascript
JavaScript动态修改背景颜色的方法
Apr 16 Javascript
JQuery限制复选框checkbox可选中个数的方法
Apr 20 Javascript
jQuery实现邮箱下拉列表自动补全功能
Sep 08 Javascript
Bootstrap 网站实例之单页营销网站
Oct 20 Javascript
深入学习jQuery中的data()
Dec 22 Javascript
jQuery仿IOS弹出框插件
Feb 18 Javascript
js+html5实现页面可刷新的倒计时效果
Jul 15 Javascript
Angular4编程之表单响应功能示例
Dec 13 Javascript
浅谈javascript错误处理
Aug 11 Javascript
layui点击左侧导航栏,实现不刷新整个页面,只刷新局部的方法
Sep 25 Javascript
浅谈js内置对象Math的属性和方法(推荐)
Sep 19 #Javascript
jquery事件绑定解绑机制源码解析
Sep 19 #Javascript
JavaScript学习笔记整理_setTimeout的应用
Sep 19 #Javascript
Node.js + Redis Sorted Set实现任务队列
Sep 19 #Javascript
JavaScript学习笔记整理_用于模式匹配的String方法
Sep 19 #Javascript
JavaScript学习笔记整理_简单实现枚举类型,扑克牌应用
Sep 19 #Javascript
JavaScript学习笔记整理_关于表达式和语句
Sep 19 #Javascript
You might like
PHP入门速成教程
2007/03/19 PHP
PHP EOT定界符的使用详解
2008/09/30 PHP
PHP DataGrid 实现代码
2009/08/12 PHP
kohana框架上传文件验证规则写法示例
2014/07/14 PHP
示例详解Laravel的注册重构
2016/08/14 PHP
jquery click([data],fn)使用方法实例介绍
2013/07/08 Javascript
三种检测iPhone/iPad设备方向的方法
2014/04/23 Javascript
node.js中的fs.writeSync方法使用说明
2014/12/15 Javascript
你一定会收藏的Nodejs代码片段
2016/02/04 NodeJs
JavaScript定义数组的三种方法(new Array(),new Array('x','y')
2016/10/04 Javascript
利用VUE框架,实现列表分页功能示例代码
2017/01/12 Javascript
JavaScript中的toString()和toLocaleString()方法的区别
2017/02/15 Javascript
javascript 秒表计时器实现代码
2017/03/09 Javascript
Angular4学习笔记之准备和环境搭建项目
2017/08/01 Javascript
详解Vue单元测试case写法
2018/05/24 Javascript
vue实现移动端悬浮窗效果
2018/12/01 Javascript
JavaScript的console命令使用实例
2019/12/03 Javascript
vue中后端做Excel导出功能返回数据流前端的处理操作
2020/09/08 Javascript
React实现todolist功能
2020/12/28 Javascript
[01:16:37]【全国守擂赛】第三周决赛 Dark Knight vs. 一个弱队
2020/05/04 DOTA
利用Python读取文件的四种不同方法比对
2017/05/18 Python
Python输出带颜色的字符串实例
2017/10/10 Python
python reverse反转部分数组的实例
2018/12/13 Python
Python 从一个文件中调用另一个文件的类方法
2019/01/10 Python
Python 二叉树的层序建立与三种遍历实现详解
2019/07/29 Python
Python实现随机取一个矩阵数组的某几行
2019/11/26 Python
flask框架渲染Jinja模板与传入模板变量操作详解
2020/01/25 Python
python集合删除多种方法详解
2020/02/10 Python
python opencv实现简易画图板
2020/08/27 Python
CSS3弹性布局内容对齐(justify-content)属性使用详解
2017/07/31 HTML / CSS
生产经理的自我评价分享
2013/11/07 职场文书
市场营销求职信范文
2014/02/21 职场文书
质量标语大全
2014/06/12 职场文书
4S店收银员岗位职责
2015/04/07 职场文书
使用CSS设置滚动条样式
2022/01/18 HTML / CSS
详解Spring Bean的配置方式与实例化
2022/06/10 Java/Android