目录
模板编译
解析器
将模板解析成AST( abstract syntax tree)
用一个对象描述一个节点
分为 html解析器,文本解析器,过滤器解析器
正则表达式
解析过程中不断触发钩子函数
Eg:
html解析器 =>
start()[碰到开始标签时触发,like < div>]
end()[碰到结束标签时触发,like</ div>]
chars()[碰到文本]
comment()[碰到注释]
每个钩子函数会返回一个对象{}
用栈来记录层级关系
因为对于解析器是平级的,需要利用栈来找到父子节点分别是什么
开始标签对应入栈,结束标签对应出栈,当前栈的栈顶对应弹出栈的父
优化器
找到AST中的静态子树并打上标记
好处
1 重新渲染不需要创建新的vnode
2 打补丁的时候patching,不需要进行比较
静态节点/静态根节点
p/ul
代码生成器
递归生成 标签名 + 数据对象 + 字节点 的字符串
字符串拼接过程,给到createElement,通过with()返回
实例方法与全局API
export default Vue文件
function Vue () {…}
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
renderMixin(Vue)
定义Vue函数然后分别用这五个函数向Vue原型里挂载方法
数据相关的实例方法
watch, set, delete
在stateMixin中被挂载
事件相关方法
on, once, off, emit
在eventsMixin中被挂载
vm.$on
用法 vm.
o
n
(
e
v
e
n
t
,
c
a
l
l
b
a
c
k
)
,
自
定
义
事
件
,
可
由
v
m
.
on(event, callback),自定义事件,可由vm.
on(event,callback),自定义事件,可由vm.emit触发
所以可以用来子传父
原理,在vm._events对象里注册事件
_events是在init的时候挂载的
vm.$off
移除监听事件
1.没有参数,vm._events = object.create(null) 重置全部事件
2,只有一个参数事件,移除该事件所有监听器
3,都有,只单个移除
vm.$once
监听自定义事件,但是只触发一次,触发后移除监听器
vm记录this,先删除,然后回调函数apply到vm执行。
on.fn防止拦截器不能$off
vm.$emit
触发事件,并传入参数,可用来子传父
生命周期相关实例方法
四个生命周期相关方法
mount,forceUpdate,nextTick,destroy
lifecycleMixin 加载 forceUpdate 和 destroy
renderMixin 加载 nextTick
跨平台代码中 加载 mount
vm.$forceUpdate
仅影响实例本身,和在此示例中写了插槽的子组件,因为插槽相当于在当前组件定义的,其他子组件不变
使用时利用当前组件的watcher的update()方法进行更新,(中等粒度)
vm.$destroy
清理实例与其他实例的链接,接触其全部监听和指令
调用beforeDestroy和destroyed函数
1,isBeingdestroyed
2,beforeDestroy // 钩子callHook
3,找到父实例,清除children,indexof + splice
4,vm._watcher teardown() watchers循环,清除用户自己定义的watcher
5,destroyed // 钩子callHook
6,vm.%off 清除监听器
vm.$nextTick
下一个DOM更新周期再执行
为什么vue使用异步更新
因为watcher是在组件上的,异步更新加队列可以保证在一个事件周期内当两个状态改变通知同个watcher时不会进行多次dom渲染
什么是事件循环
javascript是单线程非阻塞的语言,当有异步操作时,会挂起,进行下一个主线程的任务,当异步操作结束后会放入响应队列,主线程会后续来执行它
宏任务与微任务
主线程->微任务->宏任务
微任务:promise.then/ process.nextTick
宏任务:setinterval/ setTimeout/ IO/ UI交互
什么是执行栈
javascript 执行函数时会生成环境上下文,包括作用域,参数,this等。放入执行栈中执行,执行完毕进行下一个函数
promise 的状态,pending,resolve,reject
new promise
resolve()
.then .catch
执行resolve,reject
看收藏
vm.$mount
完整版,运行版
运行版没有render()
完整版vm.$mount实现原理
1,函数劫持
mount = Vue.prototype.$mount
Vue.prototype.$mount = function(el)
{
//do something
mount.call(this, el)
}
保存原始的mount到一个变量,do something else 再调用原始mount
简单回顾一下call,apply
call可以…arguments
apply 需要数组传多参
.call/.apply(target,argument)
2,do something
queryselector(el) || el
判断是否有render,根据初始函数挂载的options来判断(chapter14介绍)
如果没有,获取到template模板,利用compileToFunction转换成渲染函数
全局API的实现原理
vm.extend
用法
var aa = Vue.extend({
template: ``
data () {return {}}
})
new aa().$mount(el)
extend就是创建一个子类,继承Vue身上的一些功能
增加了缓存策略,父级id为key,子类为value
反复调用统一extend可以直接返回缓存结果
直接调用Vue.extend则继承Vue的构造函数
vm.nextTick
vm.set
vm.delete
vm.directive
注册自定义指令
用法
Vue.directive(‘aa’,{
bind: function(){}…
})
五个钩子函数:bind,inserted,update,componentUpdate,unbind
Vue内置指令:V-model,V-show
vm.filter
注册 vm.filter(‘aa’,function(){})
用法 {{ ccc | aa}}
:“cc | aa”
组件本地过滤器
filter:{
aa: function () {
}
}
vm.component
注册组件
和filter,directive都在Vue.options里(保存数据的数组都在vue.options里)
Vue.use
使用插件,elementUI,只能一次
Vue.mixin
全局注册一个mixin,会影响之后的每个Vue实例
Vue.compile
Vue.compile = compileToFunction
只在完整版有用,模板转换成渲染函数
Vue.version
字符串形式的版本号