[toc] 首發日期:2019 01 20 上篇內容回顧: 上篇內容講了 Vue的介紹:優點,MVVM Vue的靜態導入與安裝,以及hello world 實例可定義的內容:el,data,methods,生命周期鉤子(包括計算屬性,偵聽器也是可以定義在實例中的) 計算屬性 偵聽器 數據綁定 v m ...
目錄
首發日期:2019-01-20
上篇內容回顧:
上篇內容講了
- Vue的介紹:優點,MVVM
- Vue的靜態導入與安裝,以及hello world
- 實例可定義的內容:el,data,methods,生命周期鉤子(包括計算屬性,偵聽器也是可以定義在實例中的)
- 計算屬性
- 偵聽器
數據綁定
v-model可以把某個實例的數據與元素的數據綁定。這樣當其中一份數據發生變化時,與之綁定的數據也會發生變化。比如:把示例中的數據(在頁面中用{{}}
顯示出來)與輸入框的數據綁定
表單輸入框有value這個值,在表單輸入框里使用v-model會把表單輸入框與實例的數據進行“智能”綁定(為什麼說智能,因為有些輸入框的數據是value屬性,有些不是)。
表單輸入框綁定
你可以用 v-model 指令在表單 <input>
、<textarea>
及<select>
元素上創建雙向數據綁定。它會根據控制項類型自動選取正確的方法來更新元素。儘管有些神奇,但 v-model 本質上不過是語法糖。它負責監聽用戶的輸入事件以更新數據,並對一些極端場景進行一些特殊處理。
v-model 會忽略所有表單元素的 value、checked、selected 特性的初始值而總是將 Vue 實例的數據作為數據來源。如果希望輸入框有初始值,你應該在組件的 data 選項中聲明初始值。
單行文本輸入框
會把單行文本輸入框的value綁定到實例的數據中,因為value的數據就是單行文本輸入框的數據。
<body>
<div id="vm">
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
<input type="text" v-bind:value="message">
<!-- 不能使用普通的value=message,不然會識別不成正確的message,所以第三行用了v-bind -->
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#vm',
data:{
message:"hello world!"
}
})
</script>
多行文本輸入框
會把多行文本元素內的文本綁定到實例的數據中,因為多行文本元素內的文本就是單行文本輸入框的數據。
<body>
<div id="vm">
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<br>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#vm',
data:{
message:"hello world!"
}
})
</script>
在文本區域
<textarea></textarea>
使用插值表達式{{}}
來插值並不會生效,應該用 v-model 來代替。
覆選框checkbox
單個覆選框:覆選框也有value,不給定value值的時候value預設是布爾值(被勾選是true,沒有勾選是false)
<body>
<div id="vm">
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#vm',
data:{
checked:false
}
})
</script>
多個覆選框:指定了value之後,實例綁定的數據是對應的value值【由於是多個覆選框綁定到同一個實例上,所以這個實例數據應該是數組類型的。】
<body>
<div id='example-3'>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#example-3',
data:{
checkedNames:[] // 值為多個input的value的數組
}
})
</script>
單選框radio
radio也有value,所以與實例綁定的數據就是value的值
<body>
<div id="example-4">
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#example-4',
data: {
picked: ''// picked的值為input的value值
}
})
</script>
選擇框select
select的值來源與子標簽option。當select 的option沒有value值的時候,預設綁定的數據為option元素的文本值;當有value時,預設綁定的數據為option元素的value值。
<body>
<div id="example-5">
<select v-model="selected">
<option disabled value="">請選擇</option>
<option value ='a'>A</option> <!-- 這個用來測試有value的情況-->
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#example-5',
data: {
selected: "" // selected 的值為 a/B/C
}
})
</script>
select框允許多選時:那麼這時候實例的數據應該是一個數組,數組元素是option的文本值(無value時)或value
<body>
<div id="example-5">
<select multiple style="width: 50px;" v-model="selected">
<option disabled value="">請選擇</option>
<option value='a'>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#example-5',
data: {
selected: [] // 全選時: [ "a", "B", "C" ]
}
})
</script>
數據綁定的修飾符
.lazy
在預設情況下,v-model 在每次 input 事件觸發後將輸入框的值與數據進行同步 (除了輸入法組合文字時,這時候數據還沒完全輸入到輸入框中)。
你可以添加 lazy 修飾符,從而轉變為使用 change 事件進行同步:
<!-- 在“change”時而非“input”時更新 -->
<input v-model.lazy="msg" >
.number
如果想自動將用戶的輸入值轉為數值類型,可以給 v-model 添加 number 修飾符:
<input v-model.number="age" type="number">
這通常很有用,因為即使在 type="number" 時,HTML 輸入元素的值也總會返回字元串。如果這個值無法被 parseFloat() 解析,則會返回原始的值。
.trim
如果要自動過濾用戶輸入的首尾空白字元,可以給 v-model 添加 trim 修飾符:
<input v-model.trim="msg">
樣式綁定
我們平時也可以使用class='xxx'或style='xxx:xxxx'來綁定樣式。為什麼要選擇轉去使用Vue的樣式綁定?因為在Vue中class或style也可以定義成數據,你可能會想要“發生XXX情況後,某元素變成某樣式”,這個時候你需要定義“行為”來切換樣式了,而這時候如果你使用Vue自己的樣式切換會比較方便(因為首先你要獲取某個元素的class屬性,然後再重新賦值,這個操作可能需要自己定義一些dom操作)。
class綁定
使用v-bind:class
來進行class綁定
對象語法:
格式一:傳入的數據格式是{ class名: 布爾數據,.... }
,布爾數據影響class是否出現在元素的class屬性中。
<div id="app">
<div v-bind:class="{ active: isActive }">haha</div>
</div>
<!--
var app = new Vue({
el: '#app',
data: {
isActive: true // 影響著active這個class是否出現
},
})
-->
<!--
<style>
.active {
color: red;
}
</style>
-->
格式一:傳入的數據格式是對象名
,對象的數據格式是{ class名: 布爾數據,.... }
,布爾值影響class是否出現在元素的class屬性中。
<div id="app">
<div v-bind:class="classObject">haha</div>
</div>
<!--
var app = new Vue({
el: '#app',
data: {
classObject: {
active: true
}
},
})
-->
<!--
<style>
.active {
color: red;
}
</style>
-->
數組語法:
格式一:
<div id="app">
<div v-bind:class="[activeClass]">haha</div>
</div>
<!--
var app = new Vue({
el: '#app',
data: {
activeClass:'active'
},
})
-->
<!--
<style>
.active {
color: red;
}
</style>
-->
style綁定
使用v-bind:style
來進行style綁定
對象語法:
格式一:傳入的數據格式是{ 樣式名: 實例數據名(樣式值), .... }
<div id="app">
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">haha</div>
</div>
<!--
var app = new Vue({
el: '#app',
data: {
activeColor:'red',
fontSize: 14
},
})
-->
格式二:傳入的數據是一個對象,對象的數據格式是{ 樣式名: 樣式值, .... }
<div id="app">
<div v-bind:style="styleObject">haha</div>
</div>
<!--
var app = new Vue({
el: '#app',
data: {
styleObject: {
color:'red',
fontSize: "14px"
}
},
})
-->
數組語法:
傳入的數據是一個數組,數組的元素是多個對象,對象的數據格式是{ 樣式名: 樣式值, .... }
<div id="app">
<div v-bind:style="[styleObject]">haha</div>
</div>
<!--
var app = new Vue({
el: '#app',
data: {
styleObject: {
color:'red',
fontSize: "14px"
}
},
})
-->
補充:
- 當 v-bind:style 使用需要添加瀏覽器引擎首碼的 CSS 屬性時,如 transform,Vue.js 會自動偵測並添加相應的首碼。
事件
綁定事件
可以使用v-on:事件類型='函數名'
來綁定事件。
<div id="app">
<button v-on:click="myclick">點擊事件</button>
<!-- on:後面跟事件類型 -->
</div>
<!--
var app = new Vue({
el: '#app',
methods: { // 註意:是在methods裡面定義函數
myclick:function (){
alert("message")
}
}
})
-->
事件修飾符
事件修飾符可以影響事件的運行,事件修飾符使用.
跟在事件類型的後面,例如:<a v-on:click.stop="doThis"></a>
。
- .prevent 修飾符告訴 v-on 指令對於觸發的事件,調用 event.preventDefault()來阻止預設的元素行為,例如預設點擊a元素時會進行頁面跳轉,如果我們給事件加了prevent修飾符,那麼對應的a元素就不會進行網頁跳轉了
v-on:click.prevent='myFunction'
。 - .stop 修飾符告訴v-on 指令對於觸發的事件,阻止這個事件的冒泡(冒泡代表這個觸發的事件也會傳遞給父元素這些祖宗元素)
- .once修飾符告訴v-on 指令對於觸發的事件只會觸發一次。
- 還有好幾個事件修飾符,有興趣的可以自查。這個還是相對少用的。
<body>
<div id="app">
<a v-on:click.prevent='myFunction' href='#'>aaa</a>
<!-- 預設情況下,點擊a元素會進行跳轉,
上面用#來演示,如果url多了一個#說明a的原生事件觸發了,
而我們現在用prevent來阻止了a元素原始的事件
-->
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
methods: {
myFunction: function () {
alert('haha')
}
}
})
</script>
按鍵修飾符
你可能需要監聽鍵盤來觸發事件,比如最常用的就是監聽enter鍵了。
按鍵修飾符也使用.
跟在事件類型的後面 ,例如:<input v-on:keyup.enter="submit">
- .enter代表enter鍵修飾符
- .up .down .left .right代表四個方向鍵的修飾符。
- 【上面給出了常見的“按鍵修飾符別名”,是別名,真實的值可能是一個數字】
- 【這裡對於按鍵修飾符就不說那麼多了,需要用再查吧。】
事件綁定的簡寫
<!-- 完整語法 -->
<a v-on:click="doSomething">...</a>
<!-- 縮寫 -->
<a @click="doSomething">...</a>
補充:
- 還可以自定義事件【不過目前我做的一些前端項目好像都沒怎麼涉及,有興趣的可以自查】
Vue指令
Vue的指令是以v-開頭的,它們各有各的左右,在前面已經介紹了不少了。現在再彙總一下。
- v-text:向元素中輸出文本
- v-html:向元素中輸入html文本
- v-if:根據條件來判斷是否渲染元素(同類的v-else,v-else-if)
- v-show:根據條件來判斷是否顯示元素
- v-for:迴圈渲染元素
- v-bind:為元素綁定屬性
- v-model:進行數據的雙向綁定
- v-on: 為元素綁定事件
- v-once用來聲明元素只渲染一次。
數組操作
為什麼要特意地說一下數組的操作呢?因為數組是非常常用的數據類型,而在Vue中有些數組操作並不會觸發視圖更新。為了確保數據是“響應式”的,所以特意講一下這個。
下麵的代碼演示了使用普通數組操作方法時“響應失敗”的情況:
<body>
<div id="app">
<p>{{ myArray}}</p>
<button @click='addValue1'>下標法添加</button>
<button @click='addValue2'>push法</button>
<!-- 如果你點了第一個,再點第二個,第一個的添加會在第二個的時候再成功顯示 -->
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
myArray: [1,2,3]
},
methods: {
addValue1: function(){
this.myArray[1]=333
},
addValue2: function(){
this.myArray.push('999999')
}
}
})
</script>
下麵這些對數組操作的方法將會觸發視圖更新。
push()
:向數組末尾添加元素pop()
:從數組末尾取出一個元素shift()
:數組的第一個元素從其中刪除,並返回第一個元素的值unshift()
:向數組的開頭添加一個或更多元素,並返回新的長度splice()
:從數組中添加/刪除項目,然後返回被刪除的項目sort()
:對數組的元素進行排序reverse()
:對數組的元素進行逆序排序
官網的話
【官網的話】由於 JavaScript 的限制,Vue 不能檢測以下變動的數組:
- 當你利用索引直接設置一個項時,例如:
vm.items[indexOfItem] = newValue
- 當你修改數組的長度時,例如:
vm.items.length = newLength
為瞭解決第一類問題,以下兩種方式都可以實現和 vm.items[indexOfItem] = newValue 相同的效果,同時也將觸髮狀態更新:
Vue.set(vm.items, indexOfItem, newValue)
或vm.items.splice(indexOfItem, 1, newValue)
或vm.$set(vm.items, indexOfItem, newValue)
為瞭解決第二類問題,你可以使用 splice:vm.items.splice(newLength)
補充:
- 還是由於 JavaScript 的限制,Vue 不能檢測對象屬性的添加或刪除:
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 現在修改a是響應式的
vm.b = 2
// `vm.b` 不是響應式的
- 有時,我們想要顯示一個數組的過濾或排序副本,而不實際改變或重置原始數據(不改變原來的數據,代表創建一個副本,而sort會影響源數組,所以我們需要新的數組來存儲)。在這種情況下,可以創建返回過濾或排序數組的計算屬性。【如果你處理數組有多種情況,你可以使用一個 method 方法,用傳參來定義如何處理數組】
<body>
<div id="app">
<p>{{ numbers }}</p>
<ul >
<li v-for="n in evenNumbers">{{ n }}</li>
</ul>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
})
</script>
Vue的元素復用問題
Vue 會儘可能高效地渲染元素,通常會復用已有元素而不是從頭開始渲染。這麼做除了使 Vue 變得非常快之外,還有其它一些好處。
數據殘留問題
而因為復用問題,所以可能會導致以下問題。由於輸入框被覆用,所以輸入框的數據殘留了下來。
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
問題的解決:
Vue 為你提供了一種方式來表達“這兩個元素是完全獨立的,不要復用它們”。只需添加一個具有唯一值的 key 屬性即可(沒有key的label仍然被覆用了):
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
當 Vue.js 用 v-for 正在更新已渲染過的元素列表時,它預設用“就地復用”策略。如果數據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數據項的順序, 而是簡單復用此處每個元素,並且確保它在特定索引下顯示已被渲染過的每個元素。
這個預設的模式是高效的,但是只適用於不依賴子組件狀態或臨時 DOM 狀態 (例如:表單輸入值) 的列表渲染輸出。
為了給 Vue 一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一 key 屬性。理想的 key 值是每項都有的唯一 id。這個特殊的屬性相當於 Vue 1.x 的 track-by ,但它的工作方式類似於一個屬性,所以你需要用 v-bind 來綁定動態值 (在這裡使用簡寫):
<div v-for="item in items" :key="item.id">
<!-- 內容 -->
</div>
建議儘可能在使用 v-for 時提供 key,除非遍歷輸出的 DOM 內容非常簡單,或者是刻意依賴預設行為以獲取性能上的提升,因為它是 Vue 識別節點的一個通用機制。