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

pc网站制作APP西双版纳傣族自治州天气

pc网站制作APP,西双版纳傣族自治州天气,百度seo排名帝搜软件,html编辑器汉化版apk文章目录 一、编译流程1. 解读入口文件 packgages/vue/index.ts2. compile函数的运行流程 二、AST 解析器1. ast 的生成2. 创建ast的根节点3. 解析子节点 parseChildren#xff08;关键#xff09;4. 解析模版元素 Element模版元素解析-举例分析 一、编译流程 1. 解读入口文… 文章目录 一、编译流程1. 解读入口文件 packgages/vue/index.ts2. compile函数的运行流程 二、AST 解析器1. ast 的生成2. 创建ast的根节点3. 解析子节点 parseChildren关键4. 解析模版元素 Element模版元素解析-举例分析 一、编译流程 1. 解读入口文件 packgages/vue/index.ts 首先从Vue对象的入口开始packgages/vue/index.ts文件中只有compileToFunction函数 依赖注入编译函数至runtimeregisterRuntimeCompiler(compileToFunction)runtime 调用编译函数compileToFunction返回包含code的编译结果将code作为参数传入Function 的构造函数将生成函数赋值给render变量。将render函数作为编译结果返回 下面这个简单的模版 templatedivHello World/div /template经过编译后code返回的字符串为 const _Vue Vue return function render(_ctx, _cache) {with(_ctx) {const {openBlock: _openBlock, createBlock:_createBlock} _Vue;return (_openBlock(), _createBlock(div, null, Hello World)) } }拿到这个代码字符串的结果后第25行声明了一个render变量并将生成的代码字符串code 作为参数传入了new Function 构造函数生成了render函数。可以将上面的code字符串格式化。这里的render显而易见是一个柯里化的函数返回了一个函数函数内部通过with来扩展作用域链。最后入口文件返回了render变量并顺手缓存了render函数。在第一行入口文件创建了一个compileCache 对象用以缓存compileToFunction 函数生成的render 函数将template 参数作为缓存的key并在11行进行if分支做缓存判断如果该模版之前被缓存过则不再进行编译直接返回缓存中的render函数以此提高性能。 2. compile函数的运行流程 compile函数涉及到compile-dom 和compile-core 两个模块。 compile的运行流程 baseCompile命名理由因为compile-core是编译的核心模块接收外部的参数来按照规则完成编译而compile-dom是专门处理浏览器场景下的编译在这个模块下导出的compile函数是入口文件真正接收的编译函数。而compile-dom中的compile函数相对baseCompile也是一个更高阶的编译器。例如当Vue在weex或iOS或Android这些Native App中工作时compile-dom可能会被相关的移动端编译库来取代。baseCompile函数 从函数声明中看baseCompile接收template模版以及上层高阶编译器处理过的options编译选项最终返回一个CodegenResult类型的编译结果。 export interface CodegenResult {code: stringpreamble: stringast: RootNodemap?: RawSourceMap }看上方源码的第12行判断template模版是否为字符串如果是的话则会对字符串进行解析否则直接将template作为AST。我们平时写的vue代码都是以字符串的形式传递进去的。然后是第16行调用了transform函数以及传入了指令转换、节点等工具函数对由模版生成的AST进行转换。最后32行将转换好的ast传入进generate生成CodegenResult类型的返回结果。 二、AST 解析器 1. ast 的生成 ast的生成有一个三目运算符的判断如果传进来的template模版是一个字符串那么则调用baseParse解析模版字符串否则直接将template作为ast对象。 baseParse 函数 export function baseParse(content: string,options: ParserOptions {} ): RootNode {const context createParserContext(content, options) // 创建解析的上下文对象const start getCursor(context) // 生成记录解析过程的游标信息return createRoot( // 生成并返回 root 根节点parseChildren(context, TextModes.DATA, []), // 解析子节点作为 root 根节点的 children 属性getSelection(context, start)) }首先会创建解析的上下文根据上下文获取游标信息由于还未进行解析所以游标中的column、line、offset属性对应的都是template的起始位置。之后就是创建根节点并返回根节点至此ast树生成解析完成。 2. 创建ast的根节点 export function createRoot(children: TemplateChildNode[],loc locStub ): RootNode {return {type: NodeTypes.ROOT,children,helpers: [],components: [],directives: [],hoists: [],imports: [],cached: 0,temps: 0,codegenNode: undefined,loc} }该函数返回了一个RootNode类型的根节点对象其中我们传入的children参数会被作为根节点的children参数。 3. 解析子节点 parseChildren关键 function parseChildren(context: ParserContext,mode: TextModes,ancestors: ElementNode[] ): TemplateChildNode[] {const parent last(ancestors) // 获取当前节点的父节点const ns parent ? parent.ns : Namespaces.HTMLconst nodes: TemplateChildNode[] [] // 存储解析后的节点// 当标签未闭合时解析对应节点while (!isEnd(context, mode, ancestors)) {/* 忽略逻辑 */}// 处理空白字符提高输出效率let removedWhitespace falseif (mode ! TextModes.RAWTEXT mode ! TextModes.RCDATA) {/* 忽略逻辑 */}// 移除空白字符返回解析后的节点数组return removedWhitespace ? nodes.filter(Boolean) : nodes }parseChildren函数接收三个参数context解析器上下文mode文本数据类型ancestors祖先节点数据。函数执行首先会从祖先节点中获取当前节点的父节点确定命名空间以及创建一个空数组用来存储解析后的节点。之后会有一个while循环判断是否到达了标签的关闭位置如果不是需要关闭的标签则在循环体内对源模版字符串进行分类解析。之后会有一段处理空白字符的逻辑处理完成后返回解析好的nodes数组。 while循环内的逻辑函数的核心 在while中会判断文本数据的类型只有当TextModes为DATA或RCDATA时会继续往下解析。 第一种情况就是判断是否需要解析Vue模版语法中的Mustache语法如果当前上下文中没有v-pre指令来跳过表达式并且源模版字符串是以我们指定的分隔符开头的就会进行双大括号的解析。接下来会判断如果第一个字符是并且第二个字符是! 会尝试解析注释标签!DOCTYPE和!CDATA这三种情况对于DOCTYPE会进行忽略解析成注释。之后会判断当第二个字符是/的情况/已经满足了一个闭合标签的条件了所以会尝试匹配闭合标签。当第三个标签是缺少了标签名字会报错并让解析器的进度前进三个字符跳过/。如果是/并且第三个字符是小写英文字符解析器会解析结束标签。如果源模版字符串的第一个字符是第二个字符是小写英文字符开头会调用parseElement函数来解析对应的标签。当这个判断字符串字符的分支条件结束并且没有解析出任何node节点则会将node作为文本类型调用parseText进行解析。最后将生成的节点添加进nodes数组在函数结束时返回。 while循环的源码如下 while (!isEnd(context, mode, ancestors)) {const s context.sourcelet node: TemplateChildNode | TemplateChildNode[] | undefined undefinedif (mode TextModes.DATA || mode TextModes.RCDATA) {if (!context.inVPre startsWith(s, context.options.delimiters[0])) {/* 如果标签没有 v-pre 指令源模板字符串以双大括号 {{ 开头按双大括号语法解析 */node parseInterpolation(context, mode)} else if (mode TextModes.DATA s[0] ) {// 如果源模板字符串的第以个字符位置是 !if (s[1] !) {// 如果以 !-- 开头按注释解析if (startsWith(s, !--)) {node parseComment(context)} else if (startsWith(s, !DOCTYPE)) {// 如果以 !DOCTYPE 开头忽略 DOCTYPE当做伪注释解析node parseBogusComment(context)} else if (startsWith(s, ![CDATA[)) {// 如果以 ![CDATA[ 开头又在 HTML 环境中解析 CDATAif (ns ! Namespaces.HTML) {node parseCDATA(context, ancestors)}}// 如果源模板字符串的第二个字符位置是 /} else if (s[1] /) {// 如果源模板字符串的第三个字符位置是 那么就是自闭合标签前进三个字符的扫描位置if (s[2] ) {emitError(context, ErrorCodes.MISSING_END_TAG_NAME, 2)advanceBy(context, 3)continue// 如果第三个字符位置是英文字符解析结束标签} else if (/[a-z]/i.test(s[2])) {parseTag(context, TagType.End, parent)continue} else {// 如果不是上述情况则当做伪注释解析node parseBogusComment(context)}// 如果标签的第二个字符是小写英文字符则当做元素标签解析} else if (/[a-z]/i.test(s[1])) {node parseElement(context, ancestors)// 如果第二个字符是 ?当做伪注释解析} else if (s[1] ?) {node parseBogusComment(context)} else {// 都不是这些情况则报出第一个字符不是合法标签字符的错误。emitError(context, ErrorCodes.INVALID_FIRST_CHARACTER_OF_TAG_NAME, 1)}}}// 如果上述的情况解析完毕后没有创建对应的节点则当做文本来解析if (!node) {node parseText(context, mode)}// 如果节点是数组则遍历添加进 nodes 数组中否则直接添加if (isArray(node)) {for (let i 0; i node.length; i) {pushNode(nodes, node[i])}} else {pushNode(nodes, node)} }4. 解析模版元素 Element parseElement精简源码如下 function parseElement(context: ParserContext,ancestors: ElementNode[] ): ElementNode | undefined {// 解析起始标签const parent last(ancestors)const element parseTag(context, TagType.Start, parent)// 如果是自闭合的标签或者是空标签则直接返回。voidTag例如 img, br, hrif (element.isSelfClosing || context.options.isVoidTag(element.tag)) {return element}// 递归的解析子节点ancestors.push(element)const mode context.options.getTextMode(element, parent)const children parseChildren(context, mode, ancestors)ancestors.pop()element.children children// 解析结束标签if (startsWithEndTagOpen(context.source, element.tag)) {parseTag(context, TagType.End, parent)} else {emitError(context, ErrorCodes.X_MISSING_END_TAG, 0, element.loc.start)if (context.source.length 0 element.tag.toLowerCase() script) {const first children[0]if (first startsWith(first.loc.source, !--)) {emitError(context, ErrorCodes.EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT)}}}// 获取标签位置对象element.loc getSelection(context, element.loc.start)return element }首先会获取当前节点的父节点再调用parseTag()函数解析。 parseTag()函数执行流程 匹配标签名解析元素中的attribute属性存储至props属性检测是否存在v-pre属性如果存在则修改context上下文中的inVPre属性为true。检测自闭合标签如果是自闭合则将isSelfClosing属性置为true。判断tagType是Element还是component组件或slot插槽。返回生成的element对象 获取到 element对象后会判断element是否是自闭合标签或空标签例如img、br、hr如果是这种情况直接返回element对象。然后解析element的子节点把element压入栈中然后递归调用parseChildren来解析子节点。 const parent last(ancestors) 在将element入栈后拿到的父节点就是当前节点。 解析完毕后调用ancestors.pop()让当前解析完子节点的element对象出栈将解析后的children对象赋值给element的children属性完成element的子节点解析。最后匹配结束标签设置element的Ioc位置信息返回解析完毕的 element 对象。 模版元素解析-举例分析 divpHello World/p /div
http://www.w-s-a.com/news/245731/

