Vue原理:compileToFunction核心流程及parseHTML中常用的正则

这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战

Vue的渲染流程中,若是用户没有传递render函数,则需要通过template或者el的DOM结构编译处理生成render函数,生成render函数是一项繁杂且重要的事情,其主要做的事情就是将模版编译为AST,基于AST进行操作生成虚拟DOM,最终返回需要的render函数

得到compileToFunction函数的核心流程

export function compileToFunction(template) {
  // 1. 解析HTML 生成AST
  const ast = parseHTML(template);
  // optimize(ast, options)

  // 2. 根据 AST 生成 render函数
  const { render } = generator(ast);

  // render 返回的是虚拟DOM
  return {
    ast,
    render,
  };
}
复制代码

可以看到将模版转换为render函数的过程并不复杂,并没有想象的那么多操作,接下来便根据核心流程继续

第一步需要做的是将HTML编译生成AST,在Vue中采用的是通过正则匹配解析模板生成最终需要的AST,在开始parseHTML函数之前,有必要对其中使用的一些正则表达式进行了解,知道大致使用了哪些正则,每个正则做了什么事情

解析HTML元素

匹配解析html,最常用的正则便是可以解析标签,html元素的标签大多数是正对出现的:开始标签和结束标签(闭合标签),也存在img这类不存在结束标签的单标签。在vue中肯定存在组件,那么对于组件这类的编写方式也需要匹配

用于匹配html元素,例如:div、span这类,也可以匹配自定义组件,例如:el-button、el-input-number这类

const unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/;
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z${unicodeRegExp.source}]*`;
复制代码

匹配命名空间标签,例如:<div:name></div>会将div:name匹配

const qnameCapture = `((?:${ncname}\\:)?${ncname})`; // <asd:asd>
复制代码

有了上述的正则,便可以开始快乐的匹配开始标签和结束标签了

const startTagOpen = new RegExp(`^<${qnameCapture}`); // 标签开头的正则 捕获的内容是标签名
const startTagClose = /^\s*(\/?)>/; // 匹配标签结束的 >
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`); // 匹配标签结尾的 </div>
复制代码

属性

用于配置html标签上的属性

const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/; 
复制代码

用于匹配当前是否存在属性,并取出键值

const temp = `class="btn-blue"`;
const attr = temp.match(attribute);
复制代码

若是attr有值,则表示存在属性,然后便可以将属性取出

const name = attr[1]; // class
const value = attr[3] || attr[4] || attr[5]; // btn-blue
复制代码

注释

代码中经常会添加注释(虽然很多人不在HTML中写注释),需要将注释进行匹配处理

const comment = /^<!\--/;
const conditionalComment = /^<!\[/;
复制代码

上述的这些便是在解析HTML生成AST时需要的正则表达式

猜你喜欢

转载自juejin.im/post/7031727693729103880