vue原理20181211

1. 打开浏览器从输入网址到网页呈现出来,经历了什么?
打开浏览器从输入网址到网页呈现出来,经历了什么?
1.1 DNS解析域名
1.2 TCP连接:TCP三次握手
1.3 发送HTTP请求
1.4 服务器处理请求并返回HTTP报文
1.5 浏览器解析渲染页面
1.6 断开连接: TCP四次挥手


1.网址 URL(Uniform Resource Locator)
  格式:scheme://host.domain:port/path/filename
    scheme:      http/https/ftp
    host   主机   http 的默认主机是 www
    domain 域名   baidu.com
    port   端口   http 的默认端口号是 80

2.IP 地址,32位的二进制数

3.DNS解析:将域名解析成IP地址     baidu.com  220.114.33.55
    浏览器并不能直接通过域名找到对应的服务器,而是要通过 IP 地址。
    查找域名和IP的对应记录:从浏览器缓存、操作系统缓存、路由器缓存、ISP的DNS服务器、根服务器依次查找记录
    根服务器进行递归查询:从查.cn 再查 .com.cn 再查 baidu.com.cn 再查 www.baidu.com.cn

4.TCP三次握手:
    第一次握手:浏览器发送数据包到服务器端口,告诉浏览器要发送请求了
    第二次握手:服务器发送响应包以传达确认信息,告诉浏览器可以发送了
    第三次握手:浏览器再发数据包告诉服务器,马上要发了,准备接受

5.http请求
    TCP 三次握手结束后,开始发送 HTTP 请求报文。
    请求报文由请求行(request line)、请求头(header)、请求体四个部分组成

    请求行包含请求方法(get post)、URL、协议版本(http版本号)
        example: POST  /chapter17/user.html HTTP/1.1
    请求头是键值对
    请求体 example: name=kang

6. http响应报文
    响应报文由响应行(request line)、响应头部(header)、响应主体三个部分组成
    响应行包含:协议版本,状态码,状态码描述
    状态码 200 404 500

7. 浏览器渲染机制
    根据 HTML 解析出 DOM 树
    根据 CSS 解析生成 CSS 规则树
    结合 DOM 树和 CSS 规则树,生成渲染树
    根据渲染树计算每一个节点的信息(布局)
    根据计算好的信息绘制页面(paint)

    解析DOM树时,遇到script标签,会等脚本先执行
    解析CSS树时,js执行会暂停,
    精简 CSS 并可以加快 CSS 规则树的构建,从而加快页面相应速度
    重绘:绘制页面时,某元素颜色等(不影响其他元素布局的属性)发生变化
    回流:绘制页面时,某元素尺寸发生变化,要重新计算渲染树,重新渲染

8. 断开tcp连接,发起tcp四次挥手
    第一次挥手:浏览器发送给服务器,表示请求报文已发完,你可以关闭了
    第二次挥手:服务器发给浏览器,请求报文接收完,准备关闭
    第三次挥手:服务器发给浏览器,响应报文发送完,你准备关闭
    第四次挥手:浏览器发给服务器,响应报文完了,准备关闭

HTTP 请求阶段,HTTP 请求分为三个部分:TCP 三次握手、http 请求响应信息、关闭 TCP 连接。

浏览器向dns服务器发送域名,DNS服务器查询并返回IP地址,浏览器再发送到对应服务器请求数据

参考链接:https://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651555392&idx=1&sn=9042c990f82fe5d03f03e6af7536b4c3&chksm=80255181b752d897524a6f1ee332f245761c89a5e01d0cbf0499e3a74a21f3865f8cfff823cf&mpshare=1&scene=1&srcid=1126MqCAj6jUV3jqGvxxDNAF#rd
View Code

【以下为vue实现原理相关知识点】 

2. document.createDocumentFragment()     fragment 文档片段,存于内存中,不在DOM树,性能好   例子来自 mdn

/**
 *  document.createDocumentFragment()
 *  DocumentFragments 是DOM节点
 *  创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树。
 *  因为文档片段存在于内存中,并不在DOM树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段通常会带来更好的性能。
 */
function fragment () {

  var element = document.getElementById('ul') // assuming ul exists
  var fragment = document.createDocumentFragment()   // 存于内存,不在DOM树,性能好
  var browsers = ['Firefox', 'Chrome', 'Opera',
    'Safari', 'Internet Explorer']

  browsers.forEach(function (browser) {
    var li = document.createElement('li')
    li.textContent = browser
    fragment.appendChild(li)    // 先追加到 fragment
  })

  element.appendChild(fragment)  // 再追加到dom节点
}

