Vue的使用總結(jié)(1)
1、新建Vue實(shí)例
每個(gè) Vue 應(yīng)用都是通過用 Vue 函數(shù)創(chuàng)建一個(gè)新的 Vue 實(shí)例開始的。
通過 Vue 函數(shù)新建一個(gè) vue 應(yīng)用:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> {{message}} </div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script> var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) </script> </body> </html>
我們可以傳入一個(gè)選項(xiàng)對(duì)象來新建一個(gè) Vue 實(shí)例。上面的 vue 實(shí)例將會(huì)掛載到 #app 元素上,當(dāng) message 的值發(fā)生改變時(shí),視圖會(huì)重新渲染。
一個(gè) Vue 應(yīng)用由一個(gè)通過 new Vue 創(chuàng)建的根 Vue 實(shí)例,以及多個(gè)可選的嵌套的、可復(fù)用的組件組成。所有的 Vue 組件都是 Vue 實(shí)例,并且接受相同的選項(xiàng)對(duì)象 (一些根實(shí)例特有的選項(xiàng)除外)。
1.1、template字符串模板
我們可以使用 template 選項(xiàng)來作為字符串模板,該模板將會(huì)替換掛載的元素,掛載元素的內(nèi)容都將被忽略。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
template: `
<div id="newApp">
<h1>你好啊</h1>
</div>
`
})
</script>
</body>
</html>
渲染后的效果:

