写于vue3.0发布前夕的helloworld之二
接着,继续走,来到了vm.$mount。
开始生成render函数,生成VNode,由于是第一次加载,所以patch机制为只删除前一个dom节点机制,下面都会讲到。
先到$mount:
Vue.prototype.$mount = function (
el,
hydrating
) {
el = el && query(el); /* istanbul ignore if */
if (el === document.body || el === document.documentElement) {
warn(
"Do not mount Vue to <html> or <body> - mount to normal elements instead."
);
return this
} var options = this.$options;
// resolve template/el and convert to render function
if (!options.render) {
var template = options.template;
if (template) {
if (typeof template === 'string') {
if (template.charAt(0) === '#') {
template = idToTemplate(template);
/* istanbul ignore if */
if (!template) {
warn(
("Template element not found or is empty: " + (options.template)),
this
);
}
}
} else if (template.nodeType) {
template = template.innerHTML;
} else {
{
warn('invalid template option:' + template, this);
}
return this
}
} else if (el) {
template = getOuterHTML(el);
}
if (template) {
/* istanbul ignore if */
if (config.performance && mark) {
mark('compile');
} var ref = compileToFunctions(template, {
outputSourceRange: "development" !== 'production',
shouldDecodeNewlines: shouldDecodeNewlines,
shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this);
var render = ref.render;
var staticRenderFns = ref.staticRenderFns;
options.render = render;
options.staticRenderFns = staticRenderFns; /* istanbul ignore if */
if (config.performance && mark) {
mark('compile end');
measure(("vue " + (this._name) + " compile"), 'compile', 'compile end');
}
}
}
return mount.call(this, el, hydrating)
};
一句句来讲,这里边是挺长,但是足够简单,首先判断el是否为body或者html元素,是则警告,然后退出当前函数,然后根据条件拿到template,因为我们没有设置render和template,所以template走else分支getOuterHTML,拿到template之后,会将当前的template编译成一个render函数,这个编译函数叫做compileToFunctions:这个函数是真的长,而且与主题干系不大,这里我们用文字解释一下就行,首先他是一个闭包函数,闭包了一个叫cache的对象这个对象是缓存当前已经编译过的模板的,进入函数之后有缓存直接返回缓存,没有的话就会执行compile函数,这些都是编译过程,最终compile会调用parseHTML方法使用正则加字符串分析字符串,返回一个这样的对象:
{
"type":1,
"tag":"div",
"attrsList":[
{"name":"id","value":"app","start":5,"end":13}
],
"attrsMap":{
"id":"app"
},
"rawAttrsMap":{
"id":{
"name":"id",
"value":"app",
"start":5,
"end":13
}
},
"children":
[
{
"type":2,
"expression":"_s(msg)",
"tokens":[{"@binding":"msg"}],
"text":"{{msg}}",
"start":14,"end":21
}
],
"start":0,
"end":27,
"plain":false,
"attrs":[{"name":"id","value":"\"app\"","start":5,"end":13}]
}
这就是我们的ast语法树,之后会根据ast生成code,这个方法叫做generate:
function generate (
ast,
options
) {
var state = new CodegenState(options);
var code = ast ? genElement(ast, state) : '_c("div")';
return {
render: ("with(this){return " + code + "}"),
staticRenderFns: state.staticRenderFns
}
}
这个方法调用了genElement方法,简而言之,里边的方法生成code时都会以ast上的值为原料,进行字符串拼接,最后code长这样:
_c('div',{attrs:{"id":"app"}},[_v(_s(msg))])
这里做一下解释_c,_v都是vue内部创建虚拟dom的函数,_s其实就是将当前值转化成字符串,继续走,generate执行完毕之后返回到compileToFunctions,这个时候拼接好的render字符串是这样:
"with(this){return _c('div',{attrs:{"id":"app"}},[_v(_s(msg))])}"
然后会使用new Function 将其生成一个函数,这个函数就是我们的render,组建上的render,执行完compileToFunctions,继续回到$mount函数里,执行最终的$mount:
Vue.prototype.$mount = function (
el,
hydrating
) {
el = el && inBrowser ? query(el) : undefined;
return mountComponent(this, el, hydrating)
};
可见mout调用了mountComponent方法:
function mountComponent (
vm,
el,
hydrating
) {
vm.$el = el;
if (!vm.$options.render) {
vm.$options.render = createEmptyVNode;
{
/* istanbul ignore if */
if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||
vm.$options.el || el) {
warn(
'You are using the runtime-only build of Vue where the template ' +
'compiler is not available. Either pre-compile the templates into ' +
'render functions, or use the compiler-included build.',
vm
);
} else {
warn(
'Failed to mount component: template or render function not defined.',
vm
);
}
}
}
callHook(vm, 'beforeMount'); var updateComponent;
/* istanbul ignore if */
if (config.performance && mark) {
updateComponent = function () {
var name = vm._name;
var id = vm._uid;
var startTag = "vue-perf-start:" + id;
var endTag = "vue-perf-end:" + id; mark(startTag);
var vnode = vm._render();
mark(endTag);
measure(("vue " + name + " render"), startTag, endTag); mark(startTag);
vm._update(vnode, hydrating);
mark(endTag);
measure(("vue " + name + " patch"), startTag, endTag);
};
} else {
updateComponent = function () {
vm._update(vm._render(), hydrating);
};
} // we set this to vm._watcher inside the watcher's constructor
// since the watcher's initial patch may call $forceUpdate (e.g. inside child
// component's mounted hook), which relies on vm._watcher being already defined
new Watcher(vm, updateComponent, noop, {
before: function before () {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, 'beforeUpdate');
}
}
}, true /* isRenderWatcher */);
hydrating = false; // manually mounted instance, call mounted on self
// mounted is called for render-created child components in its inserted hook
if (vm.$vnode == null) {
vm._isMounted = true;
callHook(vm, 'mounted');
}
return vm
}
mountComponent方法一进来,先判断是否有render,之后会根据条件警告一些信息。然后开始调起beforeMount钩子函数,下来初始化一个updateComponent方法,他的正常版本长这样:
updateComponent = function () {
vm._update(vm._render(), hydrating);
};
实际上在组建的dom更新,包括第一次挂载,和随后的相应式更新上,本质都用的是这一个函数。然后继续走,重头戏来啦,watcher在这里开始初始化,注意传给他的第四个参数,在哪里我们把要调用beforeUpdate给传了过去。
我们的下面来到watcher的构造函数:
写于vue3.0发布前夕的helloworld之二的更多相关文章
- 写于vue3.0发布前夕的helloworld
前言: vue3.0马上要来了,于今昔写一篇vue将一个字符串hellowrold渲染于页面的过程,慰藉我这几个月写vue的'枯燥'. 源码版本是2.6.10. 开始: 我们的模板足够简单: < ...
- 写于vue3.0发布前夕的helloworld之三
接上,watcher构造函数: var Watcher = function Watcher ( vm, expOrFn, cb, options, isRen ...
- VUE3.0发布,自己搞个文档网站
9月19日,尤大神发表了VUE3.0版本的演说,强大且震撼,这两天一直在找网站文档,可能还未被百度收录,未找到文档网站.后来在github上面找到了中文代码. 地址为:https://github.c ...
- 预计2019年发布的Vue3.0到底有什么不一样的地方?
摘要: Vue 3.0预览. 原文:预计今年发布的Vue3.0到底有什么不一样的地方? 作者:小肆 微信公众号:技术放肆聊 Fundebug经授权转载,版权归原作者所有. 还有几个月距离 vue2 的 ...
- 把酒言欢话聊天,基于Vue3.0+Tornado6.1+Redis发布订阅(pubsub)模式打造异步非阻塞(aioredis)实时(websocket)通信聊天系统
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_202 "表达欲"是人类成长史上的强大"源动力",恩格斯早就直截了当地指出,处在蒙昧时代即低 ...
- 纯小白入手 vue3.0 CLI - 3.3 - 路由的导航守卫
vue3.0 CLI 真小白一步一步入手全教程系列:https://www.cnblogs.com/ndos/category/1295752.html 尽量把纷繁的知识,肢解重组成为可以堆砌的知识. ...
- 纯小白入手 vue3.0 CLI - 2.1 - 组件 ( component )
vue3.0 CLI 真小白入手全教程系列:https://www.cnblogs.com/ndos/category/1295752.html 我的 github 地址 - vue3.0Study ...
- 快速进阶Vue3.0
在2019.10.5日发布了Vue3.0预览版源码,但是预计最早需要等到 2020 年第一季度才有可能发布 3.0 正式版. 可以直接看 github源码. 新版Vue 3.0计划并已实现的主要架构改 ...
- Vue3实战系列:Vue3.0 + Vant3.0 搭建种子项目
最近在用 Vue3 写一个开源的商城项目,开源后让大家也可以用现成的 Vue3 大型商城项目源码来练练手,目前处于开发阶段,过程中用到了 Vant3.0,于是就整理了这篇文章来讲一下如何使用 Vue3 ...
- Laf v1.0 发布:函数计算只有两种,30s 放弃的和 30s 上线的
一般情况下,开发一个系统都需要前端和后端,仅靠一个人几乎无法胜任,需要考虑的特性和功能非常多,比如: 需要一个数据库来存放数据: 需要一个文件存储来存放各种文件,比如图片文件: 后端需要提供接口供前端 ...
随机推荐
- mybatis-plus 使用In查询
第一种在Dao接口中自定义SQL查询,拼接xml字符串 UserDaoMapper.java @Select("<script>" +"select * fr ...
- manim边学边做--同伦变换
在Manim中,移动一个元素除了之前介绍的方法之外,还可以通过同伦运算来移动一个元素. 与普通的移动元素方式相比,使用同伦运算移动一个元素时,实际上是在考虑整个空间的连续变形过程中元素的相应变化. 这 ...
- Qt音视频开发12-mpv解码播放
一.前言 之前玩了vlc解码和ffmpeg解码,前阵子有个客户需要换成mpv解码,于是研究了下mpv的使用方法,自从用了mpv以后发现爱不释手,这玩意天生适合极客和程序员啊,居然将各种处理封装成了命令 ...
- 基于开源IM即时通讯框架MobileIMSDK:RainbowChat v8.1版已发布
关于MobileIMSDK MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级.高度提炼,一套API优雅支持UDP .TCP .WebSocket 三种协议,支持iOS.A ...
- springboot~多节点应用里的雪花算法唯一性
雪花算法的唯一性,在单个节点中是可以保证的,对应kubernetes中的应用,如果是横向扩展后,进行多副本的情况下,可能出现重复的ID,这需要我们按着pod_name进行一个workId的生成,我还是 ...
- SpringBoot进阶教程(八十四)spring-retry
在日常的一些场景中, 很多需要进行重试的操作.而spring-retry是spring提供的一个基于spring的重试框架,某些场景需要对一些异常情况下的方法进行重试就会用到spring-retry. ...
- Mysql存储引擎Innodb和MyISAM的区别
一.mysql架构 mysql是一个单进程多线程架构的数据库. 二.存储引擎 InnoDB: 支持事务 行锁 读操作无锁 4种隔离级别,默认为repeatable 自适应hash索引 每张表的存储都是 ...
- jQuery---操作指南
功能代码(1)---通过Jquery来处理复选框 实现以下功能: 1:选中第一个复选框,那么下面所有的复选框都选中,去除选中第一个复选框,下面的都不选中 2:当点击全选按钮,上面足球.篮球.游泳.唱歌 ...
- 在线客服系统 QPS 突破 240/秒,连接数突破 4000,日请求数接近1000万次,.NET 多线程技术的高性能实践
背景 我在业余时间开发了一款自己的独立产品:升讯威在线客服与营销系统.陆陆续续开发了几年,从一开始的偶有用户尝试,到如今的 QPS 突破 240 次/秒,连接数突破 4000,日请求数接近 1000 ...
- LeetCode刷题:runtime error: reference binding to null pointer of type 'int' (stl_vector.h)报错请教
题目:https://leetcode.cn/problems/merge-intervals/ 错误代码: // 思路初探:做了很多道类似区间操作的题目了.本题就是尽可能少的创建新区间 // 1.首 ...