fragment()
View Code

 3.nodeType     1是元素   3是文本

function nodeType () {
  var p = document.createElement("p");
  p.textContent = "很久很久以前...";

  console.log(Node.ELEMENT_NODE === 1)  // p
  console.log(Node.TEXT_NODE === 3)    //  很久很久以前...

  console.log(p.nodeType === Node.ELEMENT_NODE) // true
  console.log(p.firstChild) // 很久很久以前...
  console.log(p.firstChild.nodeType === Node.TEXT_NODE) // true
}
View Code

 4.white循环 对比for循环

function whiteTest() {
  let arr = [1, 2, 3, 4, 5]
  let brr = []
  i = 0
  while (i < 3) {
    brr.push(arr[i])
    i++
  }
  console.log(brr) // [0,1,2]     for(var i =0;i<3;i++){ brr.push(arr[i])}
}
View Code

5.正则  * 0~多 + 1~多 ? 0~1 .匹配所有字符

/**
 * 正则     * 0~多  +  1~多   ? 0~1      .匹配所有字符
 * @param text
 * @returns {boolean}
 */
  function isReg (text) {
    let reg = /\{\{(.*)\}\}/    //  * 0~多  +  1~多   ? 0~1      .匹配所有字符
    return reg.test(text)
  }

  console.log(isReg('{{}}'))   // true
  console.log(isReg('{{.gfg}}')) // true
  console.log(isReg('{{.g}}'))  // true
View Code

6. node节点操作 firstChild    节点不要出现换行等

<p id="para-01">
    <span>First span</span>
</p>

<script type="text/javascript">
    /*
    * 在<p>标签和<span>标签之前,有一个换行符和多个空格充当了一个文本节点,导致 结果为 #text
    * 操作node节点不要出现空格
    * */
  var p01 = document.getElementById('para-01');
  console.log((p01.firstChild))   // #text 大对象
  console.log((p01.firstChild.nodeName))   // #text
</script>
View Code
<p id="para-012"><span>First span</span></p>

<script type="text/javascript">
  var p012 = document.getElementById('para-012');
  console.log((p012.firstChild))    // <span>First span</span>
  console.log((p012.firstChild.nodeName))  // SPAN
  console.log((p012.firstChild.firstChild.nodeValue))  // First span
  console.log((p012.firstChild.innerHTML))  // First span

</script>
View Code

7. li 标签转换成数组操作  也可以用 for 来解决  [].slice.call($Li).forEach(val=>{})

    /*
    * 原数组的浅拷贝 slice()
    *   arr.slice();
        // [0, end]

        arr.slice(begin);
        // [begin, end]

        arr.slice(begin, end);
        // [begin, end)

        [].slice.call($li)  // li标签复制一份,转换为数组调用 forEach
    * */

    let $li = document.getElementsByTagName('li')
    console.log($li)
    for(var i=0;i<$li.length;i++){
      console.log($li[i].firstChild.nodeValue)
      console.log($li[i].innerHTML.replace(/^abc/, ''))
    }
    console.log('-------');
    console.log('dd',[].slice.call($li));
    [].slice.call($li).forEach(val=>{
      val.innerHTML=val.innerHTML.replace(/^abc/,'')
    })
View Code

 8. 对象的 for循环   Object.keys(obj).forEach(key=>{})     同时拿到 obj  key val 

let obj = {
  name:'kang',
  age:12,
  date:{
    y:2018,
    m:12,
    d:13
  }
}
Object.keys(obj).forEach(key=>{
  console.log(obj)
  console.log(key)
  console.log(obj[key])
})
View Code

 9.Object.defineProperty()     对象监听

let obj = {name: 'kang', age: 12, date: {y: 12}}

observe(obj)
obj.name = 'jia'
obj.age = 20
obj.date.y = 11
for (var i in obj) {    //  enumerable 为false时,无法使用 for...in 和 object.keys()
  // console.log('df',i)
}

var o = {  // 用这个方式时,enumerable为 true  可用 for...in
  d: 1
}

/**
 * 监听对象
 * @param obj
 */
