VUE家族系列:
- Vue快速上門(1)-基礎知識
- Vue快速上門(2)-模板語法
- Vue快速上門(3)-組件與複用
01、基本概念
1.1、先了解下MVVM
VUE是基於MVVM思想實現的,❓那什麼是MVVM呢?—— MVVM,是Model-View-ViewModel的縮寫,是一種軟件架構模式。其核心思想就是分離視圖、數據、邏輯,VUE框架解決了數據Model
到視圖View
的雙向綁定,我們只關注業務邏輯ViewModel
即可,極大的提高的編程效率。
- M:Model,數據模型,通常來自後端服務、數據庫。
- V:View,視圖,就是HTML頁面,Dom。
- VM:ViewModel,視圖模型,連接模型和視圖,實現數據和視圖的相互綁定。包含了視圖狀態、行爲,如頁面展示的內容(邏輯)、頁面響應事件、數據獲取更新等,都封裝在 ViewModel 中。
VUE實現雙向綁定的基本原理:
🔸Dom Listeners:通過對DOM元素(表單輸入元素)的值變更監聽,同步視圖變化的數據到模型。
🔸Data Bindings:通過對模型數據攔截監聽,監測數據變化進行更新視圖。原理是基於基於ES5的特性Object.defineProperty(obj, propertyName, descriptor)
,通過其get、set訪問器來監聽數據變更,這也是Vue不支持IE8的原因。
🌰一個雙向綁定的簡單示例:
<div id="app">
<h2>{{message}}--{{message}}</h2>
</div>
<form action="#">
<input type="text" v-model="message">
</form>
<script>
//定義一個數據ViewModel,數據實際存儲在$data中。
let app = {
$data: {}
}
//通過defineProperty的get、set攔截,檢測數據變化》更新數據
Object.defineProperty(app, "message", {
get() { return this.$data.message; },
set(value) {
this.$data.message = value;
updateView(this); //更新視圖
}
})
//保存模板、綁定了數據的表單元素
let template = document.querySelector("#app").innerHTML;
let vinputs = document.querySelectorAll("input[v-model]");
//更新視圖
function updateView(data) {
const html = template.replace(/{{(\w+)}}/g, (match, $1) => {
return data[$1] || "";
})
document.querySelector("#app").innerHTML = html;
//更新表單元素的數據綁定
vinputs.forEach(el => {
el.value = data[el.getAttribute('v-model')];
});
}
//監聽輸入表單的值變更
vinputs.forEach(el => {
el.addEventListener("input", function (e) {
app[e.target.getAttribute('v-model')] = e.target.value;
});
});
//賦值
app.message = "hello";
</script>
» 基本過程如圖:
1.2、虛擬DOM
直接操作DOM,DOM頻繁變動會使得頁面不停的佈局、渲染,是很消耗性能的,虛擬DOM就是來解決這個問題的。虛擬DOM 就是先在內存中構建一個虛擬DOM
結構(JS對象表示),批量操作完成後再一次性的更新到瀏覽器DOM
樹上。VUE中的虛擬DOM操作思路也是如此,只是爲了更高效,實際要稍微複雜一點點。
- ❶ 用JS 對象模擬
虛擬DOM樹
。 - ❷ 比較DOM樹差異(修改、刪除、新增...)
- ❸ 將差異更新到真正的DOM樹中。
1.3、VUE是什麼?
中文官網:https://cn.vuejs.org | Vue3版本手冊 | Vue2版本手冊
Vue(讀音 /vjuː/,類似於 view) 是一套用於構建用戶界面的漸進式框架,同他周邊的生態共同構成了一個靈活的、漸進式的前端框架。
- 2013年底作爲尤雨溪個人實驗項目開始開發。
- 2014年公開發布。
- 2016年10月發佈2.0版本。
- 2020年發佈3.0版本。
🔸核心特性:
- 響應式數據驅動(雙向綁定),數據>視圖(數據監聽),視圖>數據(事件監聽)。
- 組件化:組件化的應用構建。
- 申明式渲染:採用模板語法申明式的將數據渲染到DOM。
- 輕量級框架:只關注視圖層,是一個構建數據的視圖集合,壓縮後30+K;
- 高效率:基於虛擬化Dom技術,DOM操作效率很高。
02、準備開始
2.1、安裝使用Vue2
- 通過
<script>
標籤直接引用vue.js
:
<!-- 開發環境版本,包含了有幫助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!-- 生產環境版本,優化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
- 通過
vue-cli
腳手架搭建vue
的開發框架。
2.2、命名規範
前端無非就是HTML、CSS、JS,坑爹的是他們的命名規範並不相同。前端常用的兩種命名方式:
- 小駝峯命名(lowerCamelCase):首字母小寫,後面的單詞首字母大寫:
userName
。 - kebab-case命名:烤串命名法(kebab /kɪˈbɑːb/ 烤肉串),都小寫,單詞之間用短線連接:
user-name
。
類型 | 命名方式 | 說明 |
---|---|---|
HTML | kebab-case | 按照W3C規範,HTMl中(包括標籤名、attribute)不區分大小寫,HTML解析時都會轉換爲小寫,支持字母數字、下劃線_ 、短線- 。自定義名稱一般都採用烤串命名,加短線主要是避免和HTML原生衝突(包括以後新的名稱) |
CSS | kebab-case | 字母開頭,字母數字、下劃線_ 、短線- ,一般都採用烤串命名 |
JavaScript | lowerCamelCase | 字母開頭,字母數字、下劃線_ ,不支持短線- (作爲對象屬性得引起來)。還有些細分:🔸 類、構造函數採用大駝峯命名 🔸 常量採用全大寫+下劃線_ |
在Vue中的命名就有一點特殊了(混合),默認是JavaScript的小駝峯命名,但當會用於Dom時,就要採用烤串命名了,比如:
- 組件的
id
:作爲元素標籤名 props
參數:作爲元素attribute
- 自定義事件名:作爲元素
attribute
- 自定義指令(包括指令參數、修飾符):作爲元素
attribute
📢自動轉換:參數props、組件id可以採用小駝峯命名,Vue會自動轉換。如果使用字符模板,就不歸瀏覽器管了,就沒有命名的限制問題了!
Vue中其他命名規範:
- 組件名,大駝峯,首字母大寫。
2.3、開發插件
- Vue Devtools:瀏覽器調試插件 ,在瀏覽器的調試面板中使用,推薦Edge瀏覽器安裝。
- Vetur:VSCode插件,Vue開發必備⭐,核心功能:
- ✅代碼高亮:語法、語義代碼高亮。
- ✅代碼片段:常用代碼片段的提示輸入,以及自定義代碼片段。
- ✅代碼檢查和格式化。
- ✅自定義代碼模板。
- Volar,Vue3版本的vetur
03、Vue基礎結構
3.1、創建一個Vue實例
每一個Vue組件都是通過Vue()
函數創建的一個Vue實例,他就是對應頁面Dom的 ViewModel。
<div id="app2">
<h2>{{title}}</h2>
<div>
<span v-text="user.name"></span>---<span v-text="age"></span>
<button v-on:click="showUpperCase">提交</button>
</div>
</div>
<script>
let vm = new Vue({
el: "#app2",
data: { user: { name: "sam", birthday: '2000-12-1'}, title: "hello world!" },
computed: {
age() { return (new Date().getFullYear() - new Date(this.user.birthday).getFullYear()); }
},
methods: {
showUpperCase: function (e) { this.title = this.title.toUpperCase(); },
}
})
</script>
Vue()
的構造函數參數,就是Vue的選項對象,提供了Vue實例的各項配置,常用配置:
el
:綁定視圖Dom元素,通過app.$el
訪問。data
:數據模型,會被Vue遞歸實現數據響應(數據監聽),通過Vue對象的get、set訪問器訪問數據,數據實際都存放在vm.$data
上。這裏的數據都是響應式的,支持數據雙向綁定,數據變化會自動更新同步。computed
:計算屬性(支持邏輯的屬性),值是一個(getter)函數,使用同data
。會基於其依賴的響應式屬性進行緩存:響應式屬性變更會觸發更新,緩存計算值,重複調用(綁定)複用結果。methods
:方法,實現各種業務邏輯,常用於綁定事件。
3.2、Vue選項🔖
💠Vue的構造函數參數=Vue選項:
Vue選項 | 描述 |
---|---|
💠選項-數據 | |
data | Vue的數據對象,會被遞歸實現propert 響應,vm.$data 訪問原始數據。 |
computed | 計算屬性,值是一個(getter)函數,使用同data 。會基於其依賴的響應式屬性進行緩存:響應式屬性變更會觸發更新;緩存計算值,重複調用(綁定)複用結果。 |
methods | 方法,定義方法的地方,可以綁定事件、表達式調用、訪問。 |
watch | 對property的監聽回調,當屬性值變更時觸發。也可通過實例方法添加vm.$watch(pName,func) |
props | 定義組件的參數,作爲組件特性使用:Array<string> | Object ,props: ['item','title'] |
propsData | 創建實例時傳遞 props,便於測試。{ [key: string]: any } |
💠選項-Dom | |
el | Vue的DOM根元素,值爲一個已存在Dom,(id )選擇器或元素實例。 |
template | 字符串模板,優先於el 元素內容模板,template: <h3>{{user.name}}</h3>` |
render | 渲染函數,優先於template |
renderError | render的替身, render 函數錯誤時替補 |
💠選項-資源 | |
directives | 指令,註冊局部指令,directives: {id:{}} |
filters | 過濾器,filters{id:func(value,...arg)} |
components | 註冊局部組件,components: { 'todo-box': com_todoBox } |
💠選項-組合 | |
parent | 指定父級實例 |
mixins | 混入(複用)選項,Array<Object> ,mixins:[cmixin] |
extends | 繼承另一個組件,複用代碼。extends: CompA |
provide / inject | 依賴注入,父類向子類發紅包,在父級定一個provider: {key:obj} ,後代inject :key ,獲得父類的紅包。用於一些特定對象的注入,後代需要才接收、可跨級。 |
💠選項-其他 | |
inheritAttrs | bool值-默認true,是否繼承組件上定義的(非Prop)特性Attribute,不會影響class、style綁定 |
model | 修改v-model 綁定的Prop和event,對於文本input默認v-model綁定的是value 和input 事件。 |
computed計算屬性
計算屬性在 computed
選項中,用於一些複雜邏輯數據的計算。值爲(getter)函數,使用同data
作爲vm
的屬性用。
主要特點:會基於其依賴的響應式屬性進行緩存:響應式屬性變更會觸發更新,緩存計算值,重複調用(綁定)複用結果。如果用方法methods,每次有任何更新都會被調用。
<div id="app4">
<p>age:{{age}},{{age}},{{getAge()}},{{getAge()}}</p>
</div>
<script>
let app4 = new Vue({
el: "#app4",
data: { user: { name: "sam", birthday: "2000-1-1" } },
computed: {
age() { //多次調用緩存屬性值
console.log("computed.age"); //computed.age
return new Date().getFullYear() - new Date(this.user.birthday).getFullYear();
}
},
methods: {
getAge() { //多次調用會重複執行
console.log("methods.getAge"); //methods.getAge methods.getAge
return new Date().getFullYear() - new Date(this.user.birthday).getFullYear();
}
}
})
</script>
計算屬性默認是沒有setter的,不過也可以實現setter。
computed: {
age: {
get: function () { },
set: function (value) { },
}
},
watch監聽器
針對data
中的響應式屬性的值變更監聽,也可以監聽計算屬性,存放在watch
選項裏,用於實現值變更的一些自定義業務邏輯。不需要返回值,支持異步處理,computed
計算屬性是必須要返回值的,異步就沒有意義了。
基礎語法:屬性名: function (newValue, oldValue)
,更多參考 vm.$watch API
watch: {
question: function (newValue) {
//當用戶問題變更時觸發
this.answer = "正在思考...";
// ajax請求搜索答案,這裏應該用防抖函數處理一下,避免頻繁無意義的調用。
fetchJsonp("https://www.baidu.com/s?wd=" + newValue)
.then(res => res.text())
.then(text => { console.log(text); this.answer = text; }); //跨域請求失敗
},
//或者對象的形式
question:{deep:true,handler(newValue,oldValue){}}
}
- 屬性名可以支持鏈式屬性路徑
"user.age":function(){ }
,不支持數組內部對象。 - 參數
{deep:true}
可以深度監聽對象下面的所有屬性,但oldValue
可能不準確。{immediate: true}
可以立即觸發一次監聽。
3.3、Vue選項-實例生命週期
Vue實例從①創建階段、到②運行階段、再到③銷燬終結的過程,就是Vue輝煌的一生。在這個過程中Vue提供了一些鉤子函數,這些函數都沒有參數,this指向組件自身。
Vue選項-生命週期鉤子 | |
---|---|
beforeCreate | 創建前:各項屬性配置都還不可用,幾乎不能幹什麼 |
created | 創建後:實例化完成後同步調用。數據、事件、計算屬性已完成,還未掛載模板,可發起ajax請求 |
beforeMount | 掛載el前:模板已完成編譯(各項指令都解析完成了),但還未加入到頁面Dom中 |
mounted | 掛載後-完成渲染:實例被掛載後調用,vm.$el 已創建,瀏覽器Dom完成渲染,用戶看到正式的頁面了 |
beforeUpdate | 更新前:數據發生改變後(數據最新),虛擬DOM 更新之前(頁面未更新) |
updated | 更新後:頁面Dom已更新完成,數據和頁面都是最新的,首次渲染不會觸發 |
beforeDestroy | 實例銷燬之前調用,此時組件還是正常的。 |
destroyed | 實例銷燬後調用,組件已銷燬並從Dom中移除。 |
activated | 組件激活/顯示,被 <keep-alive> 緩存的組件激活時調用 |
deactivated | 組件失活/隱藏,被 <keep-alive> 緩存的組件失活時調用 |
errorCaptured | 捕獲後代組件的錯誤 |
» 畫個圖:VUE生命週期(ProcessOn版本)
📢注意:不要在選項 property 或回調上使用箭頭函數,箭頭函數沒有this,會導致默認的this(vm)丟失。
3.4、Vue實例🔖
💠實例屬性 | 描述 |
---|---|
$data | vue對象的data 實際存儲的數據,vue代理了他的數據訪問 |
$el | el 掛載的視圖Dom元素 |
$options | Vue() 實例化的選項參數 |
$refs | 通過過ref attribute 註冊的所有 DOM 元素和組件實例的一個對象,this.$refs.header |
$parent | 父實例,根實例的 $parent 爲null |
$root | 組建樹的根實例,根實例的 $root 爲自己 |
$children | 子組件示例數組Array<Vue instance> |
$slots | 插槽分發的內容,{ [name: string]: ?Array<VNode> } |
$scopedSlots | 作用域插槽 { [name: string]: props => Array<VNode> | undefined } |
$listeners | 包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監聽器 |
$props | 組件定義的參數列表 |
$attrs | 父作用域中的非Prop的Attribute特性(不含class、style) |
$isServer | 是否運行於服務器,服務端渲染 |
💠實例方法 | |
---|---|
$watch( expOrFn, callback, [options] ) | 添加屬性變更監聽器vm.$watch("title", function (val, old) {}); |
$set( target, proName/index, value ) | 添加響應式的property,並更新視圖。用於後續增加的屬性,同Vue.set() |
$delete( target, proName/index ) | 刪除對象的 property,同Vue.delete() |
💠實例事件 | |
---|---|
$on( eventName, callback ) | 添加一個事件監聽,監聽當前實例上的自定義事件,事件可以由 vm.$emit 觸發 |
$once( eventName, callback ) | 添加一個事件監聽,但是隻觸發一次,觸發後被移除。 |
$off( [eventName, callback] ) | 移除自定義事件監聽器 |
$emit( eventName, […args] ) | 觸發當前實例上的事件,參數eventName 爲事件名稱,注意採用小寫命名方式 |
💠實例方法-生命週期 | |
---|---|
$mount( [elementOrSelector] ) | vue 實例掛載一個Dom元素,元素或CSS選擇器 |
$forceUpdate() | 強制更新渲染 |
$nextTick( [callback] ) | 同Vue.nextTick |
$destroy() | 完全銷燬一個實例 |
Vue靜態API
Vue全局靜態屬性/方法 | 描述 |
---|---|
Vue.extend( options ) | 創建一個Vue“子類”(不是實例),選項的data必須是函數,避免組件實例共享數據 |
Vue.nextTick( [callback, context] ) | Dom更新後立即調用回調,常用於手動操作Dom(需等Dom更新完),他返回的是一個Promise 🔸Vue更新都是異步的,類似JS的事件循環隊列,不會立即執行,便於去重提高性能 |
Vue.set( target, proName/index, value ) | 向響應式對象中添加一個響應式 property,並觸發視圖更新。可用於強制更新視圖 |
Vue.delete( target, proName/index ) | 刪除對象的 property,會觸發更新 |
Vue.directive( id, [definition] ) | 註冊或獲取全局指令 |
Vue.filter( id, [definition] ) | 註冊或獲取全局過濾器 |
Vue.component( id, [definition] ) | 註冊或獲取全局組件 |
Vue.use( plugin ) | 安裝 Vue.js 插件,爲Vue添加一些全局的功能,如 vue-router |
Vue.mixin( mixin ) | 全局註冊一個混入,小心使用,會影響後面所有的Vue實例。 |
Vue.compile( template ) | 將一個模板字符串編譯成 render 函數 |
Vue.observable( object ) | 讓一個對象可響應 |
Vue.version | 版本號,Vue.version //'2.7.14' |
©️版權申明:版權所有@安木夕,本文內容僅供學習,歡迎指正、交流,轉載請註明出處!原文編輯地址-語雀