Vue3啟程
關(guān)鍵字:創(chuàng)建vue實(shí)例、響應(yīng)式、響應(yīng)式原理、組合式API
1. 初始Vue3
Vue2存在一些缺陷,Vue3解決了這些缺陷,剔除了過(guò)濾器,保留了絕大部分的功能,可以說(shuō)更加好用,更加豐富。
我們將Vue2和Vue3對(duì)比一下,就很直觀了:
<div id="app">
<h2>姓名:{{name}}</h2>
<h2>年齡:{{age}}</h2>
<button @click="updateData">修改數(shù)據(jù)</button>
</div>
Vue2中--創(chuàng)建實(shí)例的方式
new Vue({
//指定掛載容器
// el:'#app',
//定義屬性
data() {
return {
name:'張三',
age:20
}
},
//定義方法
methods: {
updateData(){
this.name = '李四'
this.age = 25
}
},
}).$mount('#app') //指定當(dāng)前vue實(shí)例掛載的容器
Vue3中--創(chuàng)建實(shí)例的方式
// Vue3中--創(chuàng)建實(shí)例的方式
Vue.createApp({
//注意:這個(gè)配置對(duì)象里面除了不能寫el選項(xiàng),之前怎么寫,現(xiàn)在還可以怎么寫
//定義屬性
data() {
return {
name:'張三',
age:20
}
},
//定義方法
methods: {
updateData(){
this.name = '李四'
this.age = 25
}
},
}).mount('#app') //只能通過(guò)mount方法指定掛載的容器,不用通過(guò)el選項(xiàng)指定
2. Vue2和Vue3的響應(yīng)式
<div id="app">
<h2>學(xué)生:{{stu}}</h2>
<h2>食物:{{foods}}</h2>
<div>
<button @click="updateStuName">修改學(xué)生姓名</button>
<button @click="addStuSex">添加學(xué)生性別</button>
<button @click="delStuAge">刪除學(xué)生年齡</button>
<button @click="updateFoods2">修改第二個(gè)食物</button>
</div>
</div>
2. Vue2和Vue3的響應(yīng)式
<div id="app">
<h2>學(xué)生:{{stu}}</h2>
<h2>食物:{{foods}}</h2>
<div>
<button @click="updateStuName">修改學(xué)生姓名</button>
<button @click="addStuSex">添加學(xué)生性別</button>
<button @click="delStuAge">刪除學(xué)生年齡</button>
<button @click="updateFoods2">修改第二個(gè)食物</button>
</div>
</div>
// Vue2
new Vue({
data() {
return {
//學(xué)生對(duì)象
stu:{
name:'張三',
age:20
},
//食物數(shù)組
foods:['榴蓮','葡萄','香蕉']
}
},
methods: {
updateStuName(){
this.stu.name = '李四'
},
addStuSex(){
// 直接給對(duì)象添加的屬性,不具備響應(yīng)式
// this.stu.sex = '男'
// 如果要給對(duì)象添加屬性,并且添加的屬性也要具備響應(yīng)式,要使用$set方法
// 方法的第一個(gè)參數(shù)是指定的對(duì)象,第二個(gè)參數(shù)是屬性名,第三個(gè)參數(shù)是屬性值。
this.$set(this.stu,'sex','男')
},
delStuAge(){
// 直接刪除對(duì)象身上的屬性,是不具備響應(yīng)式的
// delete this.stu.age
// 如果要?jiǎng)h除對(duì)象身上的屬性,并且還要具備響應(yīng)式,要使用$delete方法
// 方法的第一個(gè)參數(shù)是指定的對(duì)象,第二個(gè)參數(shù)是屬性名
this.$delete(this.stu,'age')
},
updateFoods2(){
// 直接根據(jù)索引修改數(shù)組元素,不具備響應(yīng)式
// this.foods[1] = '西瓜'
// 操作數(shù)組中的元素,并且還要具備響應(yīng)式,只能使用數(shù)組的以下方法:
// push unshift pop shift splice reverse sort
// this.foods.splice(1,1,'西瓜')
// 如果就是想通過(guò)下標(biāo)去操作數(shù)組,還要具備響應(yīng)式,使用$set方法
this.$set(this.foods,1,'西瓜')
}
},
}).$mount('#app')
// 總結(jié)Vue2的響應(yīng)式:不能直接給對(duì)象添加屬性,刪除對(duì)象的屬性,不能直接操作數(shù)組的下標(biāo),
// 但是,Vue2同時(shí)也提供了解決這些問(wèn)題的方案。
// Vue3
Vue.createApp({
data() {
return {
//學(xué)生對(duì)象
stu:{
name:'張三',
age:20
},
//食物數(shù)組
foods:['榴蓮','葡萄','香蕉']
}
},
methods: {
updateStuName(){
this.stu.name = '李四'
},
addStuSex(){
// 在Vue3中,直接給對(duì)象添加屬性,新的屬性依然具備響應(yīng)式
this.stu.sex = '男'
},
delStuAge(){
// 在Vue3中,直接刪除對(duì)象的屬性,依然具備響應(yīng)式
delete this.stu.age
},
updateFoods2(){
// 在Vue3中,根據(jù)下標(biāo)操作數(shù)組,依然具備響應(yīng)式
this.foods[1] = '西瓜'
}
},
}).mount('#app')
// 總結(jié)Vue3的響應(yīng)式:解決了再Vue2中的所有問(wèn)題。
3. Vue2和Vue3的響應(yīng)式原理
<h2 id="name"></h2>
<h2 id="age"></h2>
// Vue2的響應(yīng)式原理:
// 這里的obj是源對(duì)象
let obj = {
name:'張三',
age:20
}
// 在頁(yè)面中顯示姓名和年齡
document.getElementById('name').innerText = obj.name
document.getElementById('age').innerText = obj.age
// 這里的obj2代理對(duì)象---由obj2代理obj
let obj2 = {}
// 給obj2定義name屬性
Object.defineProperty(obj2,'name',{
get(){
return obj.name
},
set(value){
obj.name = value
document.getElementById('name').innerText = obj.name
}
})
// 給obj2定義age屬性
Object.defineProperty(obj2,'age',{
get(){
return obj.age
},
set(value){
obj.age = value
document.getElementById('age').innerText = obj.age
}
})
// Vue3的響應(yīng)式原理:
// 這里的obj是源對(duì)象
let obj = {
name:'張三',
age:20
}
// 在頁(yè)面中顯示姓名和年齡
document.getElementById('name').innerText = obj.name
document.getElementById('age').innerText = obj.age
// 這里的obj2代理對(duì)象---由obj2代理obj
// new Proxy(源對(duì)象,{...})的方式,創(chuàng)建代理對(duì)象
let obj2 = new Proxy(obj,{
//讀取屬性,參數(shù)分別是:源對(duì)象,屬性名
get(target, property){
// 直接根據(jù)源對(duì)象返回源對(duì)象身上的屬性
// return target[property]
// 通過(guò)發(fā)射對(duì)象,發(fā)射輸出源對(duì)象身上的屬性
return Reflect.get(target,property)
},
//設(shè)置屬性,參數(shù)分別是:源對(duì)象,屬性名,屬性值
set(target, property,value){
// target[property] = value
if(Reflect.has(target,property)){
Reflect.set(target, property,value)
document.getElementById(`${property}`).innerText = value
}
},
//刪除屬性,參數(shù)分別是:源對(duì)象,屬性名
deleteProperty(target, property){
// delete target[property]
Reflect.deleteProperty(target, property)
}
})
4. 引出Vue3新推出的組合式API
這是很棒的一個(gè)功能,和另一個(gè)R框架有點(diǎn)像,讓數(shù)據(jù)和方法在一起,方便維護(hù)。
<div id="app">
<div>
<h2>學(xué)生信息</h2>
<!-- 注意:ref對(duì)象在模板只不需要.value的方式獲取里面的值 -->
<h4>姓名:{{stuName}}</h4>
<h4>年齡:{{stuAge}}</h4>
<button @click="updateStu">修改學(xué)生信息</button>
</div>
<div>
<h2>汽車信息</h2>
<h4>車名:{{carName}}</h4>
<h4>車價(jià):{{carPrice}}</h4>
<button @click="updateCar">修改汽車信息</button>
</div>
<div>
<h2>手機(jī)信息</h2>
<h4>名稱:{{phoneName}}</h4>
<h4>顏色:{{phoneColor}}</h4>
<button @click="updatePhone">修改手機(jī)信息</button>
</div>
<div>
<h2>食物信息</h2>
<h4>名稱:{{foodName}}</h4>
<h4>價(jià)格:{{foodPrice}}</h4>
<button @click="updateFood">修改食物信息</button>
</div>
</div>
什么是組合式API(Composition API),就是Vue推出的一些新的方法,這個(gè)方法在setup中使用, 從Vue身上獲取ref組合式API函數(shù)
let {ref} = Vue
Vue.createApp({
// 注意:Vue2中,Vue實(shí)例的data選項(xiàng)可以是一個(gè)對(duì)象,也可以是一個(gè)方法,由方法返回一個(gè)對(duì)象
// 但是,組件中data選項(xiàng)必須是一個(gè)方法。
// Vue3中,無(wú)論是Vue實(shí)例,還是組件,data選項(xiàng)都必須是一個(gè)方法。
// 我們之前習(xí)慣將所有的數(shù)據(jù)放在data選項(xiàng)中定義,所有的方法放在methods選項(xiàng)中定義,
// 所有的計(jì)算屬性放在computed選項(xiàng)中定義,所有的偵聽器放在watch選項(xiàng)中定義,
// 這樣就會(huì)導(dǎo)致一個(gè)業(yè)務(wù)的代碼會(huì)拆分到多個(gè)結(jié)構(gòu)中去寫,如果一個(gè)頁(yè)面中要操作很多個(gè)業(yè)務(wù),代碼后期維護(hù)成本會(huì)很高。
// 所以,Vue3引入了組合式API,簡(jiǎn)化之前繁瑣的過(guò)程,將相同業(yè)務(wù)的代碼靠在一起寫。
/* data: function () {
return {
//定義學(xué)生數(shù)據(jù)
stuName: '張三',
stuAge: '20',
//汽車信息
carName: '奔馳',
carPrice: '50W',
//手機(jī)信息
phoneName: 'iphone',
phoneColor: '白色',
//食物信息
foodName: '漢堡',
foodPrice: '¥20'
}
},
methods: {
//修改學(xué)生的方法
updateStu(){
this.stuName = '李四'
this.stuAge = 30
},
//修改汽車的方法
updateCar(){
this.carName = '寶馬'
this.carPrice = '40W'
},
//修改手機(jī)的方法
updatePhone(){
this.phoneName = '華為'
this.phoneColor = '藍(lán)色'
},
updateFood(){
this.foodName = '蛋糕'
this.foodPrice = '¥30'
}
}, */
// setup方法是所有組合式API的入口
setup() {
// 定義學(xué)生的信息
// 在setup中,直接定義的數(shù)據(jù)是不具備響應(yīng)式的,
// 如果要使數(shù)據(jù)具備響應(yīng)式,需要使用ref組合式API對(duì)數(shù)據(jù)進(jìn)行包裝,包裝后返回的是ref對(duì)象
let stuName = ref('張三')
let stuAge = ref('20')
let updateStu = () => {
//ref對(duì)象的value屬性保存的是值
stuName.value = '李四'
stuAge.value = 30
}
// 定義汽車的信息
let carName = ref('奔馳')
let carPrice = ref('50W')
let updateCar = () => {
carName.value = '寶馬'
carPrice.value = '40W'
}
// 定義手機(jī)的信息
let phoneName = ref('iphone')
let phoneColor = ref('白色')
let updatePhone = () => {
phoneName.value = '華為'
phoneColor.value = '藍(lán)色'
}
// 定義食物的信息
let foodName = ref('漢堡')
let foodPrice = ref('¥20')
let updateFood = () => {
foodName.value = '蛋糕'
foodPrice.value = '¥30'
}
//返回模板中需要使用的數(shù)據(jù)
return{
stuName,
stuAge,
updateStu,
carName,
carPrice,
updateCar,
phoneName,
phoneColor,
updatePhone,
foodName,
foodPrice,
updateFood
}
}
}).mount('#app')