function observe (obj) {
  if (!obj || typeof obj !== 'object') return

  // 遍历所有对象
  Object.keys(obj).forEach(key => {
    // obj 原对象
    // key : name age    date
    // obj[key]: kang 12 {y:12}
    // obj[key] 有可能是个对象,所以要再递归
    listen(obj, key, obj[key])
  })
}

/**
 * Object.defineProperty  监听属性变动
 * @param data
 * @param key
 * @param val
 */
function listen (data, key, val) {
  observe(val)  // 递归   先把递归注释掉容易理解点
  // Obeject.defineProperty() 来监听属性变动
  Object.defineProperty(data, key, {
    enumerable: true, // 可枚举  默认为false enumerable定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。
    get: function () {
      return val
    },
    set: function (newVal) {
      if (val === newVal) return
      console.log('监听到新值了', val, '->', newVal)
      val = newVal
    }
  })
}
View Code

 10. node节点操作  node.firstChild   childNodes textContent  nodeType attributes

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <input type="text" v-model="someStr">
    <p>{{getHelloWord}}</p>
    <p v-html="htmlStr"></p>
    <button v-on:click="clickBtn">change model</button>
</div>

<script>
  let $el = document.querySelector('#app')
  let $fragment = node2Fragment($el)   // 转成 文档碎片,在DOM上不会显示出来
  $el.appendChild($fragment)

  // console.log($el.textContent)  // 返回该元素下所有文本节点  {{getHelloWord}} change model

  function node2Fragment ($el) {
    let fragment = document.createDocumentFragment()
    while ($el.firstChild) {
      // console.log($el.firstChild)    // #text  <input type=...>  #text  <p>{{...  #text  <p v...>  #text <button...> #text
      //  两个标签之间的空格换行解析成 #text 文本节点
      fragment.appendChild($el.firstChild)
    }
    // 方式二
    /* for(;$el.firstChild;){   // for 三个条件可以省略第一个,第三个(可能写在for前面、for里面),只要能够执行
       fragment.appendChild($el.firstChild)
     }*/

    // 方式三 最好理解
    /*     ;[].slice.call($el.childNodes).forEach(node=>{
           fragment.appendChild(node)
         })*/
    return fragment
  }

  /*
  * https://developer.mozilla.org/en-US/docs/Web/API/Node
  *
  * node.firstChild  返回第一个child node or null
  * node.childNodes  返回nodeList 包含所有 children 如果children变了,nodeList会自动更新
  * node.textContent 返回或者设置元素及其子元素的所有文本节点  空格部分为 ''
  * node.nodeType   1 是元素ELEMENT_NODE <div>...</div>    3 是文本TEXT_NODE   #text
  * */

  // console.log($el.firstChild)   // #text   只拿到第一个空格部分
  // console.log($el.childNodes);  //  NodeList[text,input,text,p,text,p,text,button,text]  空格解析为text
  ;[].slice.call($el.childNodes).forEach(node => {
    // console.log(node)  //               #text         <input type='text' v-model='somestr'>     #text
    // console.log(node.textContent)   //   ''            {{getHelloWord}}      change model           ''
    // console.log(node.nodeType)         //    3                   1                                3
    // console.log(node.attributes)         //  undefined           NameNodeMap{}                  undefined

    if (node.nodeType === 1) {   // 处理元素节点  <div class='a'>...</div>
      elementNode(node)
    } else if (node.nodeType === 3) {  // 处理 {{xx}}
      let reg = /\{\{.*\}\}/
      let text = node.textContent
      console.log(text)
      if (reg.test(text)) {

        console.log(node)
      }
    }
  })

  /*
  * DOM1级主要定义的还是HTML的地层结构,DOM2和DOM3级则在这个结构的基础上引入了更多的交互能力
  *
  * node.attributes  DOM4 删除该属性,目前还是DOM2 DOM3   元素节点属性
  *
  *
  *
  *
  * */
  function elementNode (node) {
    var nodeAttr = node.attributes
    ;[].slice.call(nodeAttr).forEach(attr => {
      var attrName = attr.name
      // console.log(attr)   // type='text' v-model='someStr' 等
      // console.log(attr.name) // type v-model 等
      // console.log(attr.value)   // text someStr
    })
  }
</script>
</body>
</html>
View Code

 【暂停】

2-10为vue双向绑定原理知识点 

教程  https://segmentfault.com/a/1190000006599500#articleHeader3

源码: https://github.com/gyz418/mvvm

 

posted @ 2018-12-11 15:42  gyz418  阅读(190)  评论(0编辑  收藏  举报