3-2-3模板编译和组件化

1.模板编译介绍
将模板转化为渲染函数
作用:
使用Vnode描述视图以及各种交互,用户自己编写vnode比较复杂
用户只需要编写类似html的代码 -vue.js模板,通过编译器将模板转换为返回vnode的render函数
.vue文件会被webpack在构建的过程中转换成render函数

2.体验模板编译结果
function render(){
with(this){
return _c(
tag ‘div’, createElement(vm, a, b, c, d, false) h函数 创建 vnode 对象··
data {attrs:{“id”:“app”}},
children [
_m(0), renderStatic 静态方法
_v(" “), createTextVNode 创建空白文本节点
_c(‘p’,[_v(_s(msg))]), toString 转化成字符串 p标签 包含msg的文本节点
_v(” "),
_c(‘comp’,{on:{“myclick”:handler}})
],
normalizationType 1
)
}
}
3.Vue template Explorer 网页工具 把html模板转化成render函数
标签内的文本内容尽量不添加多余的空白内容 vue2
vue3没关系

4.编译的入口函数
compileToFunctions 模板转换成render函数的函数 入口
==》createCompiler ==》createCompilerCreator 平台相关的参数和用户传递的参数准备好
createCompiler
1.把模板编译成ast 抽象语法树 parse(template.trim(), options)
2.优化抽象语法树 optimize(ast, options)
3.把抽象语法树生成字符串形式的js代码 generate(ast, options)

	createCompilerCreator
	
	3.compileToFunctions  返回render函数  是编译入口
		由 2createCompiler(baseOptions) 生成  接收平台相关的参数
			由1.createCompilerCreator (baseCompile)生成
				1.1baseCompile接收两个参数  template 模板
										 finalOptions   合并之后的选项
					做了三件事	1.解析parse
								2.优化optimze
								3.生成generate
					返回2.createCompiler  
			2.createCompiler定义了两个参数	template
											options
							生成  compileToFunctions
							返回  3.compile.compileToFunctions

5.模板编译过程
1.compileToFunctions 由 2.createCompiler 生成 同时生成 compile
2.createCompiler 由 3.createCompilerCreator 生成
3.createCompilerCreator 里面 返回了 2.createCompiler方法 在2.createCompiler方法里 又通过4.createCompileToFunctionFn 返回了compileToFunctions方法
4.createCompileToFunctionFn 先找缓存中的结果 没有就编译 将字符串形式的js代码转换成js方法
cache 闭包缓存编译后的结果
options 克隆 防止五日
warn 警告
key 改变插值表达式的符号
调用4.1compile 编译返回 compiled 包含render, staticRenderFns
compiled里面又 errors 和tips

	调用 4.2.createFunction 将字符串形式的js代码转换从js方法  保存render 静态方法
		res.render = createFunction(compiled.render, fnGenErrors)
		res.staticRenderFns = compiled.staticRenderFns.map(code => {
		  return createFunction(code, fnGenErrors)
		})
    return (cache[key] = res) 缓存并返回res对象(render, staticRenderFns方法)

6.4.1 compile 在 2. createCompiler 里生成
核心作用:合并选项 编译
template: string, 用户传入的选项
options?: CompilerOptions

  finalOptions 合并选项
  warn 警告
  调用 4.1.1baseCompile 编译
	返回 compiled 
  返回 compiled对象
  1. 4.1.1 1 baseCompile 编译模板
    baseCompile
    1.把模板编译成ast 抽象语法树 parse(template.trim(), options)
    2.优化抽象语法树 optimize(ast, options)
    3.把抽象语法树生成字符串形式的js代码 generate(ast, options)
    返回 ast,
    // 渲染函数
    render: code.render,
    // 静态渲染函数,生成静态 VNode 树
    staticRenderFns: code.staticRenderFns

    抽象语法树
    1.简称AST
    2.使用对象的形式描述树形的代码结构
    3.这里是描述树形结构的HTML字符串

    为什么使用AST
    1.转成AST后,可以通过AST对模板进行优化处理 optimize
    2.标记模板中的静态内容,在patch的时候直接跳过静态内容 标签中的纯文本内容
    3.在patch的过程中 静态内容不需要对比和重新渲染

     ast explorer
    

8.parse(template.trim(), options) 函数 把模板编译成ast 抽象语法树
1. 解析 options
2. 对模板解析 parseHTML 依次遍历html模板字符串转化成ast对象 指令和组件会记录在ast相应的属性上
解析过程中的回调函数,生成 AST

9.optimize(ast, options) 标记静态节点
// 标记静态节点
markStatic(root)
// 标记静态根节点
markStaticRoots(root, false)

	markStatic
		isStatic  判断是否是静态节点
		遍历子节点
	
	node.type==1 为标签
			3  注释
				文本节点

10.generate(ast, options) 把抽象语法树生成字符串形式的js代码
调用 genElement 将ast转化成js代码
生成render函数
genStatic 生成 staticRenderFns静态根节点
state.staticRenderFns.push(with(this){return ${genElement(el, state)}}) 赋值
_m 函数 为 renderStatic 函数
renderStatic
markStatic 标记静态
markStaticNode
在 4.createCompileToFunctionFn 通过 4.2createFunction 将code 转换成函数

11.调试 编译
入口文件 entry-runtime-with-compiler.js
1.在 $mount中 调用 compileToFunctions方法 进入 把 template 转换成 render 函数
找出是否有缓存好的渲染函数 没有找到开始编译模板
进入compile 函数
2.compile(template, options) 核心是合并选项
先合并finalOptions = Object.create(baseOptions) 选项
进入baseCompile函数

		3.baseCompile(template.trim(), finalOptions)   进入函数  模板编译的核心位置 三件事
					3.1.把模板编译成ast  抽象语法树		parse(template.trim(), options)
						这个时候还没有static 相关的属性
					3.2.优化抽象语法树					optimize(ast, options)
						生成static 相关的属性 static 和 staticRoot
					3.3.把抽象语法树生成字符串形式的js代码		generate(ast, options)
					返回compiled对象 返回compile方法
		3.在compile函数中 通过createFunction 方法将 js代码转换成匿名函数的返回到 compileToFunctions 中,同样作为compileToFunctions的返回结果返回到$mount中
			
		4.挂载到option 中
		options.render = render
		options.staticRenderFns = staticRenderFns
        5.执行mount 方法

12.组件化回顾
一个vue组件就是一个拥有预定义选项的一个vue实例
一个组件可以组成页面上一个功能完完备的区域 组件包含脚本 样式 模板

可以重用 嵌套  就像搭积木  
组件粒度越小越号码

13.组件注册
全局组件 全局都可以用
局部组件

	Vue.component
		
	initAssetRegisters    
		ASSET_TYPES 定义了组件
		统一处理了组件的构造函数

14.Vue.extend 组件的选项对象 转换成组件的构造函数 开发自定义组件的过程中会用到此方法
cid 保证创建一个包裹子构造函数

	通过cid 获取缓存的构造函数
	验证组件的名称是否合法
	Sub  构造函数
		mergeOptions
		组件实例合并了参数选项

15.调试组件注册过程

16.回顾首次渲染过程
Vue构造函数
this._init()
this.$mount()
mountComponent()
new Watcher() 渲染 Watcher
updateComponent()
vm._render() ==>createElement()
vm._update()

	_createElement
		判断typeof tag === 'string' 不是的时候进入 component
			进入 vnode = createComponent(tag, data, context, children)
			createComponent	
					baseCtor=context.$options._base  组件的构造函数
					resolveConstructorOptions  合并组件选项
				安装组件的钩子函数 init/prepatch/insert/destroy
				// 准备好了 data.hook 中的钩子函数
				installComponentHooks  
					componentVNodeHooks
						init
							createComponentInstanceForVnode  返回了创建组件实例
								return new vnode.componentOptions.Ctor(options)
						prepatch
						insert
						destroy
					通过mergeHook合并用户的钩子函数和	componentVNodeHooks 的钩子函数
			const vnode = new VNode 以`vue-component-‘开头
				Ctor 创建了组件的对象
			return vnode

		init钩子函数是在patch函数调用的

17.组件的patch过程
patch函数
createElm(vnode, insertedVnodeQueue) 方法
createComponent(vnode, insertedVnodeQueue, parentElm, refElm) 函数
调用了init 钩子函数 isDef(i = i.hook) && isDef(i = i.init)
调用了 createComponentInstanceForVnode 函数 存储 vnode.componentInstance
return new vnode.componentOptions.Ctor(options)
Vue.extend 创建组件的时候调用了 this._init (options)方法
_init() 当前父组件已创建完毕 实际为 vue
合并options选项 initInternalComponent(vm,options)
vm.$options = Object.create(vm.constructor.options)
记录父组件
initLifecycle()
记录父组件
在父组件中记录子组件

								_update里面
									将当前vm实例缓存起来存储到 ActiveInstance 中  父组件对象
									const restoreActiveInstance = setActiveInstance(vm)  
									
									restoreActiveInstance 还原 ActiveInstance 
				child.$mount(hydrating ? vnode.elm : undefined, hydrating)
				创建真实dom
				
	创建父组件 再创建子组件   挂载 先挂载子组件 后挂载父组件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值