一、Vue簡介
1、數據驅動視圖
Vue.js 是一個用於創建 Web 交互界面的庫。它讓你通過簡單而靈活的 API 創建由數據驅動的 UI 組件。
Vue.js是一款輕量級的、以數據驅動構建web界面的前端JS框架,它在架構設計上采用了MVVM(Model-View-ViewModel)模式,其中ViewModel是Vue.js的核心,它是一個Vue的實例,而這個實例又作用於頁面上的某個HTML元素。
其核心在於通過數據驅動界面的更新和展示而非JS中通過操作DOM來改變頁面的顯示。
上圖的DOM Listeners和Data Bindings是數據驅動中實現數據雙向綁定的關鍵,實際的 DOM 封裝和輸出格式都被抽象為了 Directives 和 Filters; 這也是Vue.js事件驅動的原理所在。
對於View而言,ViewModel中的DOM Listeners工具會幫助我們監聽頁面上DOM元素的變化,一旦有變化,Model中的數據也會發生改變;
對於Model而言,當我們操縱Model中的數據時,Data Bindings工具會幫助我們更改View中的DOM元素。
此外,頁面組件化也是Vue.js的核心,它提供了一種抽象,讓我們可以用獨立可服用的小組件來構建大型應用。
所以,我們搭建的任何一個界面你可以把其抽象成為一個組件樹,充分的去復用它。
2、MVVM架構
Model是每個頁面的單獨數據,View是每個頁面中的HTML結構,VM是調度者;相比於MVC主要做了如下圖示的調整:
優缺點
優點:數據驅動,調度均勻;
缺點:不適合大型項目的架構設計。
3、快速體驗
核心是vm,他是一個Vue實例對象。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <p>{{message}}</p> <p>{{msg}}</p> </div> <script src="js/vue.js"></script> <script> // 1. 創建Vue的實例 const vm = new Vue({ el: '#app', data: { // vue中的model -> 數據 message: 'hello world!', msg:'我要上班' } }); </script> </body> </html>
在上面代碼中,我們通過new Vue()構建了一個Vue的實例。
在實例化 Vue 時,需要傳入一個選項對象,它可以包含數據、模板、掛載元素、方法、生命周期鈎子等選項。比如:掛載元素(el)和數據(data),我們可以操縱數據改變視圖。
el表示Vue要操作哪一個元素下面的區域,比如:#app則表示操作id為app的元素下面的區域;
data表示Vue實例的數據對象,data的屬性能夠響應數據的變化;每個 Vue 實例都會代理其 data 對象里所有的屬性。
二、Vue指令
https://cn.vuejs.org/v2/api/
2.1 v-once指令
執行一次性地插值,當數據改變時,插值處的內容不會更新。
2.2 v-if指令
條件渲染指令,根據表達式的真假來添加或刪除元素。其語法結構是:v-if="expression",其中expression是一個返回bool值的表達式,其結果可以是true或false,也可以是返回true或false的表達式。
v-else-if
v-else
2.3 v-show指令
也是條件渲染指令,不同的是有 v-show 的元素會始終渲染並保持在 DOM 中。和v-if指令不同點在於:v-show是根據表達式之真假值,切換元素的 display CSS 屬性,當條件變化時該指令觸發過渡效果。
v-show和v-if的區別:
v-if 是真實的條件渲染,因為它會確保條件塊在切換當中適當地銷毀與重建條件塊內的事件監聽器和子組件; v-show 則只是簡單地基於 CSS 切換。 v-if 有更高的切換消耗而 v-show 有更高的初始渲染消耗。因此,如果需要頻繁切換使用 v-show 較好,如果在運行時條件不大可能改變則使用 v-if 較好。
2.4 v-else指令
可以用v-else指令為v-if或v-show添加一個“else塊”。注意:v-else前一兄弟元素必須有 v-if 或 v-else-if。
2.5 v-else-if指令
可以用v-else指令為v-if或v-show添加一個“else塊”。注意:v-else前一兄弟元素必須有 v-if 或 v-else-if。
2.6 v-for指令
基於數據渲染一個列表,類似於JS中的遍歷。其數據類型可以是 Array | Object | number | string。
該指令之值,必須使用特定的語法(item, index) in items, 為當前遍歷元素提供別名。 v-for的優先級別高於v-if之類的其他指令。
一個對象的 v-for
你也可以用 v-for 通過一個對象的屬性來迭代。
<ul id="v-for-object" class="demo"> <li v-for="value in object"> {{ value }} </li> </ul> new Vue({ el: '#v-for-object', data: { object: { title: 'How to do lists in Vue', author: 'Jane Doe', publishedAt: '2016-04-10' } } })
結果:
How to do lists in Vue
Jane Doe
2016-04-10
你也可以提供第二個的參數為 property 名稱 (也就是鍵名):
<div v-for="(value, name) in object"> {{ name }}: {{ value }} </div>
結果為: title: How to do lists in Vue author: Jane Doe publishedAt: 2016-04-10
第三個參數為索引:
<div v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</div>
結果為:
0. title: How to do lists in Vue
1. author: Jane Doe
2. publishedAt: 2016-04-10
2.7 v-text指令
v-text:向標簽中注入文本,且會替換掉元素之前的內容。;
類似innerText。
2.8 v-html指令
雙大括號會將數據解釋為普通文本,而非 HTML 代碼。為了輸出真正的 HTML,你需要使用 v-html
指令:
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
通過v-html會把文本解析成html文本,有樣式的話,會直接出來樣式。
類似JavaScript中的innerHTML。
2.9 v-bind指令
動態地綁定標簽中的一個或多個屬性,或一個組件 prop 到表達式。v-bind指令可以在其名稱后面帶一個參數,中間用一個冒號隔開。這個參數通常是HTML元素的特性(attribute),比如:
v-bind:src="imageSrc" 可以縮寫: :src="imgaeSrc"
:class="{ red: isRed }" 或 :class="[classA, classB]" ...
:style="{ fontSize: size + 'px' }" 或 :style="[styleObjectA, styleObjectB]" ...
綁定一個有屬性的對象,比如:v-bind="{ id: someProp, 'other-attr': otherProp }"
語法結構:v-bind:argument="expression"
因為 Mustache 不能在 HTML 屬性中使用,應使用 v-bind 指令,Mustache 是一個 logic-less (輕邏輯)模板解析引擎,它的優勢在於可以應用在 Javascript、PHP、Python、Perl 等多種編程語言中。
語法糖為冒號(:)
2.10 v-on指令
動態地綁定一個或多個特性,或一個組件 prop 到表達式;其作用和v-bind類似。注意:如果用在普通元素上時,只能監聽 原生 DOM 事件;但是如果用在自定義元素組件上時,也可以監聽子組件觸發的自定義事件。
常用的修飾符包括:
- .stop - 調用 event.stopPropagation();停止冒泡。
- .prevent - 調用 event.preventDefault(); 停止監聽原生事件。
- .capture - 添加事件偵聽器時使用 capture 模式。
- .self - 只當事件是從偵聽器綁定的元素本身觸發時才觸發回調。
- .{keyCode | keyAlias} - 只當事件是從偵聽器綁定的元素本身觸發時才觸發回調。
- .once - 觸發一次。
使用手法:
<!-- 方法處理器 -->
<button v-on:click="doThis"></button>
<!-- 內聯語句 -->
<button v-on:click="doThat('hello', $event)"></button>
<!-- 縮寫 -->
<button @click="doThis"></button>
<!-- 停止冒泡 -->
<button @click.stop="doThis"></button>
<!-- 阻止默認行為 -->
<button @click.prevent="doThis"></button>
<!-- 阻止默認行為,沒有表達式 -->
<form @submit.prevent></form>
<!-- 串聯修飾符 -->
<button @click.stop.prevent="doThis"></button>
<!-- 鍵修飾符,鍵別名 -->
<input @keyup.enter="onEnter">
<!-- 鍵修飾符,鍵代碼 -->
<input @keyup.13="onEnter">
<!-- the click event will be triggered at most once -->
<button v-on:click.once="doThis"></button>
語法糖為(@)
2.11 v-model
v-model
指令在表單 <input>
、<textarea>
及 <select>
元素上創建雙向數據綁定。它會根據控件類型自動選取正確的方法來更新元素。
盡管有些神奇,但v-model
本質上不過是語法糖。它負責監聽用戶的輸入事件以更新數據,並對一些極端場景進行一些特殊處理。
v-model
在內部為不同的輸入元素使用不同的屬性並拋出不同的事件:
- text 和 textarea 元素使用
value
屬性和input
事件; - checkbox 和 radio 使用
checked
屬性和change
事件; - select 字段將
value
作為 prop 並將change
作為事件。
2.12 樣式綁定
兩種方式綁定屬性:
- 通過class綁定
- 通過style綁定
兩種方法表示屬性值:
1、通過對象
解釋為:通過isActivated變量來決定activated的class屬性是否顯示。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .activated{ color:red } </style> </head> <body> <div id="app"> <!--<div :style="[styleObj]" @click="handleChangeColor">--> <!--hello world--> <!--</div>--> <div :class="{activated:isActivated}" @click="handleClassColor"> hello world </div> </div> <script src="js/vue.js"></script> <script> // 1. 創建Vue的實例 let vm = new Vue({ el: '#app', // data: { // styleObj:{ // color:"red" // } // }, data:{ isActivated:false }, methods:{ handleChangeColor:function(){ this.styleObj.color = this.styleObj.color==='black'?'red':'black' }, handleClassColor:function () { this.isActivated = !this.isActivated } } }); </script> </body> </html>
2、通過數組
通過數組的方式,數組里面是一個一個對象,通過對象的賦值來決定class屬性是否顯示。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .activated{ color:red } </style> </head> <body> <div id="app"> <!--<div :style="[styleObj]" @click="handleChangeColor">--> <!--hello world--> <!--</div>--> <div :class="[activated,{backgroundColor:'yellow'}]" @click="handleClassColor"> hello world </div> </div> <script src="js/vue.js"></script> <script> // 1. 創建Vue的實例 let vm = new Vue({ el: '#app', // data: { // styleObj:{ // color:"red" // } // }, data:{ activated:'' }, methods:{ handleChangeColor:function(){ this.styleObj.color = this.styleObj.color==='black'?'red':'black' }, handleClassColor:function () { this.activated = this.activated==='activated'?'':'activated' } } }); </script> </body> </html>
總結:
通過對象綁定時,是樣式value
通過數組綁定時,是樣式key
為什么會這樣?數據返回的是一個對象,針對數組內的每個值通過key獲取真正的value,並綁定到class上。
凡是希望外界控制的,都要做成屬性,靈活改變,組件也就活了。
通過:atrr進行綁定的屬性,后面不是字符串了,而是JavaScript表達式了<div :class="oneClass">樣式類可以是字符串</div>,oneClass不是字符串,而是oneClass的值。
<template> <div> <h3>class的使用</h3> <div :class="oneClass">樣式類可以是字符串</div> <div :class="{classTwo:true}">樣式類是對象</div> <div :class="[twoClass,threeClass]">樣式類是列表</div> <div :class="[‘classOne’,classTwo]">樣式類是列表</div> <hr> <div style="width:200px;height: 100px;margin: 0 auto" :style="{backgroundColor:bgColor}"> 樣式類可以是字符串 </div> </div> </template> <script> export default { name: "ClassAndStyle", data(){ return { oneClass: 'classOne', twoClass: 'classTwo', threeClass:'classThree', bgColor:'yellow' } } } </script> <style scoped> .classOne{ color:red; } .classTwo{ color:green; } .classThree{ width:200px; height: 100px; border: solid 1px; margin: 0 auto; } </style>
總結:
data(){ return { oneClass: 'classOne', twoClass: 'classTwo', threeClass:'classThree', bgColor:'yellow' } }
Class綁定樣式三種方式:
字符串:填寫key值
<div :class="oneClass">樣式類可以是字符串</div>
對象:填寫value:bool方式
<div :class="{classTwo:true}">樣式類是對象</div>
數組:可以是key名稱 也可以是value字符串
<div :class="[twoClass,threeClass]">樣式類是列表</div> <div :class="[‘classOne’,classTwo]">樣式類是列表</div>
Style綁定樣式方式:
<div :style={backgrounColor:bgcolor}></div>
data(){
return{
bgcolor:'red';
}
}
2.13 key綁定
<div> <div v-if="show"> 用戶名:<input type="text" /> </div> <div v-else> 郵箱:<input type="text" /> </div> </div>
當show變化的時候,vue會判斷頁面上是否有同樣元素可以復用。上面例子如果我們在用戶名input框里面輸入了內容,再將show切換為false的時候,你會發現input框里面內容沒有變化。
原因就是vue進行了元素復用。
解決辦法就是加上key:
<div> <div v-if="show"> 用戶名:<input type="text" key='username' /> </div> <div v-else> 郵箱:<input type="text" key='email' /> </div> </div>
注意:key盡量不要使用index,使用數據的id或其他字段,效率更高。
可以使用第三方插件:shortid
npm i shortid --save
三、computed和methods和watch
1、起因?
雖然在模板中綁定表達式是非常便利的,但是它們實際上只用於簡單的操作。在模板中放入太多的邏輯會讓模板過重且難以維護。比如:
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
這樣,模板不再簡單和清晰。在實現反向顯示 message 之前,你應該通過一個函數確認它。所以,Vue.js提供了計算屬性來讓我們去處理實例中的復雜邏輯。
計算屬性 (computed properties) 就是不存在於原始數據中,而是在運行時實時計算出來的屬性。
在上面的案例中,計算屬性fullname 和 reverse 的值始終取決於firstname 和 lastname。計算屬性默認只有 getter ,當然在需要時我們也可以提供一個 setter 。計算屬性被設計出來的目的在於:getter 是干凈無副作用的。
2、計算屬性 和 Methods的區別?
當頁面重新渲染(不是刷新)的時候,計算屬性不會變化,直接讀取緩存使用,適合較大量的計算和改變頻率較低的屬性;
而method,就是當頁面重新渲染的時候(頁面元素的data變化,頁面就會重新渲染),都會重新調用method。
如果不希望有緩存,我們可以用method取代computed。
疑惑:為什么需要緩存?
假設我們有一個重要的計算屬性 A ,這個計算屬性需要一個巨大的數組遍歷和做大量的計算。然后我們可能有其他的計算屬性依賴於 A 。如果沒有緩存,我們將不可避免的多次執行 A 的 getter !
我們可以將同一函數定義為一個方法而不是一個計算屬性。兩種方式的最終結果確實是完全相同的。然而,不同的是計算屬性是基於它們的響應式依賴進行緩存的。
只在相關響應式依賴發生改變時它們才會重新求值。這就意味着只要 name還沒有發生改變,多次訪問 reverse
計算屬性會立即返回之前的計算結果,而不必再次執行函數。
3、watch
watch的事情場景:監聽到一個屬性變化,從而導致其他屬性也跟着改變。比如,監聽到一個物品價格的改變,會導致總價的改變,就會重新計算一次。
而computed則適應於一開始就要計算的情景,他具備緩存作用
深度監視
當我們的data中有嵌入式的數據結構,比如[{'name':'xuequn'}]類似這樣的數據,數組中有對象,當我們希望在name發生變化時,進行監視,就必須使用深度監視功能。
watch: { // 深度監視 todos: { handler: localStorageUtil.saveTodos, deep: true, // 深度監視 // immediate: true //進入后立即執行 } }
四、補充內容
1、 數組的7個方法
pop:刪除最后一個元素
push:插入到數組尾部
shift:刪除數組的第一個元素
unshift:插入到數組的頭部
splice:刪除元素
sort:數組排序
reverse:數組翻轉
2、數組和對象的遍歷
v-for="(item,index) in list"
v-for="(value,key,index) in object"
3、改變數組或對象內容的方法
使用數組的方法:vm.list.splice(index,1,{id:'111',name:'xq'})立馬生效
改變數組引用的方法:vm.list = [{id:1,name:'qq'},{id:2,name:'qx'}]立馬生效
通過Vue.set方法:Vue.set(vm.list,index,{id:3,name:'qy'})立馬生效
通過vm.$set方法:vm.$set(vm.list,index,{id:3,name:'qy'})立馬生效
直接修改對象內容:vm.object.name='qqq',注意,新增一個{key:value}在頁面上是不起作用的,他不會重新渲染。
改變對象引用的方法:vm.object={name:'qqq',age:23} 立馬生效
通過Vue.set方法:vue.set(object,sex,'male'),立馬生效
通過vm.$set(object,sex,'male')立馬生效
4、vue中的屬性
<counter counter="0"></counter> //屬性前面不加冒號,0為字符串
<counter :counter="0"></counter> //屬性面前加冒號,0為數字,因為他解析js的表達式