傳統網頁開發
- 請求數據->生成結構->監聽變化
- 元素變化->發送請求->更新結構
缺點 - DOM 操作頻繁,代碼繁雜
- DOM 操作與邏輯代碼混合,數據或者結構的修改,可維護性差
- 不同功能區域書寫在一起,可維護性低
- 模塊之間依賴關系復雜
前端流行框架Vue.js
庫是一種工具,在代碼中起到輔助作用。框架是JS框架,是遵從遵守規則開發的一種方式
本文目的是學習Vue.js規則,Vue.js是漸進式JavaScript框架,官方學習
特性:
- 數據驅動視圖
- 組件化開發
數據驅動視圖
- 數據變化會自動更新到對應元素中,無需手動操作 DOM,這種行為稱作單向數據綁定
- 對于輸入框等可輸入元素,可設置雙向數據綁定
- 雙向數據綁定是在數據綁定基礎上,可自動將元素輸入內容更新給數據,實現數據與元素內容的雙向綁定
代碼中只進行了數據展示和修改,并未使用 DOM 功能,這就是數據驅動的單項數據綁定(數據->視圖)
雙向數據綁定適用于特殊元素(可輸入元素)例如:input,checkbox,textarea
輸入后自動更新到綁定數據上,綁定數據的更改也會自動更新到元素中(雙向)
Vue數據驅動視圖
- Vue.js的數據驅動視圖是基于MVM模型實現的
- MVVM(Model -View -ViewModel )是一種軟件開發思想
- Model層,代表數據
- View層,代表視圖模板
- ViewModel層,代表業務邏輯處理代碼
優點
- 基于MVVM模型實現的數據驅動視圖解放了DOM操作
- View 與Model處理分離,降低代碼耦合度
缺點
- 但雙向綁定時的 Bug調試難度增大
- 大型項目的 View 與 Model過多,維護成本高
組件化開發
組件化開發,分功能組件進行開發的一種方式。允許我們將網頁功能封裝為自定義HTML 標簽,復用時書寫自定義標簽名即可
組件不僅可以封裝結構,還可以封裝樣式與邏輯代碼,給組件起個名字,名字可作為html標簽名進行使用。組件大大提高了開發效率與可維護性
安裝
本地引入
cdn引入
比本地引入放到服務器上要快,通過script src屬性
npm安裝(yarn)
- npm install vue
- yarn add vue
基礎語法
Vue實例,基礎選項,指令,其他選項(過濾器,計算屬性,監聽器)四部分
Vue實例
通過Vue函數創建的對象,是使用Vue功能的基礎
var vm = new Vue({
// 選項對象
})
el選項
- 用于選取一個 DOM元素作為Vue 實例的掛載目標。
- 只有掛載元素內部才會被Vue進行處理,外部為普通HTML元素無法使用Vue功能。
- 代表MVVM中的View層(視圖)。
通過 el 掛載, 掛載完畢,可以通過 vm.$el
進行訪問操作 el,訪問到的是個HTMLElement
兩種掛載方式
- css選擇器格式的字符串
- HTMLElement 實例
var app = document.querySelector('#app');
var vm = new Vue({
el:"#app" // 通過css選擇器格式的字符串
el: app // HTMLElement 實例,注意這里沒引號,不能為html或body
})
未設置 el 的 vue實例,也可以通過 vm.$mount()
進行掛載,參數形式與 el 規則相同
var vm = new Vue({});
vm.$mount('#app');
效果相同,一個通過創建時掛載,一個創建過后掛載,$mount()
傳入參數和 el 相同
插值表達式
掛載元素內可以使用Vue.js的模板語法,模板中可以通過插值表達式為元素進行動態內容設置,寫法為{{ }}
,括號內可 基本運算,三目運算,數值等等
注意點:
- 插值表達式只能書寫在標簽內容區域,可以與其它內容混合
<li>{{1+2+3}}<li> // ok
<li id="{{ 1+2 }}"><li> // error
- 內部只能書寫JavaScript表達式,不能書寫語句
<li>{{ var num = 100 }}<li> // error
data選項
用于存儲Vue 實例需要使用的數據,值為對象類型。
new Vue({
el:"#app",
data:{
title:"內容"
}
})
訪問數據方式,vm.$data.數據
或者 vm.數據
,例如 vm.title
data數據特點,
- data中的數據可以直接在視圖中通過 插值表達式 訪問
- data 中的數據為響應式數據,在發生改變時,視圖會自動更新。
data注意:
- data 中存在數組時,索引操作與
length
操作無法自動更新視圖,這時可以借助Vue.set()
方法替代操作。
var vm = new Vue({
el:"#app",
data:{
contentArr:["1","2",3]
}
})
Vue.set(vm.contentArr,0,"生效的新內容") // 數組 索引 新值
<ul>
<li>{{ contentArr[0] }}</li>
<li>{{ contentArr[1] }}</li>
<li>{{ contentArr[2] }}</li>
</ul>
此時正常顯示,通過控制臺修改
-
vm.contentArr[0] = "你好嗎"
,li
并未更新 -
vm.contentArr.length = 0
li
并未更新
methods選項
用于存儲需要在 Vue實例中使用的函數
new Vue({
el:"#app",
data:{
contentArr:["1","2",3]
},
methods:{
foo(){
console.log(this)
return this.contentArr
}
}
})
訪問數據方式
- methods中的方法可以通過vm.方法名訪問
- 方法中的
this
為vm 實例,可以便捷的訪問vm數據等功能 - 方法通過
this
也可以互相組合this.foo(){ return this.foo1() }
Vue.js指令
指令本質就是 HTML 自定義屬性 (html有固定屬性和自定義屬性),指令是給框架進行識別的一種標記手段
Vue.js的指令就是以v-
開頭的自定義屬性
修飾符
修飾符是以點開頭的指令后綴,用于給當前指令設置特殊操作
- 事件修飾符
- 按鍵修飾符
- 系統修飾符
- 鼠標修飾符
- v-model修飾符
自定義指令
指令用于簡化DOM操作,相當于對基礎DOM操作的一種封裝。
當我們希望使用一些內置指令不具備的 DOM功能時,可以進行自定義指令設置。
- 自定義全局指令
- 自定義局部指令
自定義全局指令
- 指的是可以被任意Vue 實例或組件使用的指令。
定義一個focus指令,執行配置對象內容
- 參數1:指令名
- 參數2:配置對象(內部可以添加鉤子函數)
- inserted鉤子在元素插入 DOM 后執行
插入時自動獲取焦點
Vue.directive('focus',{
inserted(el){ // el表示設置這個指令的element元素,本文指下面的input元素
el.focus() // 執行元素操作
}
})
應用上面的指令
<div id="app">
<input type="text" v-focus>
</div>
全局的意思表示, 當你創建多個vue實例對象時,都可以使用focus的指令
new Vue({
el:"#app"
})
new Vue({
el:"#app2"
})
<div id="app">
<input type="text" v-focus>
</div>
<div id="app2">
<input type="text" v-focus> // 都可以被使用
</div>
鉤子函數參數
Vue.directive('focus',{
inserted(el,binding){ // el 指定指令的元素標簽,binding指設置的相關信息,如圖
console.log(binding)
}
})
<div id="app">
<input type="text" v-focus.a.b="100+1"> // 可以判斷有a或b修飾符做什么,如圖
</div>
自定義局部指令
- 指的是可以在當前Vue 實例或組件內使用的指令。
- 對象鍵:屬性名。對象值,配置對象
new Vue({
...
directives:{
focus:{
inserted(el){
el.focus()
}
}
}
})
使用
<div id="app">
<input type="text" v-focus>
</div>
過濾器
過濾器用于進行文本內容格式化處理。過濾器可以在插值表達式和v-bind中使用。
- 全局過濾器
- 局部過濾器
全局過濾器:可以在任意Vue實例中使用
- 參數1:過濾器名
- 參數2:過濾器功能
Vue.filter('過濾器名稱', function(value){ // value是使用過濾器時傳入的數據
// 邏輯代碼
return '處理結果'
})
- 過濾器能在插值表達式和v-bind中使用,通過
管道符|
連接數據
<div id="app">
<div v-bind:id = "id | filterId"></div> // 對id處理,在bind中使用
<div>{{ content | filterContent }}</div> // 對content處理,在插值表達式中使用
</div>
例子
<div id="app">
<p v-bind:title = "val | filterVal"></p> // "abc"
<p>{{ val2 | filterVal }}</p> // "xyz"
</div>
Vue.filter('filterVal',function(value){
console.log(value) // "a-b-c"
return value.split("-").join("") // 此時title則為"abc"
})
new Vue({
...
data:{
val:"a-b-c",
val2:"x-y-z"
}
})
注意事項
- 可以將一個數據傳入到多個過濾器中進行處理。
- 過濾器的組合操作,類似于管道,
content
參數先經過filterA
處理再將filterA的返回值
傳入filterB
中處理,再返回
<div id="app">
<p>{{ content | filterA | filterB }}</p>
</div>
- 一個過濾器可以傳入多個參數
- 注意:
- 參數1:content,參數2:par1,參數3:par2
<div id="app">
<p>{{ content | filterContent(par1,par2) }}</p>
</div>
局部過濾器
- 局部過濾器只能在當前Vue 實例中使用。
new Vue({
...
filters:{
過濾器名稱:function(value){
// 邏輯代碼
return '處理結果'
}
}
})
其他特點參考全局過濾器,一致的。
注意事項
- 如果全局過濾器和局部過濾器都存在,且重名,只有局部過濾器生效
- 因此,我們可以在vue全局 定義一些基礎的過濾器規則,在實例里對 和全局重名的局部過濾器進行 重寫,定義局部過濾功能
計算屬性
- Vue.js的視圖不建議書寫復雜邏輯,這樣不利于維護。
取數組中最大值
<div id="app">
<p>{{ Math.max.apply(null, arr) }}</p>
<p>{{ Math.max.apply(null, arr) }}</p>
<p>{{ Math.max.apply(null, arr) }}</p>
</div>
解決辦法
- 封裝函數處理
- 封裝函數是很好的方式,但有時重復的計算會消耗不必要的性能。
new Vue({
...
data:{ arr:[1,2,3,4,5] },
methods:{
result(){
var sum = 0
var arr = this.arr
for(var item of arr){
sum+=item
}
return sum
}
}
})
<div id="app">
<p>{{ result() }}</p>
<p>{{ result() }}</p>
<p>{{ result() }}</p>
</div>
- 如何提高計算執行效率?計算屬性
- 計算屬性使用時為屬性形式,訪問時會自動執行對應函數。
- 執行一次后,計算屬性內部會將執行的方法進行緩存
- 計算屬性減少了函數的執行次數
- 計算屬性可以通過
實例.xx
訪問
new Vue({
...
data:{ arr:[1,2,3,4,5] },
computed:{
result(){
console.log("我只執行了一次")
var sum = 0
var arr = this.arr
for(var item of arr){
sum+=item
}
return sum
}
}
})
<div id="app">
<p>{{ result }}</p>
<p>{{ result }}</p>
<p>{{ result }}</p>
</div>
Methods 與 Computed 區別
- computed具有緩存性,methods沒有。
- computed通過屬性名訪問,methods需要調用。
- computed僅適用于計算操作。
計算屬性的setter
- 計算屬性默認只有getter,Vue.js也允許給計算屬性設置setter
- 將計算屬性改為對象(以前是個方法)
-
vm.getResult = "xxx"
會執行 set方法
var vm = new Vue({
...
computed:{
getResult:{
// getter
get:function(){
// 邏輯代碼
},
// setter
set:function(newVal){
// 邏輯代碼
}
}
}
})
偵聽器
- 偵聽器用于監聽數據變化并執行指定操作。
new Vue({
...
data:{ value:"" },
watch:{
value (newVal,oldVal){ // 當value數據發現變化會執行
// 邏輯代碼
}
}
})
例子
<div id="app">
<input type="text" v-model="inputVal">
</div>
new Vue({
...
data:{ inputVal:"" }, // 只要inputVal值變了,就會觸發watch
watch:{
inputVal (newVal,oldVal){
// 邏輯代碼
console.log("偵聽器執行了")
}
inputVal :{ // 寫法2
handler(newVal,oldVal){
console.log("偵聽器執行了")
}
}
}
})
復雜類型監聽器設置
- 為了監聽對象內部值的變化,需要將watch書寫為對象,并設置選項
deep: true
,這時通過handler
設置處理函數。
new Vue({
...
data:{
obj:{ contxt1:"內容1",contxt2:"內容2" },
arr:[1,2,3,4,5]
},
watch:{
obj:{
deep:true,
handler(val,oldVal){
console.log(val,oldVal)
console.log(val === oldVal) // true
}
},
arr(val,oldVal){ // 數組不需要設置deep
console.log(val,oldVal)
console.log(val === oldVal) // true
}
}
})
注意事項
- 當更改(非替換)數組或對象時,回調函數中的新值與舊值相同,因為它們的引用都指向同一個數組、對象。因此,對于復雜類型,無法進行
val
和oldVal
對比
Vue DevTools
- 是Vue.js官方提供的用來調試Vue應用的工具
注意事項 - 網頁必須應用了Vue.js功能才能看到 Vue DevTools
- 網頁必須使用Vue.js 而不是 Vue.min.js
- 網頁需要在http協議下打開,而不是使用file協議本地打開。