好久沒(méi)上傳了,閑來(lái)無(wú)事把囤積已久的筆記給上傳上傳 1. Vue3簡(jiǎn)介 2020年9月18日,Vue.js發(fā)布版3.0版本,代號(hào):One Piece(n 經(jīng)歷了:4800+次提交、40+個(gè)RFC、600+次PR、300+貢獻(xiàn)者 官方發(fā)版地址:Release v3.0.0 One Piece ·
好久沒(méi)上傳了,閑來(lái)無(wú)事把囤積已久的筆記給上傳上傳
2020年9月18日,
Vue.js
發(fā)布版
3.0
版本,代號(hào):
One Piece
(n
經(jīng)歷了: 4800+次提交 、 40+個(gè)RFC 、 600+次PR 、 300+貢獻(xiàn)者
官方發(fā)版地址: Release v3.0.0 One Piece · vuejs/core
截止2023年10月,最新的公開(kāi)版本為:
3.3.4
打包大小減少
41%
。
初次渲染快
55%
, 更新渲染快
133%
。
內(nèi)存減少
54%
。
使用
Proxy
代替
defineProperty
實(shí)現(xiàn)響應(yīng)式。
重寫(xiě)虛擬
DOM
的實(shí)現(xiàn)和
Tree-Shaking
。
Vue3
可以更好的支持
TypeScript
。
Composition API
(組合
API
):
setup
ref
與
reactive
computed
與
watch
......
新的內(nèi)置組件:
Fragment
Teleport
Suspense
......
其他改變:
新的生命周期鉤子
data
選項(xiàng)應(yīng)始終被聲明為一個(gè)函數(shù)
移除
keyCode
支持作為
v-on
的修飾符
......
點(diǎn)擊查看 官方文檔
備注:目前
vue-cli
已處于維護(hù)模式,官方推薦基于Vite
創(chuàng)建項(xiàng)目。
## 查看@vue/cli版本,確保@vue/cli版本在4.5.0以上
vue --version
## 安裝或者升級(jí)你的@vue/cli
npm install -g @vue/cli
## 執(zhí)行創(chuàng)建命令
vue create vue_test
## 隨后選擇3.x
## Choose a version of Vue.js that you want to start the project with (Use arrow keys)
## > 3.x
## 2.x
## 啟動(dòng)
cd vue_test
npm run serve
vite
是新一代前端構(gòu)建工具,官網(wǎng)地址:
https://vitejs.cn
,
vite
的優(yōu)勢(shì)如下:
輕量快速的熱重載(
HMR
),能實(shí)現(xiàn)極速的服務(wù)啟動(dòng)。
對(duì)
TypeScript
、
JSX
、
CSS
等支持開(kāi)箱即用。
真正的按需編譯,不再等待整個(gè)應(yīng)用編譯完成。
webpack
構(gòu)建 與
vite
構(gòu)建對(duì)比圖如下:
## 1.創(chuàng)建命令
npm create vue@latest
## 2.具體配置
## 配置項(xiàng)目名稱
√ Project name: vue3_test
## 是否添加TypeScript支持
√ Add TypeScript? Yes
## 是否添加JSX支持
√ Add JSX Support? No
## 是否添加路由環(huán)境
√ Add Vue Router for Single Page Application development? No
## 是否添加pinia環(huán)境
√ Add Pinia for state management? No
## 是否添加單元測(cè)試
√ Add Vitest for Unit Testing? No
## 是否添加端到端測(cè)試方案
√ Add an End-to-End Testing Solution? ? No
## 是否添加ESLint語(yǔ)法檢查
√ Add ESLint for code quality? Yes
## 是否添加Prettiert代碼格式化
√ Add Prettier for code formatting? No
自己動(dòng)手編寫(xiě)一個(gè)App組件
你好!
安裝官方推薦的
vscode
插件:
總結(jié):
Vite
項(xiàng)目中,
index.html
是項(xiàng)目的入口文件,在項(xiàng)目最外層。
index.html
后,
Vite
解析
Vue2
的
API
設(shè)計(jì)是
Options
(配置)風(fēng)格的。
Vue3
的
API
設(shè)計(jì)是
Composition
(組合)風(fēng)格的。
Options
類(lèi)型的
API
,數(shù)據(jù)、方法、計(jì)算屬性等,是分散在:
data
、
methods
、
computed
中的,若想新增或者修改一個(gè)需求,就需要分別修改:
data
、
methods
、
computed
,不便于維護(hù)和復(fù)用。
可以用函數(shù)的方式,更加優(yōu)雅的組織代碼,讓相關(guān)功能的代碼更加有序的組織在一起。
說(shuō)明:以上四張動(dòng)圖原創(chuàng)作者:大帥老猿
setup
是
Vue3
中一個(gè)新的配置項(xiàng),值是一個(gè)函數(shù),它是
Composition API
“表演的舞臺(tái)
”
,組件中所用到的:數(shù)據(jù)、方法、計(jì)算屬性、監(jiān)視......等等,均配置在
setup
中。
特點(diǎn)如下:
setup
函數(shù)返回的對(duì)象中的內(nèi)容,可直接在模板中使用。
setup
中訪問(wèn)
this
是
undefined
。
setup
函數(shù)會(huì)在
beforeCreate
之前調(diào)用,它是“領(lǐng)先”所有鉤子執(zhí)行的。
姓名:{{name}}
年齡:{{age}}
setup(){
return ()=> '你好!'
}
Vue2
的配置(
data
、
methos
......)中
可以訪問(wèn)到
setup
中的屬性、方法。
setup
中
不能訪問(wèn)到
Vue2
的配置(
data
、
methos
......)。
Vue2
沖突,則
setup
優(yōu)先。
setup
函數(shù)有一個(gè)語(yǔ)法糖,這個(gè)語(yǔ)法糖,可以讓我們把
setup
獨(dú)立出去,代碼如下:
姓名:{{name}}
年齡:{{age}}
這樣寫(xiě)了之后,之前的script一般就拿來(lái)寫(xiě)個(gè)name就可以了,但是只是寫(xiě)個(gè)name專門(mén)用個(gè)script標(biāo)簽麻煩,所以可以借助下面的方法
直接在steup的script標(biāo)簽寫(xiě)上
擴(kuò)展:上述代碼,還需要編寫(xiě)一個(gè)不寫(xiě)
setup
的
script
標(biāo)簽,去指定組件名字,比較麻煩,我們可以借助
vite
中的插件簡(jiǎn)化
npm i vite-plugin-vue-setup-extend -D
vite.config.ts
import { defineConfig } from 'vite'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
export default defineConfig({
plugins: [ VueSetupExtend() ]
})
ref
,否則報(bào)錯(cuò))
let 響應(yīng)式對(duì)象= reactive(源對(duì)象)
。
Proxy
的實(shí)例對(duì)象,簡(jiǎn)稱:響應(yīng)式對(duì)象。
這個(gè)是將一個(gè)對(duì)象編程一個(gè)proxy創(chuàng)建的對(duì)象接受響應(yīng)式(數(shù)組同理也是這個(gè)方法)
reactive
定義的響應(yīng)式數(shù)據(jù)是“深層次”的。
汽車(chē)信息:一臺(tái){{ car.brand }}汽車(chē),價(jià)值{{ car.price }}萬(wàn)
游戲列表:
- {{ g.name }}
測(cè)試:{{obj.a.b.c.d}}
ref
接收的數(shù)據(jù)可以是:
基本類(lèi)型
、
對(duì)象類(lèi)型
。
ref可以對(duì)對(duì)象響應(yīng)式數(shù)據(jù),但是注意改的時(shí)候要加value,特別是數(shù)組形式加在哪里
其原理還是把變量做了一個(gè)響應(yīng)式變成了value形式,但是里面的對(duì)象還是做了一個(gè)proxy
ref
接收的是對(duì)象類(lèi)型,內(nèi)部其實(shí)也是調(diào)用了
reactive
函數(shù)。
汽車(chē)信息:一臺(tái){{ car.brand }}汽車(chē),價(jià)值{{ car.price }}萬(wàn)
游戲列表:
- {{ g.name }}
測(cè)試:{{obj.a.b.c.d}}
宏觀角度看:
ref
用來(lái)定義: 基本類(lèi)型數(shù)據(jù) 、 對(duì)象類(lèi)型數(shù)據(jù) ;
reactive
用來(lái)定義: 對(duì)象類(lèi)型數(shù)據(jù) 。
ref
創(chuàng)建的變量必須使用.value
(可以使用volar
插件自動(dòng)添加.value
)。
reactive
重新分配一個(gè)新對(duì)象,會(huì) 失去 響應(yīng)式(可以使用Object.assign
去整體替換)。
這樣寫(xiě)也不行
可以這樣
如果是用的ref響應(yīng)對(duì)象,就可以直接改
- 若需要一個(gè)基本類(lèi)型的響應(yīng)式數(shù)據(jù),必須使用
ref
。- 若需要一個(gè)響應(yīng)式對(duì)象,層級(jí)不深,
ref
、reactive
都可以。- 若需要一個(gè)響應(yīng)式對(duì)象,且層級(jí)較深,推薦使用
reactive
。
如果像這樣解構(gòu)賦值,那么出來(lái)的name age都不是響應(yīng)式數(shù)據(jù)
想讓響應(yīng)式數(shù)據(jù)轉(zhuǎn)換出來(lái)也是響應(yīng)式就押用到這個(gè)
ref
對(duì)象。
注意:torefs之后會(huì)創(chuàng)建一個(gè)新的reactive響應(yīng)式對(duì)象,但是值都是指向同一個(gè)值你修改一個(gè)兩個(gè)都會(huì)變
toRefs
與
toRef
功能一致,但
toRefs
可以批量轉(zhuǎn)換。
姓名:{{person.name}}
年齡:{{person.age}}
性別:{{person.gender}}
作用:根據(jù)已有數(shù)據(jù)計(jì)算出新數(shù)據(jù)(和
Vue2
中的
computed
作用一致)。
計(jì)算屬性本身是監(jiān)視它里面的值的變化從而引起自身的變化,所以要改他的時(shí)候,也不是直接改他本身,而是改他里面的值
姓:
名:
全名:{{fullName}}
Vue2
中的
watch
作用一致)
Vue3
中的
watch
只能監(jiān)視以下
四種數(shù)據(jù)
:
ref
定義的數(shù)據(jù)。reactive
定義的數(shù)據(jù)。- 函數(shù)返回一個(gè)值(
getter
函數(shù))。- 一個(gè)包含上述內(nèi)容的數(shù)組。
我們?cè)?
Vue3
中使用
watch
的時(shí)候,通常會(huì)遇到以下幾種情況:
監(jiān)視
ref
定義的【基本類(lèi)型】數(shù)據(jù):直接寫(xiě)數(shù)據(jù)名即可,監(jiān)視的是其
value
值的改變。
stopwatch監(jiān)視會(huì)返回一個(gè)值是一個(gè)箭頭函數(shù),調(diào)用這個(gè)函數(shù)可以取消掉監(jiān)視
情況一:監(jiān)視【ref】定義的【基本類(lèi)型】數(shù)據(jù)
當(dāng)前求和為:{{sum}}
監(jiān)視
ref
定義的【對(duì)象類(lèi)型】數(shù)據(jù):直接寫(xiě)數(shù)據(jù)名,監(jiān)視的是對(duì)象的【地址值】,若想監(jiān)視對(duì)象內(nèi)部的數(shù)據(jù),要手動(dòng)開(kāi)啟深度監(jiān)視。
注意:
- 若修改的是
ref
定義的對(duì)象中的屬性,newValue
和oldValue
都是新值,因?yàn)樗鼈兪峭粋(gè)對(duì)象。
- 若修改整個(gè)
ref
定義的對(duì)象,newValue
是新值,oldValue
是舊值,因?yàn)椴皇峭粋(gè)對(duì)象了。不開(kāi)啟深度,整個(gè)對(duì)象改變了,才會(huì)觸發(fā)監(jiān)視
情況二:監(jiān)視【ref】定義的【對(duì)象類(lèi)型】數(shù)據(jù)
姓名:{{ person.name }}
年齡:{{ person.age }}
監(jiān)視
reactive
定義的【對(duì)象類(lèi)型】數(shù)據(jù),且
默認(rèn)開(kāi)啟了深度監(jiān)視
。
并且修改屬性新老value還是一樣的
情況三:監(jiān)視【reactive】定義的【對(duì)象類(lèi)型】數(shù)據(jù)
姓名:{{ person.name }}
年齡:{{ person.age }}
測(cè)試:{{obj.a.b.c}}
監(jiān)視
ref
或
reactive
定義的【對(duì)象類(lèi)型】數(shù)據(jù)中的
某個(gè)屬性
,注意點(diǎn)如下:
若該屬性值 不是 【對(duì)象類(lèi)型】,需要寫(xiě)成函數(shù)形式。
若該屬性值是 依然 是【對(duì)象類(lèi)型】,可直接寫(xiě),也可寫(xiě)成函數(shù),建議寫(xiě)成函數(shù)。
但是此時(shí)如果是這整個(gè)對(duì)象改變不會(huì)監(jiān)視到
這樣就是這個(gè)對(duì)象怎么變都監(jiān)視得到,寫(xiě)成函數(shù)是為了整個(gè)對(duì)象變,deep是對(duì)象里面變化
結(jié)論:監(jiān)視的要是對(duì)象里的屬性,那么最好寫(xiě)函數(shù)式,注意點(diǎn):若是對(duì)象監(jiān)視的是地址值,需要關(guān)注對(duì)象內(nèi)部,需要手動(dòng)開(kāi)啟深度監(jiān)視。
情況四:監(jiān)視【ref】或【reactive】定義的【對(duì)象類(lèi)型】數(shù)據(jù)中的某個(gè)屬性
姓名:{{ person.name }}
年齡:{{ person.age }}
汽車(chē):{{ person.car.c1 }}、{{ person.car.c2 }}
監(jiān)視上述的多個(gè)數(shù)據(jù)
寫(xiě)成數(shù)組形式就可以,value是這個(gè)數(shù)組
情況五:監(jiān)視上述的多個(gè)數(shù)據(jù)
姓名:{{ person.name }}
年齡:{{ person.age }}
汽車(chē):{{ person.car.c1 }}、{{ person.car.c2 }}
官網(wǎng):立即運(yùn)行一個(gè)函數(shù),同時(shí)響應(yīng)式地追蹤其依賴,并在依賴更改時(shí)重新執(zhí)行該函數(shù)。
watch
對(duì)比
watchEffect
都能監(jiān)聽(tīng)響應(yīng)式數(shù)據(jù)的變化,不同的是監(jiān)聽(tīng)數(shù)據(jù)變化的方式不同
watch
:要明確指出監(jiān)視的數(shù)據(jù)
watchEffect
:不用明確指出監(jiān)視的數(shù)據(jù)(函數(shù)中用到哪些屬性,那就監(jiān)視哪些屬性)。
比如這個(gè)例子,都可以完成但是watcheffect上來(lái)就執(zhí)行一次,而且會(huì)根據(jù)里面所寫(xiě)的自動(dòng)監(jiān)測(cè)要監(jiān)視誰(shuí)
示例代碼:
需求:水溫達(dá)到50℃,或水位達(dá)到20cm,則聯(lián)系服務(wù)器
水溫:{{temp}}
水位:{{height}}
作用:用于注冊(cè)模板引用。
用在普通
DOM
標(biāo)簽上,獲取的是DOM
節(jié)點(diǎn)。用在組件標(biāo)簽上,獲取的是組件實(shí)例對(duì)象。
用在普通
DOM
標(biāo)簽上:
尚硅谷
前端
Vue
用在組件標(biāo)簽上:
但是要獲取組件上的數(shù)據(jù)需要子組件做出defineexpose導(dǎo)出操作
注意vue3引用組件直接導(dǎo)入即可
如果在子組件定義了一組數(shù)據(jù),但是不小心名字打錯(cuò)了
后期就容易調(diào)用不到
我們就可以去定義一個(gè)接口來(lái)約束類(lèi)型,一般是在src下面創(chuàng)建一個(gè)types文件夾,然后導(dǎo)出
要用的話就在組件導(dǎo)入,并且前面要加type表明導(dǎo)入的是一個(gè)類(lèi)型,然后在要用的變量后規(guī)則如下
如果是一個(gè)數(shù)組數(shù)據(jù)想這樣用就不行
除非是用泛型先規(guī)定它是一個(gè)數(shù)組,然后數(shù)組里面每一項(xiàng)需要符合這個(gè)規(guī)則
當(dāng)然也可以去自定義類(lèi)型,直接在ts里面聲明
// 定義一個(gè)接口,限制每個(gè)Person對(duì)象的格式 export interface PersonInter { id:string, name:string, age:number } // 定義一個(gè)自定義類(lèi)型Persons export type Persons = Array
App.vue
中代碼:注意用reactive響應(yīng)式數(shù)據(jù),此時(shí)接口應(yīng)該用泛型來(lái)約束,而且數(shù)據(jù)是不能多不能少的
如果某個(gè)屬性想可有可無(wú)
Person.vue
中代碼:只接受會(huì)出問(wèn)題,萬(wàn)一傳過(guò)來(lái)是個(gè)數(shù)字 也會(huì)遍歷
注意接收+限制類(lèi)型的寫(xiě)法,prop括號(hào)里面不寫(xiě)了,提出來(lái)規(guī)定一個(gè)泛型,里面為一個(gè)對(duì)象,誰(shuí)要約束什么
限制必要性,一個(gè)?父組件就可傳可不傳了
如果不寫(xiě)自己還有默認(rèn)值,導(dǎo)入,再用
用的時(shí)候注意,把原來(lái)寫(xiě)的全部包起來(lái),第二個(gè)參數(shù)寫(xiě)默認(rèn)值,并且鍵值對(duì),屬性值不能為一個(gè)數(shù)組形式,可以寫(xiě)為一個(gè)函數(shù)返回
- {{item.name}}--{{item.age}}
規(guī)律:
生命周期整體分為四個(gè)階段,分別是: 創(chuàng)建、掛載、更新、銷(xiāo)毀 ,每個(gè)階段都有兩個(gè)鉤子,一前一后。
Vue2
的生命周期
創(chuàng)建階段:
beforeCreate
、created
掛載階段:
beforeMount
、mounted
更新階段:
beforeUpdate
、updated
銷(xiāo)毀階段:
beforeDestroy
、destroyed
v3的創(chuàng)建就是setup本身
Vue3
的生命周期
創(chuàng)建階段:
setup
掛載階段:
onBeforeMount
、onMounted
更新階段:
onBeforeUpdate
、onUpdated
卸載階段:
onBeforeUnmount
、onUnmounted
常用的鉤子:
onMounted
(掛載完畢)、
onUpdated
(更新完畢)、
onBeforeUnmount
(卸載之前)
示例代碼:
當(dāng)前求和為:{{ sum }}
如果一個(gè)頁(yè)面中全是數(shù)據(jù)和方法,看起很臃腫復(fù)雜,跟vue2又很像
注意:如果要往空數(shù)組push等作出操作需要規(guī)定數(shù)組的泛型
而hooks就類(lèi)似于mixin,把所有代碼模塊化,src創(chuàng)建文件夾hooks,創(chuàng)建模塊的ts文件,把該屬于這個(gè)部分的代碼都放進(jìn)來(lái)
注意:這里面就跟剛才一樣什么都能寫(xiě)包括生命鉤子,但是會(huì)對(duì)外暴露一個(gè)函數(shù),然后把所有數(shù)據(jù)方法返回
組件要用就直接導(dǎo)入,并且那邊是函數(shù),這邊直接調(diào)用,通過(guò)解構(gòu)賦值,獲得return出來(lái)的數(shù)據(jù)和方法
示例代碼:
useSum.ts
中內(nèi)容如下:
import {ref,onMounted} from 'vue'
export default function(){
let sum = ref(0)
const increment = ()=>{
sum.value += 1
}
const decrement = ()=>{
sum.value -= 1
}
onMounted(()=>{
increment()
})
//向外部暴露數(shù)據(jù)
return {sum,increment,decrement}
}
useDog.ts
中內(nèi)容如下:
import {reactive,onMounted} from 'vue'
import axios,{AxiosError} from 'axios'
export default function(){
let dogList = reactive([])
// 方法
async function getDog(){
try {
// 發(fā)請(qǐng)求
let {data} = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
// 維護(hù)數(shù)據(jù)
dogList.push(data.message)
} catch (error) {
// 處理錯(cuò)誤
const err = error
console.log(err.message)
}
}
// 掛載鉤子
onMounted(()=>{
getDog()
})
//向外部暴露數(shù)據(jù)
return {dogList,getDog}
}
組件中具體使用:
當(dāng)前求和為:{{sum}}
加載中......
Vue3
中要使用
vue-router
的最新版本,目前是
4
版本。
基本規(guī)則
第一步,創(chuàng)建導(dǎo)航區(qū),展示區(qū)
入口文件導(dǎo)入注冊(cè)
路由配置文件代碼如下:
import {createRouter,createWebHistory} from 'vue-router'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import About from '@/pages/About.vue'
const router = createRouter({
history:createWebHistory(),
routes:[
{
path:'/home',
component:Home
},
{
path:'/about',
component:About
}
]
})
export default router
main.ts
代碼如下:
import router from './router/index'
app.use(router)
app.mount('#app')
App.vue
代碼如下
第三步
Vue路由測(cè)試
路由組件通常存放在
pages
或views
文件夾,一般組件通常存放在components
文件夾。通過(guò)點(diǎn)擊導(dǎo)航,視覺(jué)效果上“消失” 了的路由組件,默認(rèn)是被 卸載 掉的,需要的時(shí)候再去 掛載 。
history
模式
優(yōu)點(diǎn):
URL
更加美觀,不帶有#
,更接近傳統(tǒng)的網(wǎng)站URL
。缺點(diǎn):后期項(xiàng)目上線,需要服務(wù)端配合處理路徑問(wèn)題,否則刷新會(huì)有
404
錯(cuò)誤。const router = createRouter({ history:createWebHistory(), //history模式 /******/ })
hash
模式
優(yōu)點(diǎn):兼容性更好,因?yàn)椴恍枰⻊?wù)器端處理路徑。
缺點(diǎn):
URL
帶有#
不太美觀,且在SEO
優(yōu)化方面相對(duì)較差。const router = createRouter({ history:createWebHashHistory(), //hash模式 /******/ })
主頁(yè)
Home
作用:可以簡(jiǎn)化路由跳轉(zhuǎn)及傳參(后面就講)。
給路由規(guī)則命名:
routes:[
{
name:'zhuye',
path:'/home',
component:Home
},
{
name:'xinwen',
path:'/news',
component:News,
},
{
name:'guanyu',
path:'/about',
component:About
}
]
跳轉(zhuǎn)路由:
跳轉(zhuǎn)
跳轉(zhuǎn)
編寫(xiě)
News
的子路由:
Detail.vue
配置路由規(guī)則,使用
children
配置項(xiàng):
const router = createRouter({
history:createWebHistory(),
routes:[
{
name:'zhuye',
path:'/home',
component:Home
},
{
name:'xinwen',
path:'/news',
component:News,
children:[
{
name:'xiang',
path:'detail',
component:Detail
}
]
},
{
name:'guanyu',
path:'/about',
component:About
}
]
})
export default router
跳轉(zhuǎn)路由(記得要加完整路徑):
xxxx
xxxx
記得去
Home
組件中預(yù)留一個(gè)
傳遞參數(shù)
跳轉(zhuǎn)
{{news.title}}
接收參數(shù):
import {useRoute} from 'vue-router'
const route = useRoute()
// 打印query參數(shù)
console.log(route.query)
接收參數(shù)解構(gòu)賦值版
但是這樣有個(gè)問(wèn)題,之前說(shuō)過(guò)在響應(yīng)式對(duì)象上面直接解構(gòu),會(huì)讓他失去響應(yīng)式,解決方法是一個(gè)torefs
要配置
傳遞參數(shù)
{{news.title}}
{{news.title}}
接收參數(shù):
import {useRoute} from 'vue-router'
const route = useRoute()
// 打印params參數(shù)
console.log(route.params)
備注1:傳遞
params
參數(shù)時(shí),若使用to
的對(duì)象寫(xiě)法,必須使用name
配置項(xiàng),不能用path
。備注2:傳遞
params
參數(shù)時(shí),需要提前在規(guī)則中占位。
就算剛才用這個(gè)方法,但是還是復(fù)雜在標(biāo)簽上
作用:讓路由組件更方便的收到參數(shù)(可以將路由參數(shù)作為
props
傳給組件)
第一種,只需要在路由配置里面開(kāi)啟
第二種
{
name:'xiang',
path:'detail/:id/:title/:content',
component:Detail,
// props的對(duì)象寫(xiě)法,作用:把對(duì)象中的每一組key-value作為props傳給Detail組件
// props:{a:1,b:2,c:3},
// props的布爾值寫(xiě)法,作用:把收到了每一組params參數(shù),作為props傳給Detail組件
// props:true
// props的函數(shù)寫(xiě)法,作用:把返回的對(duì)象中每一組key-value作為props傳給Detail組件
props(route){
return route.query
}
}
作用:控制路由跳轉(zhuǎn)時(shí)操作瀏覽器歷史記錄的模式。
瀏覽器的歷史記錄有兩種寫(xiě)入方式:分別為
push
和
replace
:
push
是追加歷史記錄(默認(rèn)值)。
replace
是替換當(dāng)前記錄。
開(kāi)啟
replace
模式:
News
路由組件的兩個(gè)重要的屬性:
$route
和
$router
變成了兩個(gè)
hooks
import {useRoute,useRouter} from 'vue-router'
const route = useRoute()
const router = useRouter()
console.log(route.query)
console.log(route.parmas)
console.log(router.push)
console.log(router.replace)
作用:將特定的路徑,重新定向到已有路由。
具體編碼:
{
path:'/',
redirect:'/about'
}
點(diǎn)擊獲取,就往數(shù)組增加一條土味情話
注意先從promise返回解構(gòu)data,如果還想繼續(xù)從data里面解構(gòu)可以在后面來(lái)個(gè):加對(duì)象,因?yàn)閏ontent是data對(duì)象里面的,甚至直接給content:給他來(lái)個(gè)別名
第一步:
npm install pinia
第二步:操作
src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
/* 引入createPinia,用于創(chuàng)建pinia */
import { createPinia } from 'pinia'
/* 創(chuàng)建pinia */
const pinia = createPinia()
const app = createApp(App)
/* 使用插件 */{}
app.use(pinia)
app.mount('#app')
此時(shí)開(kāi)發(fā)者工具中已經(jīng)有了
pinia
選項(xiàng)
它有三個(gè)概念:
state
、
getter
、
action
,相當(dāng)于組件中的:
data
、
computed
和
methods
。
具體編碼:
src/store/count.ts
取名最好要跟hooks一樣, 函數(shù)里面的名字最好跟文件名保持一致
// 引入defineStore用于創(chuàng)建store
import {defineStore} from 'pinia'
// 定義并暴露一個(gè)store
export const useCountStore = defineStore('count',{
// 動(dòng)作
actions:{},
// 狀態(tài)
state(){
return {
sum:6
}
},
// 計(jì)算
getters:{}
})
具體編碼:
src/store/talk.ts
// 引入defineStore用于創(chuàng)建store
import {defineStore} from 'pinia'
// 定義并暴露一個(gè)store
export const useTalkStore = defineStore('talk',{
// 動(dòng)作
actions:{},
// 狀態(tài)
state(){
return {
talkList:[
{id:'yuysada01',content:'你今天有點(diǎn)怪,哪里怪?怪好看的!'},
{id:'yuysada02',content:'草莓、藍(lán)莓、蔓越莓,你想我了沒(méi)?'},
{id:'yuysada03',content:'心里給你留了一塊地,我的死心塌地'}
]
}
},
// 計(jì)算
getters:{}
})
組件中使用
state
中的數(shù)據(jù)
注意:?jiǎn)为?dú)用ref那么是.value,但是如果里面是ref定義,外面又用了一個(gè)reactive,那他就會(huì)給你拆包,也就是直接拿不用再value
得到對(duì)應(yīng)store之后它是一個(gè)reactive對(duì)象,然后里面state定義的數(shù)據(jù)是放在ref里面的,那就拆包了
當(dāng)前求和為:{{ sumStore.sum }}
-
{{ talk.content }}
第一種修改方式,直接修改
countStore.sum = 666
第二種修改方式:批量修改
要改的數(shù)據(jù)較多的時(shí)候
countStore.$patch({
sum:999,
school:'atguigu'
})
第三種修改方式:借助
action
修改(
action
中可以編寫(xiě)一些業(yè)務(wù)邏輯)
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
/*************/
actions: {
//加
increment(value:number) {
if (this.sum < 10) {
//操作countStore中的sum
this.sum += value
}
},
//減
decrement(value:number){
if(this.sum > 1){
this.sum -= value
}
}
},
/*************/
})
組件中調(diào)用
action
即可
// 使用countStore
const countStore = useCountStore()
// 調(diào)用對(duì)應(yīng)action
countStore.incrementOdd(n.value)
有個(gè)問(wèn)題,現(xiàn)在模板上全部要加什么.sum都有個(gè)前綴,所以我想就是直接解構(gòu)賦值拿到我要的數(shù)據(jù) ,但是從響應(yīng)式解構(gòu)賦值又是老問(wèn)題了
這樣做可以得到響應(yīng)式數(shù)據(jù),但有點(diǎn)浪費(fèi),因?yàn)樗粌H是將數(shù)據(jù)變成ref,把整個(gè)store包括里面的方法也變了
所以就可以用pinia上有個(gè)專門(mén)的方法來(lái)轉(zhuǎn) 他就是只變數(shù)據(jù)
storeToRefs
將
store
中的數(shù)據(jù)轉(zhuǎn)為
ref
對(duì)象,方便在模板中使用。
pinia
提供的
storeToRefs
只會(huì)將數(shù)據(jù)做轉(zhuǎn)換,而
Vue
的
toRefs
會(huì)轉(zhuǎn)換
store
中數(shù)據(jù)。
當(dāng)前求和為:{{sum}}
概念:當(dāng)
state
中的數(shù)據(jù),需要經(jīng)過(guò)處理后再使用時(shí),可以使用
getters
配置。
追加
getters
配置。
// 引入defineStore用于創(chuàng)建store
import {defineStore} from 'pinia'
// 定義并暴露一個(gè)store
export const useCountStore = defineStore('count',{
// 動(dòng)作
actions:{
/************/
},
// 狀態(tài)
state(){
return {
sum:1,
school:'atguigu'
}
},
// 計(jì)算
getters:{
bigSum:(state):number => state.sum *10,
upperSchool():string{
return this. school.toUpperCase()
}
}
})
組件中讀取數(shù)據(jù):
const {increment,decrement} = countStore
let {sum,school,bigSum,upperSchool} = storeToRefs(countStore)
通過(guò) store 的
$subscribe()
方法偵聽(tīng)
state
及其變化
talkStore.$subscribe((mutate,state)=>{
console.log('LoveTalk',mutate,state)
localStorage.setItem('talk',JSON.stringify(talkList.value))
})
import {defineStore} from 'pinia'
import axios from 'axios'
import {nanoid} from 'nanoid'
import {reactive} from 'vue'
export const useTalkStore = defineStore('talk',()=>{
// talkList就是state
const talkList = reactive(
JSON.parse(localStorage.getItem('talkList') as string) || []
)
// getATalk函數(shù)相當(dāng)于action
async function getATalk(){
// 發(fā)請(qǐng)求,下面這行的寫(xiě)法是:連續(xù)解構(gòu)賦值+重命名
let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
// 把請(qǐng)求回來(lái)的字符串,包裝成一個(gè)對(duì)象
let obj = {id:nanoid(),title}
// 放到數(shù)組中
talkList.unshift(obj)
}
return {talkList,getATalk}
})
Vue3
組件通信和
Vue2
的區(qū)別:
mitt
代替。
vuex
換成了
pinia
。
.sync
優(yōu)化到了
v-model
里面了。
$listeners
所有的東西,合并到
$attrs
中了。
$children
被砍掉了。
常見(jiàn)搭配形式:
概述:
props
是使用頻率最高的一種通信方式,常用與 :
父 ? 子
。
父組件:
父組件,
我的車(chē):{{ car }}
兒子給的玩具:{{ toy }}
子組件
字傳父一種是可以直接寫(xiě)在標(biāo)簽里面類(lèi)似下面
子組件
我的玩具:{{ toy }}
父給我的車(chē):{{ car }}
還有一種就是一個(gè)變量接受
event類(lèi)型可以為event
click
、
mosueenter
等等)
$event
: 是包含事件相關(guān)信息的對(duì)象(
pageX
、
pageY
、
target
、
keyCode
)
$event
: 是調(diào)用
emit
時(shí)所提供的數(shù)據(jù),可以是任意類(lèi)型!。
示例:
//子組件中,觸發(fā)事件:
this.$emit('send-toy', 具體數(shù)據(jù))
也可以正常走邏輯,這樣來(lái)傳
概述:與消息訂閱與發(fā)布(
pubsub
)功能類(lèi)似,可以實(shí)現(xiàn)任意組件間通信。
安裝
mitt
npm i mitt
新建文件:
src\utils\emitter.ts
都是寫(xiě)在這個(gè)ts文件里面,一共四個(gè)api,on是綁定,off解綁,emit觸發(fā),all全部事件可以.clear全部清空
// 引入mitt
import mitt from "mitt";
// 創(chuàng)建emitter
const emitter = mitt()
/*
// 綁定事件
emitter.on('abc',(value)=>{
console.log('abc事件被觸發(fā)',value)
})
emitter.on('xyz',(value)=>{
console.log('xyz事件被觸發(fā)',value)
})
setInterval(() => {
// 觸發(fā)事件
emitter.emit('abc',666)
emitter.emit('xyz',777)
}, 1000);
setTimeout(() => {
// 清理事件
emitter.all.clear()
}, 3000);
*/
// 創(chuàng)建并暴露mitt
export default emitter
組件內(nèi)使用
接收數(shù)據(jù)的組件中:綁定事件、 同時(shí)在銷(xiāo)毀前解綁事件 :
import emitter from "@/utils/emitter";
import { onUnmounted } from "vue";
// 綁定事件
emitter.on('send-toy',(value)=>{
console.log('send-toy事件被觸發(fā)',value)
})
onUnmounted(()=>{
// 解綁事件
emitter.off('send-toy')
})
【第三步】:提供數(shù)據(jù)的組件,在合適的時(shí)候觸發(fā)事件
import emitter from "@/utils/emitter";
function sendToy(){
// 觸發(fā)事件
emitter.emit('send-toy',toy.value)
}
注意這個(gè)重要的內(nèi)置關(guān)系,總線依賴著這個(gè)內(nèi)置關(guān)系
概述:實(shí)現(xiàn) 父?子 之間相互通信。
前序知識(shí) ——
v-model
的本質(zhì)
直接寫(xiě)$event.target.value會(huì)報(bào)錯(cuò),e.target是一個(gè)對(duì)象,這個(gè)獨(dú)享就可能為空,所以這里用了個(gè)斷言告訴他是一個(gè)html輸入的元素
$event.target).value"
>
組件標(biāo)簽上的
v-model
的本質(zhì):
:moldeValue
+
update:modelValue
事件。
下面是本質(zhì),上面是程序員簡(jiǎn)寫(xiě)方式,如果v-model不寫(xiě)別名,默認(rèn)名字傳過(guò)去就是modelValue
AtguiguInput
組件中:
也可以更換
value
,例如改成
abc
也可以改名字,注意:使用父組件這邊可以直接使用簡(jiǎn)寫(xiě)方式,但是接受子組件這邊,還是要跟著原理來(lái),一個(gè)props綁定,一個(gè)觸發(fā)自定義事件
AtguiguInput
組件中:
如果
value
可以更換,那么就可以在組件標(biāo)簽上多次使用
v-model
概述:( 祖→孫 )。
具體說(shuō)明:
$attrs
是一個(gè)對(duì)象,包含所有父組件傳入的標(biāo)簽屬性。
注意:
$attrs
會(huì)自動(dòng)排除props
中聲明的屬性(可以認(rèn)為聲明過(guò)的props
被子組件自己“消費(fèi)”了)
父組件:
父組件
子組件:
子組件
孫組件:
v-bind后面寫(xiě)對(duì)象,相當(dāng)于一個(gè)一個(gè)綁定
孫組件
a:{{ a }}
b:{{ b }}
c:{{ c }}
d:{{ d }}
x:{{ x }}
y:{{ y }}
父?jìng)饕粋(gè)自定義事件,同理也可以實(shí)現(xiàn)孫給祖?zhèn)?
$refs、
$parent】
概述:
$refs
用于 :
父→子。
父組件這邊先給子組件綁定ref,然后給這個(gè)ref的名字調(diào)用ref函數(shù),通過(guò)事件就可以拿到子組件傳過(guò)來(lái)的
子組件
一個(gè)宏函數(shù)把數(shù)據(jù)曝光出來(lái)
`$refs就是一個(gè)api獲取所有子組件
這里面放的就是一個(gè)個(gè)打了ref的子組件對(duì)象
$parent
用于:
子→父。
父組件
原理如下:
屬性 | 說(shuō)明 |
---|---|
$refs
|
值為對(duì)象,包含所有被
ref
屬性標(biāo)識(shí)的
DOM
元素或組件實(shí)例。
|
$parent
|
值為對(duì)象,當(dāng)前組件的父組件實(shí)例對(duì)象。 |
概述:實(shí)現(xiàn) 祖孫組件 直接 通信(attrs需要中間人)
具體使用:
provide
配置向后代組件提供數(shù)據(jù)
inject
配置來(lái)聲明接收數(shù)據(jù)
具體編碼:
【第一步】父組件中,使用
provide
提供數(shù)據(jù)
父組件
資產(chǎn):{{ money }}
汽車(chē):{{ car }}
注意:子組件中不用編寫(xiě)任何東西,是不受到任何打擾的
提供數(shù)據(jù)時(shí)候,ref數(shù)據(jù)不用.value,前面名字,后面數(shù)據(jù)
【第二步】孫組件中使用
inject
配置項(xiàng)接受數(shù)據(jù)。
我是孫組件
資產(chǎn):{{ money }}
汽車(chē):{{ car }}
注入數(shù)據(jù),就用一個(gè)變量來(lái)接受就可以了,第二個(gè)參數(shù)是不寫(xiě)的話也可以由默認(rèn)值
孫給爺傳
爺組件
孫組件
參考之前
pinia
部分的講解
父組件中:
- {{ g.name }}
子組件中:
{{ title }}
父組件中:
- {{ g.name }}
更多
子組件中:
{{ title }}
理解:
數(shù)據(jù)在組件的自身,但根據(jù)數(shù)據(jù)生成的結(jié)構(gòu)需要組件的使用者來(lái)決定。
(新聞數(shù)據(jù)在
News
組件中,但使用數(shù)據(jù)所遍歷出來(lái)的結(jié)構(gòu)由
App
組件決定)
具體編碼:
父組件中:
- {{ g.name }}
子組件中:
今日游戲榜單
作用于插槽也可以有名字
shallowRef
作用:創(chuàng)建一個(gè)響應(yīng)式數(shù)據(jù),但只對(duì)頂層屬性進(jìn)行響應(yīng)式處理。
用法:
之前用ref綁定的數(shù)據(jù)隨便改
如果都改為shallowref
之前單數(shù)據(jù)和整個(gè)對(duì)象還可以改,但是單獨(dú)修改對(duì)象里面某個(gè)屬性就不行了
此淺層就是只把第一層編程響應(yīng)式,.value之后就不管了
用處就是如果有個(gè)對(duì)象很大,我不關(guān)心它里面某個(gè)值變沒(méi)變化,就關(guān)心對(duì)象有沒(méi)有整體被改就可以用這個(gè)
特點(diǎn):只跟蹤引用值的變化,不關(guān)心值內(nèi)部的屬性變化。
shallowReactive
作用:創(chuàng)建一個(gè)淺層響應(yīng)式對(duì)象,只會(huì)使對(duì)象的最頂層屬性變成響應(yīng)式的,對(duì)象內(nèi)部的嵌套屬性則不會(huì)變成響應(yīng)式的
用法:
此時(shí)修改都可以生效
如果用淺層次,那就是第二層改不了了
作用同上
特點(diǎn):對(duì)象的頂層屬性是響應(yīng)式的,但嵌套對(duì)象的屬性不是。
通過(guò)使用
shallowRef()
和shallowReactive()
來(lái)繞開(kāi)深度響應(yīng)。淺層式API
創(chuàng)建的狀態(tài)只在其頂層是響應(yīng)式的,對(duì)所有深層的對(duì)象不會(huì)做任何處理,避免了對(duì)每一個(gè)內(nèi)部屬性做響應(yīng)式所帶來(lái)的性能成本,這使得屬性的訪問(wèn)變得更快,可提升性能。
readonly
用法:
只能讀不能改
也可以針對(duì)對(duì)象,里面的屬性都不能改
特點(diǎn):
應(yīng)用場(chǎng)景:
shallowReadonly
作用:與
readonly
類(lèi)似,但只作用于對(duì)象的頂層屬性。
用法:
只對(duì)淺層次生效,也就是第二層可以改里面的屬性可以改
上面不可改,下面可改
特點(diǎn):
只將對(duì)象的頂層屬性設(shè)置為只讀,對(duì)象內(nèi)部的嵌套屬性仍然是可變的。
適用于只需保護(hù)對(duì)象頂層屬性的場(chǎng)景。
toRaw
作用:用于獲取一個(gè)響應(yīng)式對(duì)象的原始對(duì)象,
toRaw
返回的對(duì)象不再是響應(yīng)式的,不會(huì)觸發(fā)視圖更新。
官網(wǎng)描述:這是一個(gè)可以用于臨時(shí)讀取而不引起代理訪問(wèn)/跟蹤開(kāi)銷(xiāo),或是寫(xiě)入而不觸發(fā)更改的特殊方法。不建議保存對(duì)原始對(duì)象的持久引用,請(qǐng)謹(jǐn)慎使用。
何時(shí)使用? —— 在需要將響應(yīng)式對(duì)象傳遞給非
Vue
的庫(kù)或外部系統(tǒng)時(shí),使用toRaw
可以確保它們收到的是普通對(duì)象
使用場(chǎng)景,并不推薦,把一個(gè)響應(yīng)對(duì)象變?yōu)椴豁憫?yīng)之后給到另一個(gè)對(duì)象,而是加入一個(gè)函數(shù)需要這個(gè)對(duì)象,要?jiǎng)拥剿,但是也不想引起改?
具體編碼:
將一個(gè)響應(yīng)式數(shù)據(jù)編程不再響應(yīng)
markRaw
作用:標(biāo)記一個(gè)對(duì)象,使其 永遠(yuǎn)不會(huì) 變成響應(yīng)式的。
例如使用
mockjs
時(shí),為了防止誤把mockjs
變?yōu)轫憫?yīng)式對(duì)象,可以使用markRaw
去標(biāo)記mockjs
編碼:
/* markRaw */
let citys = markRaw([
{id:'asdda01',name:'北京'},
{id:'asdda02',name:'上海'},
{id:'asdda03',name:'天津'},
{id:'asdda04',name:'重慶'}
])
// 根據(jù)原始對(duì)象citys去創(chuàng)建響應(yīng)式對(duì)象citys2 —— 創(chuàng)建失敗,因?yàn)閏itys被markRaw標(biāo)記了
let citys2 = reactive(citys)
作用:創(chuàng)建一個(gè)自定義的
ref
,并對(duì)其依賴項(xiàng)跟蹤和更新觸發(fā)進(jìn)行邏輯控制。
如果使用ref,那就是數(shù)據(jù)已更新,頁(yè)面馬上更新
如果我想實(shí)現(xiàn)數(shù)據(jù)更新,頁(yè)面等一下在更新這個(gè)做不到
customref基本使用
需要一個(gè)初試值,但是模板用的還是ref的
但如果是這樣寫(xiě)的,頁(yè)面根本不會(huì)響應(yīng)
真正寫(xiě)法,需要在其回調(diào)兩個(gè)參數(shù),在讀取時(shí)調(diào)用前面那個(gè)函數(shù),修改后調(diào)用后面那個(gè)函數(shù)
這兩個(gè)函數(shù)很重要,面試容易問(wèn)道
這樣就可以實(shí)現(xiàn)剛才的效果了
自定義ref感覺(jué)就類(lèi)似于defineproperty那個(gè)函數(shù),就是對(duì)數(shù)據(jù)更新變化的時(shí)候可以去寫(xiě)一些自己的邏輯在里面
但是此時(shí)快速輸入有bug,解決方式如下
實(shí)現(xiàn)防抖效果(
useSumRef.ts
):
import {customRef } from "vue";
export default function(initValue:string,delay:number){
let msg = customRef((track,trigger)=>{
let timer:number
return {
get(){
track() // 告訴Vue數(shù)據(jù)msg很重要,要對(duì)msg持續(xù)關(guān)注,一旦變化就更新
return initValue
},
set(value){
clearTimeout(timer)
timer = setTimeout(() => {
initValue = value
trigger() //通知Vue數(shù)據(jù)msg變化了
}, delay);
}
}
})
return {msg}
}
真實(shí)公司開(kāi)發(fā)需求可能是要在這里來(lái)一個(gè)hooks
to里面可以為id class 標(biāo)簽等選擇器
我是一個(gè)彈窗
我是彈窗中的一些內(nèi)容
實(shí)驗(yàn)性功能
比如現(xiàn)在子組件在發(fā)請(qǐng)求,如果半天出不來(lái),那么先展示fallback插槽里面的內(nèi)容,等異步回來(lái)之后在展示上面的內(nèi)容
Suspense
包裹組件,并配置好
default
與
fallback
import { defineAsyncComponent,Suspense } from "vue";
const Child = defineAsyncComponent(()=>import('./Child.vue'))
我是App組件
加載中.......
app.component
注冊(cè)全局組件
app.config
全局配置對(duì)象
所有組件都訪問(wèn)得到
但是會(huì)報(bào)錯(cuò) vue官網(wǎng)關(guān)于這個(gè)屬性global有解釋
app.directive
注冊(cè)全局指令
app.mount
app.unmount
app.use
過(guò)渡類(lèi)名
v-enter
修改為
v-enter-from
、過(guò)渡類(lèi)名
v-leave
修改為
v-leave-from
。
keyCode
作為
v-on
修飾符的支持。
v-model
指令在組件上的使用已經(jīng)被重新設(shè)計(jì),替換掉了
v-bind.sync。
v-if
和
v-for
在同一個(gè)元素身上使用時(shí)的優(yōu)先級(jí)發(fā)生了變化。(可以用在同一組件上)
移除了
$on
、
$off
和
$once
實(shí)例方法。
移除了過(guò)濾器
filter
。
移除了
$children
實(shí)例
propert
。
......
vue官網(wǎng)
基于vue2 vue3的改變 面試暢聊
機(jī)器學(xué)習(xí):神經(jīng)網(wǎng)絡(luò)構(gòu)建(下)
閱讀華為Mate品牌盛典:HarmonyOS NEXT加持下游戲性能得到充分釋放
閱讀實(shí)現(xiàn)對(duì)象集合與DataTable的相互轉(zhuǎn)換
閱讀鴻蒙NEXT元服務(wù):論如何免費(fèi)快速上架作品
閱讀算法與數(shù)據(jù)結(jié)構(gòu) 1 - 模擬
閱讀升訊威在線客服與營(yíng)銷(xiāo)系統(tǒng)介紹
閱讀基于鴻蒙NEXT的血型遺傳計(jì)算器開(kāi)發(fā)案例
閱讀5. Spring Cloud OpenFeign 聲明式 WebService 客戶端的超詳細(xì)使用
閱讀Java代理模式:靜態(tài)代理和動(dòng)態(tài)代理的對(duì)比分析
閱讀Win11筆記本“自動(dòng)管理應(yīng)用的顏色”顯示規(guī)則
閱讀本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請(qǐng)發(fā)郵件[email protected]
湘ICP備2022002427號(hào)-10 湘公網(wǎng)安備:43070202000427號(hào)© 2013~2025 haote.com 好特網(wǎng)