Vue#
- Vue 是一個專注於「網頁視圖層」的前端框架。
- Vue 是用 js 來操作某一註冊的視圖組件的框架。
- Vue 已經擁有許多優秀的特性。
<html>
<div id="app">{{message}}</div>
<script>
new Vue({
el: '#app',
data: {
message: 'hello world!'
}
})
</script>
</html>
以上為一個典型的最小 Vue 框架的 HTML
Vue 接受了 id 為 app 的整個 div 塊,而 Vue 將對此塊進行操作。
{{message}} 是 HTML 無法識別的語法,但是由於把整個 div 塊交給 Vue 處理,因此,Vue 可以識別即可。
週期圖#
一、創建階段(beforeCreate、created)#
created 前#
我們發現,在上面的 html 代碼中,我們使用了 "{{}}" 雙大括號語法模板語法,眾所周知,這在 html 中可是沒有這樣的語法的。再看看 new Vue 時傳入的 el: '#app' 參數。是的,我們將整個 id 為 app 的 div 交給了的 Vue 來管理,我們就是使用 Vue 對這個 id 為 app 的 div(專業點就是 DOM)操作來操作去的,故 vue 的文檔裡也有說:Vue 的核心庫只關注視圖層 。
所以,vue 在創建階段(created 前)就是將傳入的 div、data 以及 methods 等做初始化。
也就是說,做點準備工作
二、掛載階段(beforeMount、mounted):#
created 到 beforeMount 階段#
在 created 到 beforeMount 這個階段發生了一件很不得了的事情 ——Vue 將傳入的這個 id 為 app 的 div 轉化成了一個貌似高大上的東西,叫抽象語法樹(AST)。可又為什麼要轉化成抽象語法樹呢?
(哈哈,這個問題稍加思索一下便可得到答案,讀者可稍微暫停一下,再往下繼續看文章)
因為這樣 Vue 才能理解我們在 html 寫的雙大括號語法模板語法,以及在標籤裡添加的 v-bind,v-for,v-if,甚至是自定義標籤等等亂七八糟的東西,將我們上面寫的這個 id 叫 app 的 div——
<div id="app">
<p>
{{message}}
</p>
</div>
轉化成 AST 之後就會像這個樣子 ——
{
tag: "div",
type: 1,
staticRoot: false,
static: false,
plain: true,
parent: undefined,
attrsList: [],
attrsMap: {},
children: [
{
tag: "p",
type: 1,
staticRoot: false,
static: false,
plain: true,
parent: {
tag: "div",
type: 1,
staticRoot: false,
static: false,
plain: true,
parent: undefined,
attrsList: [],
attrsMap: {},
},
attrsList: [],
attrsMap: {},
children: [
{
type: 2,
text: {{message}},
static: false,
expression: "_s(message)"
}
]
}
]
}
我們可以看到,這個所謂的抽象語法樹(AST)也就是一個 js 對象而已,在這個 js 對象裡包含了所有需要用到的各種信息。
Vue 將這麼一轉化,js 操作這些變量不是輕輕鬆鬆,就可以將雙大括號裡的變量換成 data 裡的數據啦。
beforeMount 到 mounted 階段#
可瀏覽器根本讀不懂這個 AST 啊,所以 Vue 在 beforeMount 到 mounted 這個階段就是將 AST 再轉化為 html 代碼,也就是說,到 mounted 完成後
模板語法
<div id="app">
<p>
{{message}}
</p>
</div>
已經變成了
<div id="app">
<p>
Hello world!
</p>
</div>
三、掛載完畢(beforeUpdate、updated):#
到這,久聞大名的虛擬 DOM 終於出場了。
我們可以先看看虛擬 DOM 大概長什麼樣子 ——
{
tag:'div', // 元素標籤
attrs:{ // 屬性
id:'app'
}
children:[
{tag:'p',...} // 子元素
]
}
(可以看到,也是個 js 的對象,通過鍵和值描述節點,但可千萬不能認為這和 AST 沒兩樣,這是兩個不同階段的產物)
然後再想想我們為什麼需要虛擬 DOM—— 現代網頁程序在運行時,狀態會不停的發生變化,有可能是用戶點擊了按鈕,有可能是發送了一次 axios 請求,這些行為都是異步的。每當狀態發生某些改變時,就會需要重新渲染
難道每次發生變化了都把整個 DOM 刪掉然後重新渲染一份出來嗎?
我們看看真實 DOM 的體量 ——
一個 div 元素就這麼多東西,這樣做的代價無疑非常龐大的
故我們希望檢測出來哪些 DOM 發生了變化,然後更新變化的 DOM 便能極大的優化性能,
在各大框架中都有自己的一套解決方案,在 Angular.js 中使用的是髒檢查手法,這裡不討論。而 react.js 與 Vue.js 的手段便是虛擬 DOM
下圖就是虛擬 DOM 的具體流程
看了此圖,也就能理解 Vue生命週期裡 beforeUpdate 與 updated 是什麼時候觸發的了
總之,虛擬 DOM 就起這麼一個對比的作用,找出不同,然後有選擇的替換渲染,達到優化性能的目的
四、銷毀階段(beforeDestroy、destroyed):#
就是 Vue 實例不再被使用的銷毀階段,具體細節在一開始圖片裡已描述的非常詳細,這裡不再贅述#
再講講 Vue 的響應式數據綁定
什麼是響應式數據綁定?
響應式數據綁定就是在修改 data 裡的數據後頁面視圖也隨之改變,這可是在沒有刷新頁面的情況下做到的喔。
Vue 是怎麼做到的呢?
想要做到數據變化後修改視圖,首先要做到的就是監聽到哪變化了,
1. 偵測變化:
深入學習過 JavaScript 的同學會知道:有兩種方法可以偵測到 js 對象的變化,Object.defineProperty 和 ES6 的 Proxy(如果有不清楚的同學,具體的使用方法這裡就不討論了,大概就是在 Object.defineProperty 中當傳入的對象被讀取時會觸發 get 回調,當傳入的對象被修改時會觸發 set 回調,ES6 的 Proxy 就是 js 提供的一種源編程能力,可以直接檢測到對象的變化)
2. 通知變化
通過一系列的代碼監聽到都有哪些數據發生變化之後的下一步就是通知使用此數據的地方,希望使用此數據的地方使用新的數據,直接通知到 DOM 嗎? Vue1.x 的版本確實是這樣做的,可這麼精確是有代價的,依賴追蹤在內存的開銷會很大,因此 Vue 搞了一個叫 Watcher 的東西,當數據變化時就先通知 Watcher,Watcher 再通知使用此數據的地方,每一個 Vue 組件也就是 Vue 實例都會有一個 Watcher,統一管理達到了優化的效果
PS:其實也挺簡單的對吧,就是監聽數據變化,然後通知到使用此數據的地方
但還有一個值得注意的地方,如果數組數據變化了的話,Object.defineProperty 和 ES6 的 Proxy 都是沒有辦法監聽到的,所以數組的變化是通過在 Array 原型裡構造一個攔截器,每當使用了 6 種數組方法的其中一個就能被攔截器監聽到,實現監聽數據改變的方法。
總結
在上述的每一步,Vue 都做了非常多的工作,從將 html 代碼轉化成 AST,到虛擬 DOM 的渲染,再到 diff 算法,又或是各種 API 的實現,源碼都有很多有意思的地方,使用了函數柯里化優化速度,在抽象語法樹裡使用優化器,避免更改沒有變化的 DOM 元素,還有更多的 v-if, v-for 的原理,過濾器等。多少了解一些可以很大程度的幫助你寫出更優秀的 Vue 代碼
————————————————
版權聲明:本文為 CSDN 博主「我叫李文(living)」的原創文章,遵循 CC 4.0 BY-SA 版權協議,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_45963949/article/details/124575471
Vue 的使用#
文本綁定#
- {{variable}} 定義在標籤內部,插值綁定
- v-text=‘variable’ 定義在標籤屬性中,讓元素的文本內容與變量綁定
- v-html=‘variable’ 定義在標籤屬性中,讓元素的標籤內容和變量綁定
屬性綁定#
讓元素的 屬性值 與 變量 單向綁定,屬性值發生變化,變量會跟隨發生變化。
- v-bind='variable' / ='variable'
<div>
<input type="text" :value="info">
<input type=="text" v-bind:value="info">
<a :href="url">超鏈接</a>
<img :src="imageName" alt="">
</div>
<script src="../vue.js"></script>
<script>
new Vue({
el:'div',
data:{
info:"屬性綁定"
url:'http://www.baidu.com',
imageName:'head.jpg'
}
})
</script>
雙向綁定#
定義在標籤屬性中,讓標籤控件的 value 值和變量雙向綁定,相互影響同步
- v-model=‘variable’
<div id="app">
<input type="text" v-model='info'>
{{info}}
<h1>
註冊表單
</h1>
<form action="">
用戶名:<input type="text" v-model="user.username"><br>
密碼:<input type="password" v-model="user.password"><br>
</form>
<script src="../vue.js"></script>
<script>
let v = new Vue({
el:"#app",
data:{
info:"雙向綁定",
user:{
username:"",
password:""
}
}
})
</script>
</div>
事件綁定#
綁定元素的事件與函數。
鼠標點擊實例: v-on:click="func"
或 @click="func"
<div id="app">
<input type="button" value="bt1" @click='f()'>
<input type="button" value="bt2" v-on:click='f()'>
</div>
<script src="../vue.js"></script>
<script>
let v = new Vue({
el:"div",
data:{},
methods:{
f:function(){
console.log("按鈕被點擊!");
}
}
})
</script>
遍歷#
讓元素根據綁定對象的成員數量自動遍歷生成相同元素。
v-for="(variable,i) in vars"
<table>
<caption>汽車列表</caption>
<Tr>
<th>編號</th><th>品牌名稱</th><th>售價</th><th>類型</th>
</Tr>
<tr v-for="(car,i) in arr">
<td>{{i+1}}</td>
<td>{{car.name}}</td>
<td>{{car.price}}</td>
<td>{{car.type}}</td>
</tr>
</table>
<script src="../vue.js"></script>
<script>
let v=new Vue({
el:"table",
data:{
arr:[ {name:'a',price:50000,type:'car1'}
{name:'b',price:60000,type:"car2"}
{name:'c',price:40231,type:'car3'}]
}
})
</script>
判斷#
讓元素的顯示狀態與變量綁定,true 則顯示,false 則不顯示
v-if="variable"
和v-else
<div id="app">
<h1 v-if="isVisible">
標題可調整顯示
</h1>
<h1 v-else>
否則顯示此內容
</h1>
</div>
<script src="../vue.js"></script>
<script>
let v=new Vue({
el:'div',
data:{
isVisible:true
}
})
</script>
Tips#
property
attribute
前者是標籤固有屬性,後者是標籤內定義的 k-v 鍵值對npm root -g
查看全局插件路徑
css#
Position 定位#
-
static
默認文檔流定位,從上到下,從左到右
-
relative
相對於自身正常文檔流的定位,其占用空間不會改變,只是帶有一定 偏移
-
fixed
相對於 == 瀏覽器窗口 == 的定位,不會跟隨頁面滾動而移動
-
absolute
絕對定位是相對於已定位的父元素 / 或 html 元素。
絕對定位使元素脫離文檔流,不占據文檔流空間,可以重疊。
-
sticky
粘性定位,使元素在 relative 和 fixed 之間切換,實現「滾動到一定範圍,元素附著在頁面上」 的效果。