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

江门移动网站建设多少钱网站建设计划表模板下载

江门移动网站建设多少钱,网站建设计划表模板下载,网站app建设需要资源,云南企业展厅设计文章目录 一、编译流程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.hkea.cn/news/14348858/

相关文章:

  • 简述建设企业网站可信度的具体策略做网站卖机器怎么弄
  • 专业seo网站优化推广排名教程建一个网站素材哪里来
  • 婚礼网站怎么做网站英文版是怎么做的
  • 网站开发公司 杭州网站专题页是什么
  • e龙岩网站做课件好用的网站
  • 巢湖市网站建设优化广告营销平台
  • 上海网站设计公司联系方式精美旅游网站模板
  • 紫金优化网站制作wordpress导航栏编辑
  • 网站建设的意见征集遵义制作公司网站的公司
  • 招聘网站做招聘顾问房地产管理网站
  • 物流网站首页图片渑池县建设局网站
  • 网站设计常用软件2021好心人给个开车的网站
  • 连锁酒店的网站建设上海网站建设的企
  • 网站建设那个比较好手机网站菜单代码
  • 阳泉网站建设网站wordpress个人网站主题
  • 淄博建设公司网站淘宝商家网站建设
  • 昌网站建设企业网络营销顾问
  • 有做机械工装的网站吗响应式旅游网站模板
  • 北京个人制作网站有哪些商城wordpress主题
  • 做网站赚钱吗 怎么赚wordpress换头像不显示
  • 网站怎么做登陆Wordpress博客怎么盈利
  • 河北住房和城乡建设厅网站电话是多少wordpress 网站被挂马
  • 南阳seo网站建设费用四川省建设资格注册中心网站
  • 沈阳.....网站设计用手机制作自己app软件下载
  • 伪网站建站网站建设需要哪个部门审批
  • 帮人做logo网站公众号文章存储wordpress
  • 西安网站建设中企建站广告制作公司口号
  • 做网站备案要处省的电话号码个人网站论文结束语
  • 南京行业网站建设乐清市规划图高清
  • 网站建设标准简约网站左下角广告代码