浏览代码

浏览器怪癖讲解,编译器选项讲解

HcySunYang 7 年之前
父节点
当前提交
1f1f48a0c4
共有 2 个文件被更改,包括 81 次插入2 次删除
  1. 8 2
      note/7创建编译器.md
  2. 73 0
      note/附录/web-util.md

+ 8 - 2
note/7创建编译器.md

@@ -181,9 +181,9 @@ export function createCompileToFunctionFn (compile: Function): Function {
 
 #### 
 
-经过前面的讲解,我们已经知道了 `entry-runtime-with-compiler.js` 文件中调用的 `compileToFunctions` 的真正来源,可以说为了创建 `compileToFunctions` 函数经历了一波三折,现在大家也许会有疑问,比如为要弄的这么复杂?我们暂时把这个疑问放在心里,随着我们的深入,大家将会慢慢理解其内涵。
+经过前面的讲解,我们已经知道了 `entry-runtime-with-compiler.js` 文件中调用的 `compileToFunctions` 的真正来源,可以说为了创建 `compileToFunctions` 函数经历了一波三折,现在大家也许会有疑问,比如为什么要弄的这么复杂?我们暂时把这个疑问放在心里,随着我们的深入,大家将会慢慢理解其内涵。
 
-这个小节我们就以 `entry-runtime-with-compiler.js` 文件中调用的 `compileToFunctions` 开始,仔细探索其所做的事情,打开 `entry-runtime-with-compiler.js` 文件找到这段代码:
+这个小节我们就以 `entry-runtime-with-compiler.js` 文件中调用的 `compileToFunctions` 开始,去探索其背后所做的事情。打开 `entry-runtime-with-compiler.js` 文件找到这段代码:
 
 ```js
 const { render, staticRenderFns } = compileToFunctions(template, {
@@ -205,6 +205,12 @@ const { render, staticRenderFns } = compileToFunctions(template, {
 }
 ```
 
+其中 `shouldDecodeNewlines` 和 `shouldDecodeNewlinesForHref` 这两个变量来自于 `platforms/web/util.js` 文件,大家可以在附录 [platforms/web/util 目录下的工具方法全解](/note/附录/web-util) 中查看这两个变量的作用,其目的是对浏览器的怪癖做兼容,具体在附录中都有讲到,并且这两个变量的类型都是布尔值。
+
+对于 `options.delimiters` 和 `options.comments`,其中 `options` 就是当前 `Vue` 实例的 `$options` 属性,并且 `delimiters` 和 `comments` 都是 `Vue` 提供的选项。所以这两只是简单的将这两个选项透传了过去。
+
+另外 
+
 
 
 

+ 73 - 0
note/附录/web-util.md

@@ -108,6 +108,79 @@ return (
 
 #### compat.js 文件
 
+`compat.js` 文件的全部代码如下:
+
+```js
+import { inBrowser } from 'core/util/index'
+
+// check whether current browser encodes a char inside attribute values
+let div
+function getShouldDecode (href: boolean): boolean {
+  div = div || document.createElement('div')
+  div.innerHTML = href ? `<a href="\n"/>` : `<div a="\n"/>`
+  return div.innerHTML.indexOf('&#10;') > 0
+}
+
+// #3663: IE encodes newlines inside attribute values while other browsers don't
+export const shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false
+// #6828: chrome encodes content in a[href]
+export const shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false
+```
+
+该文件主要导出两个变量,分别是 `shouldDecodeNewlines` 和 `shouldDecodeNewlinesForHref`,这两个变量都是布尔值,那么这两个变量是干嘛的呢?我们看一个例子就知道了,假设我们有如下 DOM:
+
+```html
+<div id="link-box">
+  <!-- 注意 href 属性值,链接后面加了一个换行 -->
+  <a href="http://hcysun.me
+  ">aaaa</a>
+  <!-- 注意 href 属性值,链接后面加了一个Tab -->
+  <a href="http://hcysun.me	">bbbb</a>
+</div>
+```
+
+上面的 DOM 看上去貌似没有什么奇特地方,关键点在于 `<a>` 标签的 `href` 属性,我们在第一个 `<a>` 标签的 `href` 属性值后面添加了换行符,在第二个 `<a>` 标签的 `href` 属性值后面添加了制表符。那么这么做会有什么影响呢?执行下面的代码就显而易见了:
+
+```js
+console.log(document.getElementById('link-box').innerHTML)
+```
+
+上面的代码中我们打印了 `id` 为 `link-box` 的 `innerHTML`,如下图:
+
+![](http://ovjvjtt4l.bkt.clouddn.com/2017-11-15-123008.jpg)
+
+注意,只有在 `chrome` 浏览器下才能获得如上效果,可以发现,在获取的内容中换行符和制表符分别被转换成了 `&#10` 和 `&#9`。实际上,这算是浏览器的怪癖行为。在 `IE` 中,不仅仅是 `a` 标签的 `href` 属性值,任何属性值都存在这个问题。这就会影响 `Vue` 的编译器在对模板进行编译后的结果,导致莫名奇妙的问题,为了避免这些问题 `Vue` 需要知道什么时候要做兼容工作,这就是 `shouldDecodeNewlines` 和 `shouldDecodeNewlinesForHref` 这两个变量的作用。
+
+下面我们看一下具体实现,首先定义了一个函数 `getShouldDecode`:
+
+```js
+let div
+function getShouldDecode (href: boolean): boolean {
+  div = div || document.createElement('div')
+  div.innerHTML = href ? `<a href="\n"/>` : `<div a="\n"/>`
+  return div.innerHTML.indexOf('&#10;') > 0
+}
+```
+
+该函数的作用是判断当前浏览器是否会对属性值中所包含的换行符进行编码,如果是则返回真,否则返回假。其实现原理分三步:
+
+* 1、创建一个 `div`
+* 2、设置这个 `div` 的 `innerHTML` 为 `<a href="\n"/>` 或者 `<div a="\n"/>`
+* 3、获取该 `div` 的 `innerHTML` 并检测换行符是否被编码
+
+`getShouldDecode` 接受一个布尔值参数 `href`,如果该参数为 `true` 意味着要监测的是 `a` 标签的 `href` 属性,否则检测任意属性。
+
+有了上面的函数再实现 `shouldDecodeNewlines` 和 `shouldDecodeNewlinesForHref` 这两个变量就容易多了:
+
+```js
+export const shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false
+export const shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false
+```
+
+最终如果 `shouldDecodeNewlines` 为 `true`,意味着 `Vue` 在编译模板的时候,要对属性值中的换行符或制表符做兼容处理。而 `shouldDecodeNewlinesForHref` 为 `true` 意味着 `Vue` 在编译模板的时候,要对 `a` 标签的 `href` 属性值中的换行符或制表符做兼容处理。当然,一切都是以在浏览器中为前提的,因为上面的代码中存在一个 `inBrowser` 的判断。
+
+最后再啰嗦一句,为什么只在浏览器中才需要判断是否需要做此兼容处理呢?那是因为,只有完整版(包括编译器)的 `Vue`才会遇到这个问题,因为只有完整版的 `Vue` 才会在浏览器中对模板就行编译,才有可能在获取模板的时候使用 `innerHTML` 获取模板内容。
+
 #### element.js 文件
 
 ##### isHTMLTag