可以看到,#app 元素已經(jīng)被 template 里面的模板完全替換掉。
1.2、將某個(gè)對(duì)象賦值給vue實(shí)例中的data屬性時(shí)是淺拷貝
var obj= { a: 1 } var vm = new Vue({ data: obj }) obj.a = 2; console.log(vm.a) //2
2、vue上的字段:computed、method、watch
2.1、計(jì)算屬性(computed)
計(jì)算屬性作用一般是用來返回 data 屬性里數(shù)據(jù)通過一系列計(jì)算過后返回的新數(shù)據(jù),將會(huì)自動(dòng)根據(jù)data屬性里的數(shù)據(jù)發(fā)生改變而改變。computed里面的屬性值重新進(jìn)行計(jì)算的時(shí)機(jī)是方法體里面的任一響應(yīng)式數(shù)據(jù)發(fā)生改變,無論該數(shù)據(jù)是否影響到該屬性值。
var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { reversedMessage: function () { return this.message.split('').reverse().join('') } } })
計(jì)算屬性有 getter 和 getter,但是默認(rèn)只有 getter 。
當(dāng)獲取計(jì)算屬性時(shí),getter 被觸發(fā),返回計(jì)算值。
2.1.1、計(jì)算屬性的 setter
計(jì)算屬性有 getter 和 getter,但是默認(rèn)只有 getter 。如果該計(jì)算屬性也聲明了 setter,當(dāng)給計(jì)算屬性賦值時(shí)(比如上面的 vm.reversedMessage = 'aaa'),計(jì)算屬性值并不會(huì)被賦值為等號(hào)后面的值,而是執(zhí)行里面的函數(shù)體。同時(shí)有g(shù)etter和setter時(shí),getter 的觸發(fā)同默認(rèn)情況(即沒有setter時(shí))一致。
要想修改計(jì)算屬性的值,可以通過在 setter 方法里面響應(yīng)式修改依賴的值(computed一般依賴于data里面的數(shù)據(jù)),由此觸發(fā)計(jì)算屬性的 getter ,計(jì)算屬性的值得以更新。
注意,必須是響應(yīng)式修改依賴的值。當(dāng)修改數(shù)組某個(gè)索引的值時(shí)需要用 Vue.$set() 方法,當(dāng)往對(duì)象里面添加屬性時(shí)需要用 Vue.$set() 或者 Object.assign() 方法,刪除時(shí)用 Vue.$delete() 方法。(請(qǐng)注意,使用Object.assign添加屬性時(shí),必須是往一個(gè)新對(duì)象里面添加屬性,然后再將返回的新對(duì)象賦值給需要修改的對(duì)象)
data () { return { firstName: '張' } } computed: { name: { get () { return this.firstName + '三' }, set (newVal) { this.firstName = '李' //此處修改firstName,計(jì)算屬性name的getter將會(huì)被觸發(fā),導(dǎo)致重新計(jì)算,name得以更新 } } }
不建議將 v-model 的值綁定到計(jì)算屬性上。如果這樣做了,你會(huì)發(fā)現(xiàn)輸入框中的值改變但是計(jì)算屬性的值并沒有發(fā)生變化,而且此時(shí)你還要給計(jì)算屬性添加 setter 屬性才能編譯成功,所以非常不建議將 v-model 綁定到計(jì)算屬性上。
2.2、方法字段(methods)
方法字段里一般是定義一些dom可以調(diào)用的方法。
雖然方法也可以返回?cái)?shù)據(jù)而達(dá)到跟計(jì)算屬性一樣的作用,不同的是計(jì)算屬性基于它們的依賴而進(jìn)行緩存,只在相關(guān)依賴發(fā)生改變時(shí)它們才會(huì)重新求值。這就意味著只要依賴的數(shù)據(jù)還沒有發(fā)生改變,多次訪問 reversedMessage 計(jì)算屬性會(huì)立即返回之前的計(jì)算結(jié)果,而不必再次執(zhí)行函數(shù)。而每當(dāng)觸發(fā)重新渲染時(shí),調(diào)用方法將總會(huì)再次執(zhí)行函數(shù)。
所以如果是為了返回跟data數(shù)據(jù)里依賴的數(shù)據(jù)的話最好還是用計(jì)算屬性返回。
//index.html <p>Reversed message: "{{ reversedMessage() }}"</p> //index.js var vm = new Vue({ el: '#example', data: { message: 'Hello' }, methods: { show: function () { console.log('showtime') }, reversedMessage: function () { return this.message.split('').reverse().join('') } } })
2.3、偵聽屬性(watch)
偵聽屬性可以監(jiān)聽data屬性里的數(shù)據(jù)變化,當(dāng)數(shù)據(jù)改變時(shí)調(diào)用函數(shù)
var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: { firstName: function (val) { console.log('firstname數(shù)據(jù)發(fā)生改變了') }, lastName: function (val) { this.fullName = this.firstName + ' ' + val } } })
watch 監(jiān)聽在 mounted 之前就已經(jīng)綁定,即在 mounted 中觸發(fā)數(shù)據(jù)改變,watch 也會(huì)執(zhí)行。
watch 監(jiān)聽的數(shù)據(jù)在默認(rèn)情況下,在 data 中給該數(shù)據(jù)綁定,即第一次綁定時(shí),是不會(huì)觸發(fā) watch 的。
vue 中也可以監(jiān)聽 data 里的數(shù)據(jù)的屬性的變化:
var vm = new Vue({ el: '#demo', data: { obj: { name: '張三' } }, watch: { //監(jiān)聽數(shù)據(jù)的屬性要用引號(hào) 'obj.name'() { console.log(111) } } })
2.3.1、深度監(jiān)聽(deep)
在 vue 中監(jiān)聽數(shù)據(jù),如果數(shù)據(jù)是一個(gè)對(duì)象,當(dāng)對(duì)象的屬性發(fā)生改變時(shí),監(jiān)聽函數(shù)并不會(huì)被觸發(fā)
<button @click="change">修改信息</button> var vm = new Vue({ el: '#demo', data: { obj: { name: '張三' } }, methods: { change() { this.obj.name = '李四' } } watch: { obj() { console.log(111) } } })
上面代碼中改變 obj.name 后,監(jiān)聽函數(shù)并不會(huì)被觸發(fā)。
此時(shí)就可以使用深度監(jiān)聽來解決這個(gè)問題,當(dāng)然通過直接監(jiān)聽數(shù)據(jù)的屬性也是可以的。
watch: { obj: { deep: true, handler() { console.log('深度監(jiān)聽修改'); } } }
此時(shí)修改 obj.name 監(jiān)聽函數(shù)就可以被觸發(fā)。數(shù)組不需要使用 deep 屬性也能監(jiān)聽到變化。
2.3.2、綁定時(shí)立即執(zhí)行(immediate)
監(jiān)聽還有一個(gè)屬性是 immediate。
在默認(rèn)情況下,在 data 中給監(jiān)聽的數(shù)據(jù)綁定值時(shí),即第一次綁定時(shí)是不執(zhí)行函數(shù)的,但是有時(shí)候可能也需要在綁定時(shí)就執(zhí)行函數(shù),此時(shí)就可以使用 immediate 屬性。通過該屬性,在 data 中第一次給監(jiān)聽數(shù)據(jù)定義時(shí),就會(huì)觸發(fā) watch 的執(zhí)行。
比如當(dāng)父組件向子組件動(dòng)態(tài)傳值時(shí),子組件props首次獲取到父組件傳來的默認(rèn)值時(shí),也需要執(zhí)行函數(shù),此時(shí)就需要將 immediate 設(shè)為 true。
watch: { firstName: { handler(newName, oldName) { console.log(newName) }, immediate: true } }
3、vue中模板語法
在vue中給綁定的特性賦值,應(yīng)該寫在雙引號(hào)里面,雙引號(hào)里面的是JavaScript表達(dá)式
//index.html <div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }" ></div> //index.js data: { isActive: true, hasError: false }
4、vue中管理可復(fù)用元素
給每個(gè)元素定義一個(gè)唯一的 KEY ,這樣 vue 將會(huì)把該元素視為獨(dú)立唯一的,將不會(huì)簡(jiǎn)單地復(fù)用其他元素來渲染它。
參考:https://cn.vuejs.org/v2/guide/conditional.html 用key管理復(fù)用元素
5、Vue中響應(yīng)式更改數(shù)組和對(duì)象
5.1、更改數(shù)組
以下方法更改數(shù)組可以觸發(fā)視圖更新:
不更改原始數(shù)組,返回新數(shù)組:filter()、concat()、slice(),可以用新數(shù)組取代原數(shù)組
直接更改數(shù)組某個(gè)索引的值并不會(huì)觸發(fā)視圖更新:
var vm = new Vue({ data: { items: ['a', 'b', 'c'] } }) vm.items[1] = 'x' // 不是響應(yīng)性的 vm.items.length = 2 // 不是響應(yīng)性的
由于 Vue 只是監(jiān)聽了vue實(shí)例中的屬性的根屬性,比如上面 data 中的 items 數(shù)組,而并沒有監(jiān)聽根屬性內(nèi)的數(shù)據(jù)的改變,所以對(duì) items 進(jìn)行修改會(huì)觸發(fā) items 屬性的 set 方法,而對(duì) items 屬性中的某個(gè)值進(jìn)行修改則不會(huì)觸發(fā) set 方法,因此也不會(huì)觸發(fā)視圖更新。
// JS代碼模擬Vue中對(duì)數(shù)據(jù)的監(jiān)聽 let person = { get name() { return ['張三','李四'] }, set name(val) { console.log(111); } } person.name = [11,22] //會(huì)觸發(fā)set方法 person.name[1] = 11 //不會(huì)觸發(fā)set方法 person.name.splice(1,1) //不會(huì)觸發(fā)set方法
Vue 中使用變異方法來修改根屬性的值時(shí)可以觸發(fā)視圖更新,比如 pop、push等方法,值得注意的是Vue在底層中已經(jīng)重寫了這些方法
5.2、更改對(duì)象
由于 JavaScript 的限制,Vue 不能檢測(cè) data 屬性里根級(jí)別的屬性的添加或刪除。比如:
var vm = new Vue({ data: { a: 1 } }) // `vm.a` 現(xiàn)在是響應(yīng)式的 vm.b = 2 // `vm.b` 不是響應(yīng)式的
5.2.1、響應(yīng)式添加對(duì)象屬性
對(duì)于已經(jīng)創(chuàng)建的實(shí)例,Vue 不能動(dòng)態(tài)添加 data 屬性里的根級(jí)別的響應(yīng)式屬性。但是,可以使用 Vue.set(object, key, value) 方法向根級(jí)別里的屬性的對(duì)象屬性添加響應(yīng)式屬性。 比如:
var vm = new Vue({ data: { userProfile: { name: 'Anika' } } }) Vue.set(vm.userProfile, 'age', 27) //可以添加一個(gè)新的 age 屬性到嵌套的 userProfile 對(duì)象: this.$set(vm.userProfile, 'age', 27) //還可以使用實(shí)例的 $set 實(shí)例方法,它只是全局 Vue.set 的別名:
一次性往嵌套對(duì)象添加多個(gè)屬性可以使用 Object.assign() 方法。注意,使用 Object.assign() 方法時(shí)必須新生成一個(gè)對(duì)象,然后往該對(duì)象里添加屬性,再將該對(duì)象賦值給需要修改的對(duì)象。不能使用下面的第二、三種方法,修改對(duì)象屬性時(shí)可以使用這兩種方法。
// 應(yīng)該使用的方法 vm.userProfile = Object.assign({}, vm.userProfile, { age: 27, favoriteColor: 'Vue Green' }) // 錯(cuò)誤的使用方法,下面并不會(huì)響應(yīng)式修改或者添加userProfile的屬性 Object.assign(vm.userProfile, { age: 27, favoriteColor: 'Vue Green' }) //這樣也不行 vm.userProfile = Object.assign(vm.userProfile, { age: 27, favoriteColor: 'Vue Green' })
5.2.2、響應(yīng)式刪除對(duì)象屬性
響應(yīng)式刪除對(duì)象屬性可以使用 Vue.delete(obj, 屬性) 或者 this.$delete(obj, 屬性) 方法。
6、Vue中的事件及修飾符
使用 v-on 為DOM元素綁定的事件相當(dāng)于使用 onclick 方式,綁定的事件是在冒泡階段觸發(fā)的。
6.1、事件修飾符(stop、prevent、capture、self、once、passive)
6.2、修飾符串聯(lián)使用
//在沒有默認(rèn)行為的元素里看不出區(qū)別 <div @click.prevent.self="show('aaa')">點(diǎn)擊</div> //點(diǎn)擊后將輸出aaa //在有默認(rèn)行為的元素里就能看出區(qū)別 //點(diǎn)擊百度,先是判斷是否自身行為,結(jié)果不是,所以不會(huì)觸發(fā)click事件,也不會(huì)執(zhí)行后面的阻止默認(rèn)行為,所以 a 標(biāo)簽會(huì)跳轉(zhuǎn)
//輸出:3、1、然后跳轉(zhuǎn) <div @click="show(1)"> <a @click.self.prevent="show(2)"> <div @click="show(3)">百度</div> </a> </div>
//點(diǎn)擊百度,先阻止了默認(rèn)行為,所以 a 標(biāo)簽不會(huì)跳轉(zhuǎn)。然后判斷是否自身行為,結(jié)果不是,所以不會(huì)輸出 2
//輸出:3、1,不跳轉(zhuǎn) <div @click="show(1)"> <a @click.prevent.self="show(2)"> <div @click="show(3)">百度</div> </a> </div> show: function(str){ console.log(str); }
6.3、sync修飾符
官方文檔:https://cn.vuejs.org/v2/guide/components-custom-events.html#.sync修飾符
sync 只是一個(gè)語法糖:
//父組件代碼 <testComponent :title.sync="title"></testComponent> //等價(jià)于 <testComponent :title="title" @update:title="updateTitle"></testComponent> //子組件代碼 <template> <div> {{dateMsg}} <button @click="updateTitle">修改title</button> </div> </template> props: { title: { type: Date } }, data() { return { dateMsg: this.title } }, methods: { updateTitle() { let newVal = new Date(); this.dateMsg = newVal; this.$emit('update:title',newVal); //當(dāng)數(shù)據(jù)更新時(shí)傳遞給父組件,實(shí)現(xiàn)數(shù)據(jù)同步 } },
sync 修飾符的功能只是為了在父組件給子組件傳 props 值時(shí),可以實(shí)現(xiàn)父子組件的數(shù)據(jù)同步更新。
sync 修飾符只是一個(gè)語法糖,它的擴(kuò)展有點(diǎn)像 v-model 在組件上使用時(shí)的情況。
7、Vue生命周期與Vue.nextTick()
7.1、vue的生命周期
Vue 生命周期有八個(gè):beforeCreate、created、beforeMount、mounted、beforeUpdate、update、beforeDestroy、destroyed
- beforeCreate:創(chuàng)建實(shí)例之前。
- created:實(shí)例創(chuàng)建完成(執(zhí)行new Vue(options)),可訪問data、computed、watch、methods上的方法和數(shù)據(jù),可進(jìn)行數(shù)據(jù)請(qǐng)求。但是還未掛載到DOM結(jié)構(gòu)上,不能進(jìn)行dom操作。在生命周期中,要想訪問 methods 或者 data 中的方法和數(shù)據(jù),最早需要在 created 鉤子中操作。
- beforeMount:在掛載開始之前被調(diào)用,此時(shí)只是完成了模板的編譯,但是編譯完成的 HTML 還沒掛載到頁面中,此時(shí)頁面并沒有內(nèi)容。
- mounted:此時(shí)編譯好的 HTML 已經(jīng)掛載到了頁面中,要想操作頁面中的 DOM 節(jié)點(diǎn),最早得在 mounted 鉤子中操作。
- beforeupdate:響應(yīng)式數(shù)據(jù)更新時(shí)調(diào)用,發(fā)生在給虛擬DOM打補(bǔ)丁之前,適合在更新之前訪問現(xiàn)有的DOM,比如用于手動(dòng)移除已添加的事件監(jiān)聽器。
- updated:虛擬 DOM 重新渲染和打補(bǔ)丁之后調(diào)用,此時(shí)組件DOM已經(jīng)更新。
- beforeDestroy:實(shí)例銷毀之前調(diào)用,this 仍能獲取到實(shí)例,常用于銷毀定時(shí)器、解綁全局事件、銷毀插件對(duì)象等操作。
- destroyed: 實(shí)例銷毀之后

參考:https://blog.csdn.net/mqingo/article/details/86031260
7.1.1、父子組件生命周期執(zhí)行順序
加載渲染過程:
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
子組件更新過程:
父beforeUpdate->子beforeUpdate->子updated->父updated
父組件更新過程:
父beforeUpdate->父updated
銷毀過程:
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
7.2、Vue.nextTick() 方法
Vue 更新 DOM 時(shí)是異步執(zhí)行的。(在更新 DOM 時(shí),vue 會(huì)嘗試使用原生的 Promise.then、MutationObserver 和 setInmmediate,如果執(zhí)行環(huán)境不支持這些方法,則會(huì)采用 setTimeout 方法代替)
Vue.nextTick() 接受一個(gè)回調(diào)函數(shù)作為參數(shù),它的作用是將回調(diào)函數(shù)延遲到一次DOM更新之后的操作。如果沒有提供回調(diào)函數(shù)參數(shù)且在支持Promise的環(huán)境中,nextTick將返回一個(gè)Promise。
注意:在組件中應(yīng)該使用 this.$nextTick() 來代替,并且 this.$nextTick() 里面的回調(diào)函數(shù)的 this 自動(dòng)綁定到該組件實(shí)例上。
使用 Vue.nextTick() 方法的場(chǎng)景:
1、在數(shù)據(jù)更新之后
vm.someData = 'new value',DOM并不會(huì)馬上更新,而是在異步隊(duì)列被清除,也就是下一個(gè)事件循環(huán)開始時(shí)執(zhí)行更新時(shí)才會(huì)進(jìn)行必要的 DOM 更新。如果你不用這個(gè)方法而是直接想要根據(jù)更新的 DOM 狀態(tài)去做某些事情,就會(huì)出現(xiàn)問題,因此直接操作時(shí) DOM 還未更新。為了在數(shù)據(jù)變化之后等待 Vue 完成更新 DOM ,可以在數(shù)據(jù)變化之后立即使用 Vue.nextTick(callback) 。這樣回調(diào)函數(shù)在 DOM 更新完成后就會(huì)調(diào)用。
<div id="example">{{message}}</div>
let vm = new Vue({
el: "#example",
data: {
message: '123'
}
})
vm.message = 'new message'
console.log(vm.$el.textContent) //輸出 'message' 直接獲取時(shí),此時(shí)DOM還未更新
Vue.nextTick(function (){
console.log(vm.$el.textContent) //輸出 'new message' 使用該方法,會(huì)在 DOM 更新后才觸發(fā),獲取到的是 DOM 更新后的數(shù)據(jù)
})
2、在 created() 生命周期進(jìn)行 DOM 操作
Vue生命周期的created()鉤子函數(shù)進(jìn)行的DOM操作一定要放在Vue.nextTick()的回調(diào)函數(shù)中。原因是什么呢,原因是在created()鉤子函數(shù)執(zhí)行的時(shí)候DOM 其實(shí)并未進(jìn)行任何渲染,而此時(shí)進(jìn)行DOM操作無異于徒勞,所以此處一定要將DOM操作的js代碼放進(jìn)Vue.nextTick()的回調(diào)函數(shù)中。與之對(duì)應(yīng)的就是mounted鉤子函數(shù),因?yàn)樵撱^子函數(shù)執(zhí)行時(shí)所有的DOM掛載和渲染都已完成,此時(shí)在該鉤子函數(shù)中進(jìn)行任何DOM操作都不會(huì)有問題 。參考:https://www.jianshu.com/p/46c9d777cab1
7.3、Vue.nextTick 和 setTimeout 的執(zhí)行順序
Vue 中 nextTick 比 setTimeout 先執(zhí)行
可以參考:https://segmentfault.com/q/1010000018001188
8、v-cloak避免頁面出現(xiàn){{}}
某些情況下瀏覽器可能會(huì)在系統(tǒng)未解析完數(shù)據(jù)時(shí)就已經(jīng)顯示頁面,此時(shí)就會(huì)顯示出一些Vue的標(biāo)簽,比如可能會(huì)顯示出雙大括號(hào) {{}},此時(shí)可以使用 v-cloak 來避免這種情況。
將 v-cloak 添加至元素中,通過 css 控制 v-cloak 屬性的元素為隱藏,因?yàn)楫?dāng) Vue 解析完后一些指令包括 v-cloak 不會(huì)出現(xiàn)在元素內(nèi),所以當(dāng) Vue 解析完后 css 將不會(huì)起作用,該元素也將顯示出來,這樣就避免了先顯示然后再閃爍的情況。
參考:https://cn.vuejs.org/v2/api/#v-cloak

浙公網(wǎng)安備 33010602011771號(hào)