相关文章:

  • 用网站模板做网站动漫制作专业学校前十名
  • 网页 代码怎么做网站网站建设与维护课程设计
  • 网站制作哪家公司好企业名录联系电话
  • 做的网站怎么上传到网上wordpress图片之间空一行
  • 腾讯云建设网站视频vi报价单
  • 个人网站发布怎么做建设银行网站收款怎么打明细
  • 网站整体色调网站建设都有什么类型
  • 比较简洁大方的网站软件工程四大方向
  • 大家称赞的网站建设常德小学报名网站
  • 做网站怎么建文件夹百度网盘搜索神器
  • 企业有域名怎么做网站淘宝推广平台
  • 学网站开发去哪学药品销售推广方案
  • 哔哩哔哩h5播放器深圳网站seo外包公司哪家好
  • asp做的手机网站wordpress 文章title
  • 网站验证码目录wordpress内嵌播放器
  • 文明网网站建设南昌市建设规费标准网站
  • 安康有建网站的公司吗做网站用什么网名好
  • 济南网站制作哪家专业西安市城乡建设网官方网站
  • 网站建设有趣小游戏怎样让网站优化的方式
  • 昭通做网站儿童编程教学入门教程
  • eclipse静态网站开发软文广告投放平台
  • 网站建设教学视频济南做网站需要多少钱
  • 网站免费做软件市工商联官方网站建设方案
  • 网站建设大体包含英铭长沙网站建设
  • 网站建设培训学校北京如何搜索网站
  • discuz论坛模板哪些网站容易做seo优化
  • 渭南公司做网站网站建设互联网推广
  • 公司网站app怎么做杭州建设局网站
  • 网站开发需要自己写代码吗12306网站多少钱做的
  • 策勒网站建设四川建设网有限责任公司招聘