当前位置: 首页 > news >正文

用织梦做外文网站海外社交媒体平台

用织梦做外文网站,海外社交媒体平台,社保扣款怎么在社保网站上做》,滑县网站建设服务【Vue3】源码解析 系列文章什么是虚拟DOMVue 3虚拟DOM获取template内容生成AST语法树生成render方法字符串得到最终VNode对象 系列文章 【Vue3】源码解析-前置 【Vue3】源码解析-响应式原理 【Vue3】源码解析-虚拟DOM 什么是虚拟DOM 在浏览器中#xff0c;HTML页面… 【Vue3】源码解析 系列文章什么是虚拟DOMVue 3虚拟DOM获取template内容生成AST语法树生成render方法字符串得到最终VNode对象 系列文章 【Vue3】源码解析-前置 【Vue3】源码解析-响应式原理 【Vue3】源码解析-虚拟DOM 什么是虚拟DOM 在浏览器中HTML页面由基本的DOM树来组成的当其中一部分发生变化时其实就是对应某个DOM节点发生了变化当DOM节点发生变化时就会触发对应的重绘或者重排当过多的重绘和重排在短时间内发生时就会可能引起页面的卡顿所以改变DOM是有一些代价的那么如何优化DOM变化的次数以及在合适的时机改变DOM就是开发者需要注意的事情。 虚拟DOM就是为了解决上述浏览器性能问题而被设计出来的。当一次操作中有10次更新DOM的动作虚拟DOM不会立即操作DOM而是和原本的DOM进行对比将这10次更新的变化部分内容保存到内存中最终一次性的应用在到DOM树上再进行后续操作避免大量无谓的计算量。 虚拟DOM实际上就是采用JavaScript对象来存储DOM节点的信息将DOM的更新变成对象的修改并且这些修改计算在内存中发生当修改完成后再将JavaScript转换成真实的DOM节点交给浏览器从而达到性能的提升。 例如下面一段DOM节点如下代码所示 div idappp classtextHello/p /div转换成一般的虚拟DOM对象结构如下代码所示 {tag: div,props: {id: app},chidren: [{tag: p,props: {className: text},chidren: [Hello]}] }上面这段代码就是一个基本的虚拟DOM但是他并非是Vue中使用的虚拟DOM结构因为Vue要复杂的多。 Vue 3虚拟DOM 在Vue中我们写在template标签内的内容都属于DOM节点这部分内容会被最终转换成Vue中的虚拟DOM对象VNode其中的步骤比较复杂主要有以下几个过程 抽取template内容进行compile编译。得到AST语法树并生成render方法。执行render方法得到VNode对象。VNode转换真实DOM并渲染到页面。 完整流程如下图 我们以一个简单的demo为例子在Vue 3的源码里去寻找到底是如何一步一步进行了demo如下代码所示 div idappdiv{{name}}/divp123/p /div Vue.createApp({data(){return {name : abc}} }).mount(#app)上面代码中data中定义了一个响应式数据name并在template中使用插值表达式{{name}}进行使用还有一个静态节点p123/p。 获取template内容 调用createApp()方法会进入到源码packages/runtime-dom/src/index.ts里面的createApp()方法如下代码所示 export const createApp ((...args) {const app ensureRenderer().createApp(...args)...app.mount (containerOrSelector: Element | ShadowRoot | string): any {if (!isFunction(component) !component.render !component.template) {// 将#app绑定的HTML内容赋值给template项上component.template container.innerHTML// 调用mount方法渲染const proxy mount(container, false, container instanceof SVGElement)return proxy}...return app }) as CreateAppFunctionElement对于根组件来说template的内容由挂载的#app元素里面的内容组成如果项目是采用npm和Vue CliWebpack这种前端工程化的方式那么对于template的内容则主要由对应的loader在构建时对文件进行处理来获取这和在浏览器运行时的处理方式是不一样的。 生成AST语法树 在得到template后就依据内容生成AST语法树。抽象语法树Abstract Syntax TreeAST是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构树上的每个节点都表示源代码中的一种结构。之所以说语法是“抽象”的是因为这里的语法并不会表示出真实语法中出现的每个细节。比如嵌套括号被隐含在树的结构中并没有以节点的形式呈现而类似于if-condition-then这样的条件跳转语句可以使用带有三个分支的节点来表示。如下代码所示 while b ≠ 0if a b a : a − belse b : b − a return a如果将上述代码转换成广泛意义上的语法树如图所示。 对于template的内容其大部分是由DOM组成但是也会有if-condition-then这样的条件语句例如v-ifv-for指令等等在Vue 3中这部分逻辑在源码packages\compiler-core\src\compile.ts中baseCompile方法核心代码如下所示 export function baseCompile(template: string | RootNode,options: CompilerOptions {} ): CodegenResult {...// 通过template生成ast树结构const ast isString(template) ? baseParse(template, options) : template...// 转换transform(ast,...)return generate(ast,extend({}, options, {prefixIdentifiers})) }baseCompile方法主要做了以下事情 生成Vue中的AST对象。将AST对象作为参数传入transform函数进行转换。将转换后的AST对象作为参数传入generate函数生成render函数。 其中baseParse方法用来创建AST对象在Vue 3中AST对象是一个RootNode类型的树状结构在源码packages\compiler-core\src\ast.ts中其结构如下代码所示 export function createRoot(children: TemplateChildNode[],loc locStub ): RootNode {return {type: NodeTypes.ROOT, // 元素类型children, // 子元素helpers: [],// 帮助函数components: [],// 子组件directives: [], // 指令hoists: [],// 标识静态节点imports: [],cached: 0, // 缓存标志位temps: 0,codegenNode: undefined,// 存储生成render函数字符串loc // 描述元素在AST树的位置信息} }其中children存储的时后代元素节点的数据这就构成一个AST树结构type表示元素的类型NodeType主要分为HTML普通类型和Vue指令类型等常见的有以下几种 ROOT, // 根元素 0 ELEMENT, // 普通元素 1 TEXT, // 文本元素 2 COMMENT, // 注释元素 3 SIMPLE_EXPRESSION, // 表达式 4 INTERPOLATION, // 插值表达式 {{ }} 5 ATTRIBUTE, // 属性 6 DIRECTIVE, // 指令 7 IF, // if节点 9 JS_CALL_EXPRESSION, // 方法调用 14 ...hoists是一个数组用来存储一些可以静态提升的元素在后面的transform会将静态元素和响应式元素分开创建这也是Vue 3中优化的体现codegenNode则用来存储最终生成的render方法的字符串loc表示元素在AST树的位置信息。 在生成AST树时Vue 3在解析template内容时会用一个栈stack来保存解析到的元素标签。当它遇到开始标签时会将这个标签推入栈遇到结束标签时将刚才的标签弹出栈。它的作用是保存当前已经解析了但还没解析完的元素标签。这个栈还有另一个作用在解析到某个字节点时通过stack[stack.length - 1]可以获取它的父元素。 demo代码中生成的AST语法树如下图所示。 生成render方法字符串 在得到AST对象后会进入transform方法在源码packages\compiler-core\src\transform.ts中其核心代码如下所示 export function transform(root: RootNode, options: TransformOptions) { // 数据组装 const context createTransformContext(root, options)// 转换代码traverseNode(root, context)// 静态提升if (options.hoistStatic) {hoistStatic(root, context)}// 服务端渲染if (!options.ssr) {createRootCodegen(root, context)}// 透传元信息root.helpers [...context.helpers.keys()]root.components [...context.components]root.directives [...context.directives]root.imports context.importsroot.hoists context.hoistsroot.temps context.tempsroot.cached context.cachedif (__COMPAT__) {root.filters [...context.filters!]} }transform方法主要是对AST进行进一步转化为generate函数生成render方法做准备主要做了以下事情 traverseNode方法将会递归的检查和解析AST元素节点的属性例如结合helpers方法对click等事件添加对应的方法和事件回调对插值表达式、指令、props添加动态绑定等。处理类型逻辑包括静态提升逻辑将静态节点赋值给hoists以及根据不同类型的节点打上不同的patchFlag便于后续diff使用。在AST上绑定并透传一些元数据。 generate方法主要是生成render方法的字符串code在源码packages\compiler-core\src\codegen.ts中其核心代码如下所示 export function generate(ast: RootNode,options: CodegenOptions {onContextCreated?: (context: CodegenContext) void} {} ): CodegenResult {const context createCodegenContext(ast, options)if (options.onContextCreated) options.onContextCreated(context)const {mode,push,prefixIdentifiers,indent,deindent,newline,scopeId,ssr} context...// 缩进处理indent()deindent()// 单独处理component、directive、filtersgenAssets()// 处理NodeTypes里的所有类型genNode(ast.codegenNode, context)...// 返回code字符串return {ast,code: context.code,preamble: isSetupInlined ? preambleContext.code : ,// SourceMapGenerator does have toJSON() method but its not in the typesmap: context.map ? (context.map as any).toJSON() : undefined} }generate方法的核心逻辑在genNode方法中其逻辑是根据不同的NodeTypes类型构造出不同的render方法字符串部分类型如下代码所示 switch (node.type) { case NodeTypes.ELEMENT: case NodeTypes.IF: case NodeTypes.FOR:// for关键字元素节点genNode(node.codegenNode!, context)break case NodeTypes.TEXT:// 文本元素节点genText(node, context)break case NodeTypes.VNODE_CALL:// 核心VNode混合类型节点AST语法树节点genVNodeCall(node, context)break case NodeTypes.COMMENT: // 注释元素节点genComment(node, context)break case NodeTypes.JS_FUNCTION_EXPRESSION:// 方法调用节点genFunctionExpression(node, context)break ...其中 节点类型NodeTypes.VNODE_CALL对应genVNodeCall方法和ast.ts文件里面的createVNodeCall方法对应后者用来返回VNodeCall前者生成对应的VNodeCall这部分render方法字符串是整个render方法字符串的核心。节点类型NodeTypes.FOR对应for关键字元素节点其内部是递归调用了genNode方法。节点类型NodeTypes.TEXT对应文本元素节点负责静态文本的生成。节点类型NodeTypes.JS_FUNCTION_EXPRESSION对应方法调用节点负责方法表达式的生成。 终于经过一系列的加工最终生成的render方法字符串结果如下所示 (function anonymous( ) { const _Vue Vue const { createElementVNode: _createElementVNode } _Vueconst _hoisted_1 [data-a] // 静态节点 const _hoisted_2 /*#__PURE__*/_createElementVNode(p, null, 123, -1 /* HOISTED */)// 静态节点return function render(_ctx, _cache) {// render方法with (_ctx) {const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } _Vue // helper方法return (_openBlock(), _createElementBlock(_Fragment, null, [_createElementVNode(div, { data-a: attr }, _toDisplayString(name), 9 /* TEXT, PROPS */, _hoisted_1),_hoisted_2], 64 /* STABLE_FRAGMENT */))} } })_createElementVNode_openBlock等等上一步传进来的helper方法。其中p123/p这种属于没有响应式绑定的静态节点会被单独区分而对于动态节点会使用createElementVNode方法来创建最终这两种节点会进入createElementBlock方法进行VNode的创建。 render方法中使用了with关键字with的作用如下代码所示 const obj {a:1 } with(obj){console.log(a) // 打印1 }在with(_ctx)包裹下我们在data中定义的响应式变量才能正常使用例如调用_toDisplayString(name)其中name就是响应式变量。 得到最终VNode对象 最终这是一段可执行代码会赋值给组件Component.render方法上其源码在packages\runtime-core\src\component.ts中如下所示 ... Component.render compile(template, finalCompilerOptions) ... if (installWithProxy) { // 绑定代理installWithProxy(instance) } ...compile方法是最初baseCompile方法的入口在完成赋值后还需要绑定代理执行installWithProxy方法其源码在runtime-core/src/component.ts中如下所示 export function registerRuntimeCompiler(_compile: any) {compile _compileinstallWithProxy i {if (i.render!._rc) {i.withProxy new Proxy(i.ctx, RuntimeCompiledPublicInstanceProxyHandlers)}} }这主要是给render里_ctx的响应式变量添加绑定当上面render方法里的name被使用时可以通过代理监听到调用这样就会进入响应式的监听收集track当触发trigger监听时进行diff。 在runtime-core/src/componentRenderUtils.ts源码里的renderComponentRoot方法里会执行render方法得到VNode对象其核心代码如下所示 export function renderComponentRoot(){// 执行renderlet result normalizeVNode(render!.call(proxyToUse,proxyToUse!,renderCache,props,setupState,data,ctx))...return result }demo代码中最终得到的VNode对象如下图所示。 上图就是通过render方法运行后得到的VNode对象可以看到children和dynamicChildren区分前者包括了两个子节点分别是div和p这个和在template里面定义的内容是对应的而后者只存储了动态节点包括动态props即data-a属性。同时VNode也是树状结构通过children和dynamicChildren一层一层递进下去。 在通过render方法得到VNode的过程也是对指令插值表达式响应式数据插槽等一系列Vue语法的解析和构造过程最终生成结构化的VNode对象可以将整个过程总结成流程图便于读者理解如下图所示。 另外一个需要关注的属性是patchFlag这个是后面进行VNode的diff时所用到的标志位数字64表示稳定不需要改变。最后得到VNode对象后需要转换成真实的DOM节点这部分逻辑是在虚拟DOM的diff中完成的
http://www.zqtcl.cn/news/94031/

