Vue
1、上手
1、安裝
- 使用命令:
npm create vue@latest
- vue文件后綴為
.vue
const app = createApp(App)
:初始化根組件app.mount("#app")
:掛載根組件到頁面
2、文件
- script標簽:編寫js
- template標簽:編寫html
- style標簽:編寫css
2、樣式
1、樣式設置
- style標簽內,編寫樣式
- template標簽內,元素節點通過class定義類名
2、樣式隔離
style標簽通過scoped
,能夠進行組件之間的樣式隔離
3、樣式穿透
-
vue2中使用
::v-deep
前綴修飾::v-deep .box {}
-
vue3中使用
:deep(.box)
進行包裹:deep(.box) {}
4、使用less
-
安裝
less
-
修改標簽:
<style scoped lang="less"></style>
3、渲染
1、基礎渲染
- 定義常量:
const num = 10
- 顯示常量:
<div>{{ num }}</div>
- 計算顯示:
<div>{{ num - 2 }}</div>
- 能夠在數據顯示中,進行js邏輯執行
- 設置動態屬性:
- 定義屬性:
const idName = "box"
- 綁定屬性:
<div v-bind:id="idName">vue</div>
- 簡寫:
<div :id="idName">vue</div>
- 定義屬性:
- 設置多個屬性:
- 定義屬性:
const attr = { id: "box" }
- 綁定屬性:
<div v-bind="attr"></div>
- 定義屬性:
- 渲染HTML:
- 定義:
const dom = "<span>vue</span>"
- 渲染:
<div v-html="dom"></div>
- 注意:此時div不能添加內容
- 定義:
- 類名綁定:
- 單類名:
<div :class="className">vue</div>
- 多類名:
<div :class="[class1, class2]">vue</vue>
- 可控類名:
<div :class="{ active: isActive }">vue</div>
- 單類名:
2、條件渲染
- 定義變量:
const show = false
- 判斷顯示:
<div v-show="show">隱藏</div>
- 判斷顯示:
<div v-if="show">消失</div>
- 區別:
v-show
:節點會進行構建、布局和渲染,但是會設置display為none進行隱藏v-if
:節點不參與構建、頁面沒有該節點v-else
:配合v-if
使用,v-if
、v-else
、v-else-if
3、列表渲染
- 定義數組:
const list = [1, 2, 3]
- 列表遍歷:
<div v-for="(item, index) in list" :key="index">{{item}}</div>
- 屬性key:提供給vue,方便節點插入刪除,提高性能
- 空數組時隱藏
- 優先度小于
v-show
、v-if
- 不建議和
v-if
一起使用
4、事件響應
-
語法:
v-on:事件類型="綁定函數名"
-
簡寫:
@:事件類型="綁定函數名"
-
綁定事件函數:
<button @click="fn">按鈕</button>
-
事件傳值:
- 調用傳值:
<button @click="fn('value')">按鈕</button>
- 事件對象:
<button @click="fn($event)">按鈕</button>
<button @click="(e) => fn(e)">按鈕</button>
- 調用傳值:
-
事件修飾:
@click.stop
:阻止事件冒泡@click.prevent
:阻止默認事件@click.self
:事件只作用與本身@click.once
:事件只執行一次@click.capture
:事件在捕獲階段執行@scroll.passive
:先執行滾動,然后再執行監聽函數,避免滾動卡頓- 鏈式:
@click.stop.prevent
:阻止冒泡、阻止默認- 需要注意鏈式調用順序
-
按鍵修飾:
@keyup.enter
:僅enter按鍵彈起時觸發@keyup.tab
@keyup.delete
@keyup.esc
@keyup.space
@keyup.up
@keyup.down
@keyup.left
@keyup.right
@keyup.ctrl
@keyup.alt
@keyup.shift
@keyup.meta
:菜單鍵- 鏈式:
@keyup.alt.enter
:符合按鍵alt + enter - 點擊組合:
@click.ctrl
:點擊 + ctrl
-
鼠標修飾
@click.exact
:沒有任何按鍵時觸發@click.left
:鼠標左鍵觸發@click.right
:鼠標右鍵觸發@click.middle
:鼠標輔助鍵觸發
5、動態數據
1、定義
- vue3:使用ref定義數據。
const count = ref(0)
- 返回值:初始化的變量
- 參數:初始化的值
- 元素內可以直接使用
- 元素外需要通過
count.value
訪問
- vue3:使用reactive定義數據:
const data = reactive({ count: 1 })
- 返回值:初始化的復雜變量
- 參數:需要代理的對象,數組等。無法代理普通類型數據
- 元素內外可以直接使用
2、綁定和顯示
和其他常量一樣,直接進行使用
4、修改
- 節點內:
<button @click="count++">{{ count }}</button>
- 節點外:
function fn() { count.value++ }
5、雙向綁定
-
v-model
:輸入框數據雙向綁定-
使用:
<input type="text" v-model="text" />
-
相當于:
<inputtype="text":value="text"@input="event => text = event.target.value" />
-
-
修飾:
v-model.lazy
:相當于綁定@change
v-model.number
:只輸入數字v-trim
:去掉兩端空格
6、計算屬性
const num = computed(() => count)
:獲取計算屬性- 只有當count響應變量變化時,才會重新計算num數據。
- 能夠對數據進行緩存,如
computed(() => Date.now())
7、數據監聽
-
watch(data, callback):數據監聽
- data:監聽的數據
- callback:監聽函數
- 參數一:可選,變化后的值
- 參數二:可選,變化前的值
-
data:監聽多個數據,
[data1, data2]
-
callback:監聽函數
- 參數一:可選,變化后的值,
[data1, data2]
- 參數二:可選,變化前的值,
[data1, data2]
- 參數一:可選,變化后的值,
-
watchEffect(callback):數據監聽
- 組件中,多個響應數據發生變化,組件會等待所有數據變化完后,統一刷新一次
- 觸發條件:
- 響應數據發送變化
- callback函數中,只用使用到的數據才會被監聽。
- 組件掛載完成后,也會被觸發
8、強行刷新
- 由于統一刷新機制,某個響應變量需要提前響應,需要強行刷新
nextTick()
:強行刷新函數
6、插槽
slot組件:定義插槽,就是子元素渲染位置
1、渲染內容
<template><h3>Box</h3><slot />
</template>
2、默認內容
<template><h3>Box</h3><slot>這里是插槽默認內容</slot>
</template>
3、具名插槽
<slot name="header"></slot>
:定義插槽名稱<template v-slot:name>插入內容</template>
4、動態插槽名
<template v-slot:[動態響應變量]>插入內容</template>
5、插槽傳值
-
普通插槽
-
傳值:
<slot :text="傳值"></slot>
-
讀取:
<template v-slot="slotProps"><p>插槽 {{ slotProps.text }}</p></template>
-
-
具名插槽:
-
傳值:
<slot name="header" :text="傳值"></slot>
-
讀取:
<template v-slot:header="slotProps"><p>插槽 {{ slotProps.text }}</p> </template>
-
7、動態組件
- 使用
component
組件動態加載不同組件 - 使用:
<component :is="組件名" />
4、組件傳值
1、父傳子
-
傳值
- 通過屬性之間傳值
- 通過v-bind傳遞動態屬性變量,或者方法
-
讀取
-
子組件通過:
const props = defineProps(["屬性名"])
讀取屬性、方法 -
props只讀,無法修改
-
defineProps:
- 參數為數組:讀取屬性名
- 參數為對象:設置props的數據類型,必填、默認值
- 屬性名稱:值可以為數據類型,可以為對象
- type:數據類型
- required:是否必填
- default:默認值
- validator:自定義校驗
- 屬性名稱:值可以為數據類型,可以為對象
const props = defineProps({propA: Number,propB: [Number, String],propC: Function,propD: {type: String,required: true,default: "必填"},propF: {validator(value, props) {return ["success", "error"].includes(value);}} })
-
-
綁定事件:
<Box @submit="callback" />
-
觸發事件:
-
<button @click="$emit('submit')">按鈕</button>
-
使用
const emit = defineEmits(['事件名'])
接受事件emit('事件名')
:調用事件
-
傳值:
$emit("事件名", arg1, arg2)
emit("時間嗎", arg1, arg2)
-
-
單個v-model
- 綁定v-model:
<Box v-model="text" />
- 獲取model:
const model = defineModel([optons])
- options:可選
- required:是否必填
- options:可選
- 綁定v-model:
-
具名v-model
- 綁定v-model:
<Box v-model:title="text" />
- 獲取model:
const title = defineModel('title'[, options])
- 參數一:名稱
- options:可選,同上
- 綁定v-model:
-
多個v-model
-
綁定多個v-model
<Box v-model:title="title" v-model:text="text" />
-
獲取model
const title = defineModel("title") const text = defineModel("text")
-
- 讀取attrs
- 使用
$attrs
直接進行讀取 - 使用:
const attrs = useAttrs()
獲取
- 使用
- 讀取slots
- 使用
$slots
直接進行讀取 - 使用:
const solts = useSlots()
獲取
- 使用
2、父讀子
- 子組件通過
defineExpose({ 變量, 方法 })
,暴漏自身變量和方法 - 父組件通過
const child = useTemplateRef(refName)
獲取綁定ref的子組件 - 父組件通過ref屬性綁定refName:
<Box ref="refName" />
- 父組件讀取:
child.value.名稱
- 父組件調用:
child.value.名稱()
- 如果ref綁定的是html標簽元素,直接通過
refName.名稱
進行讀取和調用
3、兄弟傳值
- 共享父組件響應變量傳值
- 使用pinia狀態管理傳值
4、上下文
- 單個數據
- 父組件提供:
provide(key, value)
- 子組件注入:
const value = inject(key)
- 父組件提供:
- 多個數據
- 父組件提供:
provide(key, value, setValue)
- 子組件注入:
const { value, setValue } = inject(key)
- 父組件提供:
- provide可以多次調用,inject也可以多次調用
5、生命周期
- onBeforeMount(fn):加載前
- onMounted(fn):加載后
- onBeforeUpdate(fn):數據變化前
- onUpdated(fn):數據變化后
- onBeforeUnmount(fn):卸載前
- onUnmounted(fn):卸載后
- onErrorCaptured(fn):子組件出現錯誤鉤子函數
- onActivated(fn):
- 首次掛載時調用
- 每次從緩存中重新插入
- onDeactivated(fn):
- 卸載時調用
- 從緩存中卸載時調用
- onServerPrefetch(fn):異步組件在服務器上渲染之前觸發
1、加載前
- script標簽內,直接執行的代碼就是組件加載前執s行
- onBeforeMount(callback):加載前執行
2、加載后
- onMounted(callback):加載后執行
3、變化后
- watch:監聽數據變化完成
- watchEffect:監聽數據變化完成
4、卸載前
- onBeforeUnmount(callback):卸載前執行
5、進出動畫
1、條件渲染
-
使用
v-if
、v-show
等控制組件進入進出時,渲染動畫 -
使用組件
Transition
完成動畫<Transition><div v-if="show">內容</div> </Transition>
-
基于css過度
- Transition默認會給包裹子節點添加6個類名
.v-enter-from
:渲染前className,定義元素進入頁面前的樣式.v-enter-active
:渲染中className,定義元素進入頁面時的CSS動畫.v-enter-to
:渲染后className,定義元素進入頁面后的樣式.v-leave-from
:卸載前className,定義元素退出頁面前的樣式.v-leave-active
:卸載時className,定義元素退出頁面時的CSS動畫.v-leave-to
:卸載后className,定義元素退出頁面后的樣式
- Transition設置name屬性:
<Transition name="fade">
.v-enter-from
就需要改為.fade-enter-from
- Transition默認會給包裹子節點添加6個類名
-
自定義css
- Transition可以自定義類名
enter-from-class
:重定義.v-enter-from
類名enter-active-class
:重定義.v-enter-active
類名enter-to-class
:重定義.v-enter-to
類名leave-from-class
:重定義.v-leave-from
:類名leave-active-class
:重定義.v-leave-active
類名leave-to-class
:重定義.v-leave-to
類名
- Transition可以自定義類名
-
動畫鉤子函數
-
Transition每個動畫階段都有鉤子事件函數
@before-enter
:進入頁面前觸發事件@enter
:進入頁面時觸發事件@after-enter
:進入頁面后觸發事件@enter-cancelled
:進入動畫完成后,觸發事件@before-leave
:退出頁面前觸發事件@leave
:退出頁面時觸發事件@after-leave
:退出頁面后觸發事件@leave-cancelled
:退出動畫完成后,觸發事件
-
Transition組件在使用鉤子函數時,建議設置css屬性為false
-
事件綁定函數,參數一為當前元素指向
-
@enter
和@leave
還有參數二,為動畫完成后回調函數。告訴vue動畫以及完成<template><div><h1>app</h1><button @click="toggle">按鈕</button><Transitionname="fade"@enter="activeEnter"@leave="leaveEnter"><div v-if="show">內容</div></Transition></div> </template><script setup> import { ref } from 'vue' import { gsap } from 'gsap'const show = ref(false) function toggle() {show = !show }function activeEnter(el, done) {gsap.fromTo(el,{ x: -100, opacity: 0 },{ x: 0, opacity: 1, duration: 1 }).then(done) }function leaveEnter(el, done) {gsap.fromTo(el,{ x: 0, opacity: 1 },{ x: 100, opacity: 0, duration: 1 }).then(done) } </script>
-
-
渲染時動畫
- 不依靠
v-if
和v-show
控制,而是組件mount時進行動畫 - Transition組件添加
appear
屬性
- 不依靠
-
替換動畫
- 當使用
v-if
和v-else
進行組件替換時,需要設置model
- Transition組件添加設置
model="out-in"
- 當使用
-
組件替換
- 當使用
component
組件進行動態組件替換時 - Transition組件添加設置
model="out-in"
- 當使用
2、列表渲染
-
使用組件
TransitionGroup
完成v-for
的動畫渲染 -
組件
TransitionGroup
和Transition
擁有基本相同的props- 多一個
.v-move
的類名,用于元素的過度 - 多一個
tag
屬性,用于創建一個元素標簽
.list-move, /* 對移動中的元素應用的過渡 */ .list-enter-active, .list-leave-active {transition: all 0.5s ease; }.list-enter-from, .list-leave-to {opacity: 0;transform: translateX(30px); }/* 確保將離開的元素從布局流中刪除以便能夠正確地計算移動的動畫。 */ .list-leave-active {position: absolute; }
- 多一個
6、Pinia
1、使用
-
入口文件
main.js
,添加使用中間件import { createPinia } from 'pinia'// ... app.use(createPinia())
-
定義數據
-
創建文件:
src/stores/counter
-
使用響應式定義數據
import { ref, computed } from 'vue' import { defineStore } from 'pinia'export const useCounterStore = defineStore('counter', () => {const count = ref(0)count doubleCount = computed(() => count.value * 2)function add() {count.value++}return { count, doubleCount, add } })
-
-
createPinie:函數,返回一個中間件
-
defineStore(key, callback):函數
- key:唯一標識
- callback:使用響應式創建數據和方法
2、數據使用
-
引入Store:
import { useCounterSotre } from "@/stores/counter"
-
使用:
<template><div>{{ counter.count }}</div><button @click="counter.add">按鈕</button> </template><script setup> import { useCounterStore } from "@/stores/counter" const counter = useCounterStore() </script>
-
注意:
- 不要對counter進行結構,否則無法進行數據響應變化
- 原因:結構后相當于重新賦值,所以結構后的值不會發生任何變化
3、數據監聽
-
store內監聽
- 直接使用
watch
和watchEffect
進行數據監聽即可 - 然后使用sessionStorage或者loactStorage完成數據持久化
- 直接使用
-
組件內監聽
-
也使用
watch
和watchEffect
進行數據監聽,需要深層次監聽watch(() => store.count,() => {// 數據變化時觸發} )
-
4、異步修改
- 直接在方法里,進行數據異步修改即可
5、模塊化
- 直接修改defineStore的key值,實現不過store不同唯一標識
6、外部使用
- 直接在外部js文件中引入store,然后使用store方法即可
7、路由
1、路由使用
-
const router = createRouter(options)
:創建路由配置 -
app.use(router)
:中間件的方式使用router -
RouterView
:渲染路由頁面組件 -
options配置項
-
history:定義路由模式
- createWebHistory(import.meta.env.BASE_URL):定義history模式
- createWebHashHistory(import.meta.env.BASE_URL):定義hash模式
-
routers:定義路由列表
- router-item配置
- path:路由地址
- name:路由別名
- meta:原信息
- component:組件
- redirect:路由重定向
- children:子路由列表
- router-item配置
-
404
routes: [{ path: '/:catchAll(.*)', component: Error } ]
-
2、路由跳轉
const router = useRouter()
:獲取router操作- router.back():返回上一個路由
- router.go(number):返回數值步路由
- number可以為負
- 1,向前1步。
- -1,向后1步。
- 0,刷新路由
- number可以為負
- router.push(path):路由跳轉
- 參數為字符串時,直接進行路由跳轉
- 參數為對象時
- path:路由路徑
- query:路由query傳遞參數
3、子路由
-
定義子路由
const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{ path: "/", redirect: "/home" },{path: "/home",component: Home,children: [{ path: "/home/one", component: HomeOne },{ path: "/home/two", component: HomeTwo },]}] })
-
使用子路由
<template><h1>home</h1><RouterView /> </template>
5、路由傳值
- 路由傳值,也就是get請求傳參。
- params:
url/:id
,需要對路由路徑進行修改 - query:
url?a=1&b=2
- hash:
url#123
- params:
- 傳值參數
- 獲取路由操作:
const router = useRouter()
- params傳遞:
router.push("url/123456")
- query傳遞:
router.push("url?a=10&b=10")
router.push({ path: "url", query: { a: 10, b: 10 } })
- hash傳值:
router.push("url#123456")
- 獲取路由操作:
- 讀取參數
- 獲取路由讀取:
const route = useRoute()
- 讀取param:
const param = route.param
- 讀取query:
const query = route.query
- 讀取hash:
const hash = route.hash
- 讀取meta:
const meta = route.meta
- 讀取完整路徑:
const fullPath = route.fullPath
- 獲取路由讀取:
6、路由懶加載
const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: "/home",component: () => import("@/view/Home.vue")}]
})
7、跳轉守衛
- 跳轉前攔截:
router.beforeEach((to, from ,next) => {})
- 跳轉后攔截:
router.afterEach((to, from) => {})
8、路由進度條
- 插件:
nprogress
- 引入:
- 引入組件:
import NProgress from 'nprogress';
- 引入樣式:
import 'nprogress/nprogress.css';
- 引入組件:
- 使用:
- 開啟:
NProgress.start()
- 結束:
NProgress.done()
- 設置進度:
NProgress.set(0.4)
:0~1之間NProgress.inc()
:設置隨機進度
- 開啟:
- 配置:
NProgress.config(options)
- minimum:進度條的最小百分比,默認0.08
- easing:動畫動作 [ease、linear]
- speed:動畫速度,默認200
- showSpinner:是否顯示旋轉加速器,默認true
- parent:進度條父容器,默認body
9、進出動畫
- 首先創建store,存儲路由變化狀態,默認為false
- 路由跳轉前,修改狀態為true
- 注意:必須在
router.beforeEach
回調內使用useStore
,否則報錯 - 原因:在外面使用,路由組件還未進行掛載,pinia也為進行掛載
- 注意:必須在
- 路由跳轉后,修改狀態為false
- 在layout組件,也就是使用RouterView組件內,監聽狀態
- 如果狀態為true,控制RouterView外殼元素進行gsap離開動畫
- 如果狀態為false,控制RouterView外殼元素進行gsao進入動畫
10、路由封裝
- 自動讀取views文件內的index.vue
- 自動構建路由
import { createRouter, createWebHistory } from 'vue-router'const history = createWebHistory(import.meta.env.BASE_URL)
const routes = [{ path: '/', redirect: '/home' }]
const globModel = import.meta.glob(`@/views/**/index.vue`)Object.entries(globModel).forEach(([file, model]) => {const segments = file.split('/')let current = {}let path = ''for (let i = 3; i < segments.length; i++) {const segment = segments[i]if (segment === 'index.vue') {current.component = model} else {let list = routesif (i !== 3) {if (!current.children) current.children = []list = current.children}path += '/' + segmentconst child = list.find((child) => child.path === path)if (child) current = childelse {current = { path }list.push(current)}}}
})routes.push({path: '/:catchAll(.*)',component: () => import('@/views/ErrorView.vue'),
})export default createRouter({ history, routes })
8、指令
1、v-html
正常渲染的數據都是字符串,v-html能把html字符串渲染成html節點
2、v-bind
- 動態綁定屬性:
<div v-bind:id="idName">vue</div>
- 簡寫:
<div :id="idName">vue</div>
- 綁定多個屬性:
<div v-bind="attr"></div>
3、v-show
- 控制隱藏:
<div v-show="show">vue</div>
- 通過變量,控制
display
樣式,進行顯示或隱藏
4、v-if
- 控制渲染:
<div v-if="show">vue</div>
- 通過變量,控制節點是否渲染,進行顯示或隱藏
5、v-for
- 列表渲染:
<div v-for="(item, index) in list" :key="index">{{ item }}</div>
- 進行遍歷,可以結構出下標
- 需要綁定key屬性,讓vue能夠更好進行節點計算,提高性能
- 空數組時隱藏
- 優先度小于
v-if
、v-show
- 不建議和
v-if
一起使用 - 配套使用:
v-if
、v-else
、v-else-if
6、v-on
- 綁定事件
7、v-model
- 雙向綁定
- 相當于:v-bind:value + v-on:input
8、v-slot
- 使用具名插槽:
<template v-slot:插槽名稱>內容</template>
- 簡寫:
<template #插槽名稱>內容</template>
9、v-pre
- 所有 Vue 模板語法都會被保留并按原樣渲染
- 如:
<span v-pre>{{ 123 }}</span>
- 渲染成:
<span>{{ 123 }}</span>
10、自定義
-
app.directive(name, callback)
:自定義指令-
app:createApp創建的根節點
-
name:指令名稱,使用為
v-名稱
-
callback:
-
函數時
-
參數一:使用的元素
-
參數二:賦值的參數
-
案例:
<div v-color="color"></div>app.dircetive('color', (el, binding) => {el.style.color = binding.value })
-
-
對象時:
-
created(el, binding, vnode):創建節點后
-
beforeMount(el, binding, vnode):掛載前
-
mounted(el, binding, vnode):掛載后
-
beforeUpdate(el, binding, vnode, prevVnode):更新前
-
update(el, binding, vnode, prevVnode):更新后
-
beforeUnmount(el, binding, vnode):卸載前
-
unmounted(el, binding, vnode):卸載后
-
el:使用的元素
-
binding:賦值的參數
-
vnode:綁定元素的底層vnode
-
prevVNode,代表之前的渲染中指令所綁定元素的 VNode
-
案例:
<div v-color="color"></div>app.dircetive('color', {mounted(el, binding) {el.style.color = binding.value} })
-
-
-
9、組件
-
template:空標簽組件
-
computed:組件加載空標簽
-
Transition:過度動畫標簽
-
TransitionGroup:列表過度動畫標簽
-
KeepAlive:
-
緩存組件
<KeepAlive><component :is="activeComponent" /> </KeepAlive>
-
排除:include
<KeepAlive :include="['a', 'b']"><component :is="view" /> </KeepAlive>
-
最大緩存數:max
<KeepAlive :max="10"><component :is="activeComponent" /> </KeepAlive>
-
生命周期
- onActivated:掛載時,從緩存中重新掛載時,觸發
- onDeactivated:卸載時,從緩存中卸載時,調用
-
-
Teleport:選擇掛載節點
<Teleport to="body"><div>該節點將添加掛載到body上</div> </Teleport>
-
組件全局注冊
- vue3中,局部組件之間引入即可使用
- vue3中,全局組件注冊:
app.component(組件名, 組件)
10、API
-
app.use():使用插件
-
app.mount():掛載節點
-
app.directive(name, options):自定義指令
-
app.component(name, component):注冊全局組件
-
h:渲染函數,創建虛擬dom
- 參數一:標簽、或者組件名稱
- 參數二:標簽的屬性,事件
- 參數三:子節點
-
ref:定義并初始化響應數據
-
nextTick:響應數據變化后,強行刷新組件函數
-
reactive:定義并初始化復雜類型數據
-
readonly:設置并返回響應數據只讀
import {ref, readonly} from "vue" const count = ref(0) const copyCount = readonly(count)
-
computed:定義并通過函數處理獲取數據
-
watch:對數據進行監聽
-
watchEffect:對使用數據進行監聽
-
defineProps:讀取props
-
defineEmits:讀取組件綁定事件
-
defineModel:讀取v-model
-
defineOptions:設置組件
- inheritAttrs:是否Attributes繼承
-
defineExpose:拋給ref變量,方法,函數
-
provide:提供上下文
-
inject:注冊上下文
11、變量
$attrs
:讀取組件被設置的屬性$event
:讀取事件綁定元素本身的事件對象$slot
:讀取組件的所有slot- 具名插槽:
$slot.名稱
- 非具名:
$slot.default
- 具名插槽:
$emit("事件名稱")
:觸發組件綁定的事件
12、函數與插件
1、函數
-
在pinia中,就能看到vue的api是可以單獨在函數中使用
-
所以vue的script標簽內部的重復邏輯可以提取到外部
-
組合式函數約定駝峰命名,并以
use
開頭 -
import { ref } from 'vue'function useCount(init) {const count = ref(init)functoin add() {count++}return { count, add } }export default useCount
-
使用:
const { count, addCount } = useCount()
2、插件
-
插件本質是一個函數
-
定義一個插件:
function addDir(app) {app.directive('color', (el, binding) => {el.style.color = binding.value}) }
-
使用插件:
app.use(addDir)
13、請求
// src/utils/api.js 封裝class Api {constructor(baseurl, timeOut) {this.baseurl = baseurl;this.timeOut = timeOut || 10000;}async #request(url, method = "GET", data, json = false, fileName) {const path = this.baseurl + url;const controller = new AbortController();const config = { method, signal: controller.signal };const timeoutPromise = new Promise((_, reject) =>setTimeout(() => {controller.abort();reject(new Error("請求超時"));}, this.timeOut));if (data) {config.body = json ? JSON.stringify(data) : data;if (json) config.headers = { "Content-Type": "application/json" };}try {const res = await Promise.race([fetch(path, config), timeoutPromise]);if (!res.ok) throw new Error(res.statusText);// 進行接口響應后攔截邏輯 - 可通過響應頭獲取登錄狀態等const contentType = res.headers.get("content-type").split(";")[0].trim();if (!contentType) throw new Error("Unknown content type");// 處理文件下載if (fileName) {const resData = await res.arrayBuffer();this.#downloadFile(resData, contentType, fileName);return { success: true };}// 返回請求結果return contentType === "application/json"? await res.json(): await res.text();} catch (error) {throw new Error(`請求失敗: ${error.message}`);}}#downloadFile(res, contentType, fileName) {const blob = new Blob([res], { type: contentType });const url = URL.createObjectURL(blob);const a = document.createElement("a");a.href = url;a.download = fileName;a.click();URL.revokeObjectURL(url);a.remove();}get(url, query, param) {let path = url;if (query) path += "?" + new URLSearchParams(query).toString();if (param) path += "/" + param;return this.#request(path);}post(url, data) {return this.#request(url, "POST", data, true);}postByFormData(url, data) {let formData = new FormData();for (const key in data) {formData.append(key, data[key]);}return this.#request(url, "POST", formData);}download(url, fileName = "file") {this.#request(url, "GET", null, false, fileName);}upload(url, file, key = "file") {const formData = new FormData();formData.append(key, file);return this.#request(url, "POST", formData);}uploads(url, files, key = "files") {const formData = new FormData();for (const file of files) {formData.append(key, file);}return this.#request(url, "POST", formData);}
}let baseurl = import.meta.env.MODE === "production" ? "" : "/api";
let api = new Api(baseurl);
export default api;
14、服務代理
// vite.config.js
// ...const default defineConfig({// ...server: {proxy: {'/api': {target: 'http://localhost:3000',changeOrigin: true,rewrite: (path) => path.replace(/^\/api/, '')},'/bpi': {target: 'http://localhost:3001',changeOrigin: true,rewrite: (path) => path.replace(/^\/bpi/, '')}}}
})
15、環境變量
- 讀取環境變量:import.meta.env
- 環境判斷
- import.meta.env.MODE === development:開發環境
- import.ment.env.MODE === production:生產環境
- 設置變量
- 創建.env文件
- 創建變量:
VITE_NAME=hello
- 變量前綴需為:
VITE_
- env文件
- .env文件:所有環境都能訪問
- .env.development:開發環境才能訪問
- .env.production:生產環境才能訪問
16、別名配置
-
resolve-alias:配置別名
// vite.config.js import { fileURLToPath, URL } from 'node:url' import { defineConfig } from 'vite'export default defineConfig({resolve: {alias: {"@": fileURLToPath(new URL('./src', import.meta.url))}} })
17、靜態資源
- 樣式使用
- public:
background: url("/public/images/bg.jpg")
- src/assets:
background: url("./assets/images/bg.jpg")
- public:
- src使用
- public:
<img alt="#" src="/public/images/bg.jpg" />
- src/assets:
<img alt="#" src="./assets/images/bg.jpg" />
- public:
- 打包:
- public:文件會被復制
- src/assets:文件會被編譯,壓縮(需要配置),文件名會發生變化
18、校驗規則
-
腳手架創建項目時,能夠選擇eslint
-
對eslint微調
-
eslint.config.js中,添加對象
-
// eslint.config.js // ... export default defineConfig([// ...{rules: {'no-console': 'off'}} ])
-
-
對prettier微調
- 在.prottierrc.json內直接修改
19、渲染函數
-
導入渲染函數:
import { h } from 'vue'
-
創建dom
import { h } from 'vue' const vnode = h('div', { class: 'box' }, 'hello world vue3')
-
配置attr
- 配置id:
h('div', { id: 'box' })
- 配置class:
h('div', { class: 'box' })
- 配置style:
h('div', { style: { color: 'red' } })
- 配置id:
-
事件綁定
-
import { h } from 'vue' const handleClick = () => alert('hello world') const vnode = h('div', { onClick: handleClick })
-
綁定其他事件:使用jsx的形式綁定,如
onInput
-
v-model:
import { h, ref } from 'vue' const text = ref('') const vnode = h('input',{type: 'text',value: text.value,onInput: (e) => {text.value = e.target.value}} )
-
-
子節點
- 單個子節點:
h('div', vnode)
- 多個子節點:
h('div', [vnode1, vnode2])
- 單個子節點:
-
組件
-
創建組件節點
import Home from "@/views/Home.vue" import { h } from 'vue' const vnode = h('Home', { class: 'home' })
-