1.Vue與模板
vue是如何使用的:
- 編寫頁面模板
- 創建Vue實例
- 在Vue構造函數中提供:data、methods、computed...
- 將Vue掛載到頁面中(mount)
下面是一個代碼實例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <!-- 第一步:寫模板 --> <div id="root"> <h1>姓名:{{name}}——年齡:{{age}}</h1> </div> <script> // 第二步:創建Vue實例 let app=new Vue({ el:'#root', data:{ name:'xxx', age:14 } }) // 第三步:掛載。這種用法的掛載在vue.js中幫我們實現了 </script> </body> </html>
2.數據驅動模型
Vue的執行流程:
- 獲得模板:模板中有預留的坑(如{{}}、:等)
- 利用Vue構造函數中所提供的數據來填補預留的坑,就可以在頁面上顯示標簽 了
- 將標簽替換頁面中原來有坑的標簽
Vue利用我們提供的數據和頁面中的模板,生成了一個新的HTML標簽,替換到了頁面中放置模板的位置。
比如:在上面那個例子中打印那個root標簽:
<script> console.log(root); let app=new Vue({ el:'#root', data:{ name:'xxx', age:14 } }) console.log(root); </script>
控制台結果:
- 此時如果將鼠標懸浮在第二次打印的root上面,頁面上會高亮表示選中的是當前的標簽
- 但是將鼠標懸浮在第一次打印的結果上沒有高亮,表明創建Vue實例之后的root的標簽已經不是頁面剛加載時的那個標簽了
3.一個簡單的模板填充數據的實例:
這個部分的作用是把頁面模板上帶有花括號的內容全部替換成具體的數據:<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 第一步:寫模板 --> <div id="root"> <div> <div> <h1>姓名:{{name}}——年齡:{{age}}</h1> </div> </div> <h2>姓名:{{name}}</h2> <h2>年齡:{{age}}</h2> </div> <script> let r = /\{\{(.+?)\}\}/g /** * 步驟拆解: * 1.拿到模板 * 2.拿到數據(data) * 3.將數據與模板結合,得到的是HTML元素(DOM元素) * 4.放到頁面中 * */ // 1 let tempNode = document.getElementById('root') // 2 let data = { name: 'xlx', age: 26 } // 3.將數據放到模板中:一般都是使用遞歸 // 在這個案例中,template是一個DOM元素 // 在真正的VUe源碼中是將DOM元素轉換成字符串模板 -> 轉換成抽象語法樹 -> 轉換成虛擬DOM(VNode) -> 轉換成真正的DOM function compiler(template, data) { // 這個函數,把花括號里面的數據用data里面所對應的屬性進行替換 // 把子元素中所有帶雙花括號的元素取出來 let childNodes = template.childNodes // 取出子元素 for (let i = 0; i < childNodes.length; i++) { let type = childNodes[i].nodeType // nodeType表示這個節點的類型:1表示元素節點;3表示文本節點(不同瀏覽器不同,這里只需要記住這兩個) if (type === 3) { // 文本節點,可以判斷里面是否有 {{}} 插值 let txt = childNodes[i].nodeValue // nodeValue該屬性只有文本節點才有意義 // 有沒有{{}}呢 txt = txt.replace(r, function (_, g) { // replace方法,使用正則匹配了一次,這個函數就會被調用一次。return的值就是替換的匹配到的值 // 參數一:表示匹配到的內容 // 參數二:表示正則中的第n組:g.trim()表示寫在雙花括號里面的東西 let key = g.trim(); let value = data[key] // 將{{ xxx }}用這個值(data中對應的值)替換 return value }) // 注意:txt現在和DOM元素是沒有關系的,需要將修改后的值放回去 childNodes[i].nodeValue = txt } else if (type === 1) { // 元素節點,考慮有沒有子元素,是否需要將其子元素進行判斷是否要插值 compiler(childNodes[i], data) // 遞歸處理 } } } // 我們此時是沒有生成新的template,所以這里看到的是直接在頁面中就更新的數據,因為DOM是引用類型 // 但是我們這么處理的話,原來帶{{}}的模板就沒有了。無法再更新了
// 利用模板生成一個需要被渲染的HTML標簽(准·真正在頁面中顯示的標簽) let generateNode = tempNode.cloneNode(true) // 注意這里是DOM元素,可以直接這么用 console.log(1, tempNode); compiler(generateNode, data) console.log(2, generateNode); // 4.將渲染好的HTML加到頁面當中 root.parentNode.replaceChild(generateNode, root) // 到此為止:上面的思路有比較大的問題 // 1.Vue使用的是虛擬DOM,而這里用的是真實的DOM // 2.只考慮了單屬性{{ name }},而Vue中大量的使用了層級({{ child.name }}) // 3.代碼沒有整合 </script> </body> </html>
頁面結果如下:
說明:這個實現的大致理論: