都是基于最新的Vue3版本?"vue": "^3.4.29"
1 vue組建樣式設置
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
</script><template><div><a href="https://vitejs.dev" target="_blank"><img src="/vite.svg" class="logo" alt="Vite logo" /></a><a href="https://vuejs.org/" target="_blank"><img src="./assets/vue.svg" class="logo vue" alt="Vue logo" /></a></div><HelloWorld msg="Vite + Vue" class="test-baz"/>
</template><style scoped>
.logo {height: 6em;padding: 1.5em;will-change: filter;transition: filter 300ms;
}
.logo:hover {filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {filter: drop-shadow(0 0 2em #42b883aa);
}
.test-baz {color: red;
}
</style>
父組建里面的test-baz并不會被字組建HelloWorld用到,字組建只會用它自己里面的test-baz樣式。
2? vue中getter函數理解
在JavaScript中箭頭函數?() => x.value + y.value
?是一個匿名函數,并不是getter函數。
? 在Vue中,watch
?函數用于觀測一個表達式或函數(通常稱為“getter”)的變化。當這個表達式的值發生變化時,watch
?中定義的回調函數會被觸發。因此,盡管上面提到的箭頭函數?() => x.value + y.value
?本身并不是一個嚴格意義上的JavaScript getter函數(如在對象屬性定義中的那種),在Vue框架的上下文中,它可以被視作一個“getter”功能的實現,因為它用來獲取并計算狀態(即?x.value
?和?y.value
?的和)。
? 這里的匿名箭頭函數?( ) => x.value + y.value
?被Vue用作一個getter來監控依賴項(x.value
?和?y.value
)的變化。當這些依賴項的值發生變化導致計算結果(即兩者的和)改變時,Vue就會調用第二個參數中的回調函數,打印出新的求和結果。因此,在Vue的語境下,將其稱為一個“getter函數”是為了強調其觀測數據變化并響應的功能,而非嚴格遵循JavaScript語言中getter的定義。
3??watch和?watchEffect?
?修改狀態數據就是副作用
const testNumber = ref(0)// 可以直接偵聽一個 ref
watch(testNumber, async (newValue, oldValue) => {testNumber.value = testNumber.value + 1
},)
上面代碼會造成循環依賴報錯
Uncaught (in promise) Maximum recursive updates exceeded. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.
可以修改成只會執行一次,
const testNumber = ref(0)// 可以直接偵聽一個 ref
watch(testNumber,async (newValue, oldValue) => {testNumber.value = testNumber.value + 1},{ once: true }
)
或者使用watchEffect
const testNumber = ref(0)watchEffect(async () => {testNumber.value+=1
})
watchEffect修改自己內部ref不會造成循環依賴。
JPT:
在Vue中,watch
?用于觀察數據變化并在變化時執行一些操作。關于“避免在發生副作用時追蹤依賴”的說法,這實際上與Vue的響應式系統如何處理數據變化和依賴收集有關,尤其是在Vue 3引入的Composition API中,通過ref
或reactive
創建的狀態自動具有響應式特性。
當你在watch
的回調函數內部修改正在被觀察的數據時,如果沒有正確處理,可能會導致無限循環或者不期望的行為。這是因為修改數據會再次觸發依賴更新,進而重新觸發watch
,形成一個循環。為了避免這種情況,Vue在設計上要求開發者注意副作用的管理。
const testNumber = ref(0)// 可以直接偵聽一個 ref
watch(testNumber,async (newValue, oldValue) => {testNumber.value = testNumber.value + 1}
)
執行這段代碼會導致以下問題:
- 副作用:直接修改響應式數據是一種副作用,因為它改變了應用的狀態。
- 依賴追蹤與無限循環:修改
testNumber.value
會觸發表達式的重新計算,如果這個修改又滿足watch
的觸發條件,那么watch
回調將再次執行,從而可能形成無限循環。
為了避免這種情形,Vue提供了幾種策略:
- 使用異步
watch
: 如果你的副作用需要修改觸發它的數據,考慮使用異步watch
(通過將回調設為返回Promise的函數,或使用immediate
和flush: 'post'
選項)。這樣Vue會在當前tick的微任務隊列結束后再執行副作用,避免了即時的循環觸發。 - 在副作用中謹慎修改數據: 確保修改數據的操作不會立即觸發正在運行的
watcher
的重新計算。有時候可以通過條件判斷來避免不必要的修改。 - 使用
watchEffect
: 如果你的副作用邏輯依賴于多個狀態,并且修改這些狀態是預期行為的一部分,考慮使用watchEffect
。watchEffect
更加靈活,會自動管理依賴,并確保副作用在依賴變更時執行,但同樣需要注意避免循環調用的問題。
總之,“避免在發生副作用時追蹤依賴”意味著在執行可能改變響應式數據的操作時,要小心不要無意中觸發了自己正在依賴的數據變化,從而進入無限循環或不可控的狀態變更。正確的做法是合理安排數據修改的位置和時機,以及利用Vue提供的機制來控制副作用的執行。
4??DOM內模板和<template>區別
在Vue中,<template>
?標簽有特定的用途,根據上下文的不同,它扮演著不同的角色。以下是兩種主要的使用場景:
1. Vue單文件組件內的?<template>
在Vue的單文件組件(SFC,Single File Component)中,<template>
?標簽用于包裹組件的HTML模板部分。這部分定義了組件的結構和布局,Vue會解析這個模板并將其編譯為虛擬DOM。例如:
vue
<template><div class="example"><h1>{{ message }}</h1><button @click="reverseMessage">Reverse Message</button></div>
</template><script>
export default {data() {return {message: 'Hello Vue!'};},methods: {reverseMessage() {this.message = this.message.split('').reverse().join('');}}
};
</script>
在這個例子中,<template>
?包含了組件的HTML結構,其中可以綁定數據和事件處理器。
2. DOM內模板插值
在Vue 2中,有一種較為少見的用法是在DOM中直接使用模板字符串插值,這種方式不推薦在現代Vue應用中使用,但在某些老版本的應用或特定場景下可能存在。這通常指的是直接在HTML元素內使用雙大括號?{{ }}
?來插入數據。例如:
html
<div id="app">{{ message }}
</div><script>
new Vue({el: '#app',data: {message: 'Hello World!'}
});
</script>
這里雖然沒有直接使用<template>
標簽,但雙大括號?{{ }}
?實現了數據綁定,相當于簡單模板的使用。然而,對于復雜的結構和邏輯,應該使用Vue組件和<template>
標簽。
總結
- Vue SFC中的?
<template>
?定義了組件的HTML結構,是Vue組件的核心部分,支持指令、插槽等高級功能。 - DOM內模板插值?使用雙大括號?
{{ }}
?直接在HTML中插入數據,適用于非常簡單的數據展示,但不適用于復雜組件結構和邏輯。
在現代Vue開發實踐中,推薦使用Vue組件和單文件組件內的<template>
來構建應用界面,以充分利用Vue的響應式系統和組件化優勢。
5?v-model
?自定義修飾符
子組件
const [myDemo, myDemoModifiers] = defineModel('myDemo',{// get我們這里不需要set(value:string) {if (myDemoModifiers.uppercase) {return value?.toUpperCase();}},
});<input type="text" v-model="myDemo" />
父組件
const name = ref(0)<HelloWorld msg="" v-model:my-demo.uppercase="name"
/>
6 什么是構建步驟
構建步驟就是將源碼轉化為可執行的代碼的過程。例如使用vite、webpack進行轉換!
7? 組件Class 與 Style 綁定
//父組件
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'</script><template><HelloWorld class="test-baz" :style="{ backgroundColor:'pink'}"/></template><style scoped></style>//子組件<script setup lang="ts"></script><template><p class="input-color">Hi!</p>
</template><style scoped >.test-baz {color: green ;
}.input-color {color: red;
}</style>
渲染結果
外部樣式放在默認樣式后面class="input-color test-baz"
按道理應該是test-baz的優先級比input-color高(錯誤認為)
當一個元素指定多個 class 時,class 的優先級與指定順序無關,而是和 class 的定義順序有關。后聲明的優先級高。
.test-baz {color: green ;
}.input-color {color: red;
}
input-color定義在下面所以優先級高。