一.創(chuàng)建vue工程方式有兩種
- 傳統(tǒng)的 vue-cli 方式
##首先保證本地的vue-cli版本在4.5.0以上
vue --version
##如果不是,先升級(jí)最新的vue-cli工具
npm i -g @vue\vue-cli
## 然后和之前的創(chuàng)建vue2的方式一樣。
vue init webapack <project-name> ## 打包工具指定的是webpack
## 在后續(xù)list中,選擇[vue3]即可。
傳統(tǒng)的方式創(chuàng)建vue3,也沒(méi)問(wèn)題,但是這樣一來(lái)的打包工具仍然是webpack。
- 使用 vite 創(chuàng)建
## 創(chuàng)建工程
npm init vite-app <project-name> # 指定了腳手架為vite 以及項(xiàng)目框架是vue3.x [為什么是vue3.0框架?因?yàn)檫@個(gè)vite工具就是vue3開(kāi)發(fā)團(tuán)隊(duì)寫(xiě)的,所以人家直接默認(rèn)就用 vite-app 創(chuàng)建的項(xiàng)目就是基于 vue3.0]
## 進(jìn)入功能目錄
cd <project-name>
## 安裝依賴
npm install
## 運(yùn)行
npm run dev
使用 vite 方式創(chuàng)建,打包工具就是 vite 了,項(xiàng)目也沒(méi)有什么 build 文件夾,以及一堆 webpack.config.js webpack.base.js xxxxxx
二、 vue3.0中main.js文件
在 vue2.x 中,我們的 main.js 是這么寫(xiě)的。
import Vue from 'vue'
import App from './App'
const vm = new Vue({
render(h) => h(App)
})
vm.$mount('#app')
在 vue3.0中是這么寫(xiě)的。
import { createApp } from 'vue'
import App from './App'
const app = createApp(App)
app.mount('#app')
在vue2.0中,我們直接調(diào)用 new Vue 構(gòu)造函數(shù)創(chuàng)建一個(gè)vm實(shí)例。在v3.0中,我們使用 createApp函數(shù),傳遞進(jìn)去一個(gè)options對(duì)象,來(lái)創(chuàng)建一個(gè)app實(shí)例。 后面的掛載都是一樣的。
你把 app 和 vm 打印到控制臺(tái)查看一下,就會(huì)發(fā)現(xiàn) app 比 vm 屬性少很多,也就是說(shuō) vue3.0 里的 app 更為輕量。
三、 Vue3.0中的 setup 函數(shù)
在 vue2.x 中,我們定義組件的數(shù)據(jù),方法,計(jì)算屬性,watch等都是以配置選項(xiàng)的方式來(lái)進(jìn)行的。
export default {
name: 'App',
data () {
return {
num:1
}
},
methods: {},
computed: {},
watch: {}
}
在 vue3.0 中,所有需要的上述組件配置,都應(yīng)該定義在 setup 函數(shù)里,并返回。(為什么要返回?返回才會(huì)掛載在當(dāng)前組件實(shí)例上,才能在模板中使用。)
export default {
name: 'App',
setup () {
// 我定義的函數(shù)
// 我定義的數(shù)據(jù)
// 我定義的watch
// 我定義的計(jì)算屬性
// .....
return {
我定義的函數(shù),
我定義的數(shù)據(jù),
我定義的,
我定義的計(jì)算屬性
}
}
}
四、vue3.0中的ref函數(shù)
vue2.0 和 vue3.0 配置數(shù)據(jù)響應(yīng)式也有區(qū)別。
在 vue2.0中,我們把數(shù)據(jù)放在 data 選項(xiàng)里,就可以完成響應(yīng)式的配置了。
在vue3.0中,提供了更精細(xì)化的響應(yīng)式數(shù)據(jù)配置。
// vue3.0 ref 函數(shù)功能說(shuō)明
import { ref } from 'vue'
export default {
name: 'App',
setup () {
// 定義一個(gè)基本數(shù)據(jù)類型響應(yīng)式
let num = ref(100)
// 返回的是一個(gè) RefImpl 的對(duì)象 RefImpl { ......}
// 使用num
num.value = 100 // 觸發(fā)setter
console.log(num.value) // 觸發(fā)getter
// 定義一個(gè)對(duì)象類型數(shù)
let obj = ref({
name: '張三-老工具人了',
job: {
detail: {
title: '前端開(kāi)發(fā)',
salary: 30
}
}
})
// 修改name屬性
obj.value.name = '李四' //
obj.value.job.detail.title = 'python開(kāi)發(fā)'
// tips: 可能有人覺(jué)得,obj.value.xxx 不如 obj.xxx 直接來(lái)的直觀,但是 ref 定義數(shù)據(jù)響應(yīng)式就是有這么一個(gè)特點(diǎn)。
return {
num, // 在模板中,使用num,不需要加.value
obj
}
}
}
// ref 函數(shù)內(nèi)部邏輯
// 1. 如果你傳遞的參數(shù)是基本數(shù)據(jù)類型,那么內(nèi)部直接使用Object.defineProperty來(lái)定義一個(gè)新屬性叫.value來(lái)實(shí)現(xiàn)響應(yīng)式。
// 2. 如果你傳遞的是一個(gè)對(duì)象數(shù)據(jù)類型,那么內(nèi)部使用 new Proxy 來(lái)定義數(shù)據(jù)的響應(yīng)式。
// 所以,對(duì)于ref來(lái)說(shuō),內(nèi)部選擇使用 Object.defineProperty 還是 new Proxy 取決于你傳遞進(jìn)來(lái)的數(shù)據(jù).
// 大概邏輯如下.
function ref (value) {
return new RefImpl(value)
}
function RefImpl (value) {
this.__v_Ref = true
this.__rawValue = value
this.__newValue = value
// this.__shallowRef = fasle
if (typeof value !== 'object') {
Object.define(this,'value', {
get () {
return this.__newValue
},
set (newVal) {
this.__newValue = newVal
}
})
} else {
this.value = new Proxy (this,{
get (target,propertyName) {
return Reflect.get(target,propertyName)
},
set (target,propertyName,value) {
Reflect.set(target,proeprtyName,value)
},
deleteProperty (target,propertyName) {
//...監(jiān)聽(tīng)delete屬性操作...
Reflect.delete(target,propertyName)
},
})
}
}
如果你給 ref 傳遞的是基本數(shù)據(jù)類型,那么 .value 拿到的就是由 Object.defineProperty定義的那個(gè) .value 屬性。
如果你給 ref 傳遞的是對(duì)象數(shù)據(jù)類型,那么 .value 拿到的就是有 new Proxy 定義的那個(gè)對(duì)象。
五、 vue3.0 中的 reactive 函數(shù)
在ref函數(shù)介紹里,我們有這么一段代碼
let obj = ref({
name: '張三-老工具人了',
job: {
detail: {
title: '前端開(kāi)發(fā)',
salary: 30
}
}
})
obj.value.name = '李四' //
obj.value.job.detail.title = 'python開(kāi)發(fā)'
// 可能有人覺(jué)得,obj.value.xxx 不如 obj.xxx 直接來(lái)的直觀,但是 ref 定義數(shù)據(jù)響應(yīng)式就是有這么一個(gè)特點(diǎn)。
可能有人覺(jué)得,obj.value.xxx 不如 obj.xxx 直接來(lái)的直觀,但是 ref 定義數(shù)據(jù)響應(yīng)式就是有這么一個(gè)特點(diǎn)。
所以,使用 ref 定義對(duì)象類型數(shù)據(jù),并不是很好的方式。
于是就有了 reactive 函數(shù)。
import { reactive } from 'vue'
export default {
name:'App',
setup () {
let person = reactive({
name: '張三-老工具人了',
job: {
detail: {
title: '前端開(kāi)發(fā)',
salary: 30
}
}
})
/// 訪問(wèn)數(shù)據(jù)
console.log(person.name)
// 修改屬性
person.job.detail.title = 'python開(kāi)發(fā)' // 就沒(méi)有煩人的.value了。
return {
person
}
}
}
所以,對(duì)于對(duì)象數(shù)據(jù)類型,使用 reactive 比 ref 更為合適。
建議: 基本數(shù)據(jù)類型,使用 ref, 對(duì)象類型使用 reactive
注意:不要給基本數(shù)據(jù)類型使用reactive做響應(yīng)式,否則被報(bào)錯(cuò)
let num = reactive(0)
value cannot be made reactive: 0
總結(jié)ref和reactive
- ref 可以定義基本數(shù)據(jù)類型響應(yīng)式,也可以定義對(duì)象類型數(shù)據(jù)響應(yīng)式
- 當(dāng)你給
ref傳遞基本數(shù)據(jù)類型時(shí),其內(nèi)部的.value是使用的Object.defineProperty來(lái)實(shí)現(xiàn)響應(yīng)式。 - 當(dāng)給你
ref傳遞對(duì)象類型數(shù)據(jù)是,其內(nèi)部的.value是使用的new Proxy來(lái)實(shí)現(xiàn)響應(yīng)式。 - 使用
ref定義響應(yīng)式,想訪問(wèn)到真實(shí)的數(shù)據(jù),必須加一個(gè).value
- 當(dāng)你給
-
reactive只能定義對(duì)象類型數(shù)據(jù)響應(yīng)式