相关文章:

  • 新材建设局网站百度提问首页
  • 网站优化网站建设栅格布局 网站设计
  • 网站建设销售前景网站手机开
  • 网站建站 用户注册北京网站建设方案报价
  • jsp做网站 案例网站模板 招聘
  • 德州建设银行兑换网站服务器网站跳转怎么做的
  • 金华专业做网站公司湖南网站建设服务
  • 企业网站设计沈阳苏宁电器网站建设特点分析
  • 建设工程类公司网站易语言可以做api网站对接吗
  • 青岛做网站皆赴青岛博wordpress 数据库 备份
  • 外贸公司网站空间哈尔滨seo优化专注
  • 建筑行业综合查询平台优化推广联盟
  • 北京管庄网站建设公司开平网站制作
  • 如何做销售直播网站最专业网站建设
  • 太原市住房和城乡建设局的网站首页网络推广服务外包公司
  • 湘icp备 网站建设 农业 湖南稿定设计免费版
  • 公司网站推广方法陕西省住房建设厅官网
  • 网站关键词排名突然没了无锡企业网站建设报价
  • 找做网站的人网站改版 301跳转
  • 网站备案一次就可以了吧营销管理培训课程
  • 怎么做网站背景专做民宿预定的网站
  • wordpress安装谷歌分析代码建网站seo
  • 百度外卖网站建设与维护方法建设 银行网网站
  • 小程序开发定制开发上海优化价格
  • 来宾住房和城乡建设局网站做外贸推广要做哪些平台
  • 无锡建设网站制作wordpress 知乎
  • 动漫网站源码免费怎么怎么做网站
  • 和两个黑人同时做网站中工互联网站建设
  • windows10PHP 网站建设app应用分发平台开发
  • 中唯建设工程有限公司网站做网站页面对PS切图