vue3的新特性
- [組合式 API]
- Teleport
- 片段
- 觸發組件選項
- createRenderer API 來自 @vue/runtime-core 創建自定義渲染器
- 單檔案組件組合式 API 語法糖
- 單檔案組件狀態驅動的 CSS 變數
- 單檔案組件現在可以包含全域規則或只針對插槽內容的規則
1,什么是組合式API?
平時使用vue開發的小伙伴們不難發現,在我們封裝組件的時候大部分使用組件的選項(data、computed、methods、watch)組織邏輯在大部分情況下都是有效,然而當我們組件變得更大時,邏輯關注點串列增加,組件中的代碼量越來越大,導致維護起來變得很困難,
Vue 選項式 API: 按選項型別分組的代碼
一個大型組件的示例,其中邏輯關注點是按顏色分組,
這種碎片化使得理解和維護復雜組件變得困難,選項的分離掩蓋了潛在的邏輯問題,此外,在處理單個邏輯關注點時,我們必須不斷地“跳轉”相關代碼的選項塊,
如果我們能夠將與同一個邏輯關注點相關的代碼配置在一起會更好,而這正是組合式 API 使我們能夠做到的,
于是就有了組合式API
既然我們知道了為什么,我們就可以知道怎么做,為了開始使用組合式 API,我們首先需要一個可以實際使用它的地方,在 Vue組件中,我們將此位置稱為 setup
setup 在組件創建之前執行,一旦props被決議,就被充當成API的入口點
由于執行setup時組件實體未被創建,因此setup選項中沒有this,這意味著除了props,我們無法訪問組件中生命的任何屬性–本地狀態、計算屬性【computed】、方法【methods】
setup的使用:
// src/components/UserRepositories.vue
export default {
components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
props: {
user: { type: String }
},
setup(props) {
console.log(props) // { user: '' }
return {} // 這里回傳的任何內容都可以用于組件的其余部分
}
// 組件的“其余部分”
}
代碼實戰:
1,從假定的外部 API 獲取該用戶名的倉庫,并在用戶更改時重繪它
先來看第一段代碼??因為我們的 repositories 變數是非回應式的,所以我們要進行修改
// src/components/UserRepositories.vue `setup` function
import { fetchUserRepositories } from '@/api/repositories'
// 在我們的組件內
setup (props) {
let repositories = []
const getUserRepositories = async () => {
repositories = await fetchUserRepositories(props.user)
}
return {
repositories,
getUserRepositories // 回傳的函式與方法的行為相同
}
}
帶ref的回應式變數
在 Vue 3.0 中,我們可以通過一個新的 ref 函式使任何回應式變數在任何地方起作用,如下所示:
import { ref } from 'vue'
const counter = ref(0)
console.log(counter) // { value: 0 }
console.log(counter.value) // 0
//ref接受引數并回傳它包裝在具有value的property物件中,然后可以使用property 修改回應式變數的值
counter.value++
console.log(counter.value) // 1
//在物件中對于包裝值就不是必要的,但是在javaScript中基本型別是通過值來傳遞的
//如 let val1 = 1 const val2 = val1 值的傳遞
//物件則是通過參考來傳遞
在任何值周圍都有一個包裝器物件,這樣我們就可以在整個應用程式中安全地傳遞它,而不必擔心在某個地方失去它的回應性,
提示
換句話說,ref 對我們的值創建了一個回應式參考,使用參考的概念將在整個組合式 API 中經常使用,
回到之前的代碼,我們來完善它:
// src/components/UserRepositories.vue `setup` function
import { fetchUserRepositories } from '@/api/repositories'
import { ref } from 'vue'
// in our component
setup (props) {
const repositories = ref([])
const getUserRepositories = async () => {
repositories.value = await fetchUserRepositories(props.user)
}
return {
repositories,
getUserRepositories
}
}
完成!現在,每當我們呼叫 getUserRepositories 時,repositories 都將發生變化,視圖將更新以反映更改,我們的組件現在應該如下所示:
// src/components/UserRepositories.vue
import { fetchUserRepositories } from '@/api/repositories'
import { ref } from 'vue'
export default {
components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
props: {
user: { type: String }
},
setup (props) {
const repositories = ref([])
const getUserRepositories = async () => {
repositories.value = await fetchUserRepositories(props.user)
}
return {
repositories,
getUserRepositories
}
},
data () {
return {
filters: { ... }, // 3
searchQuery: '' // 2
}
},
computed: {
filteredRepositories () { ... }, // 3
repositoriesMatchingSearchQuery () { ... }, // 2
},
watch: {
user: 'getUserRepositories' // 1
},
methods: {
updateFilters () { ... }, // 3
},
mounted () {
this.getUserRepositories() // 1
}
}
mounted 鉤子呼叫 getUserRepositores
// src/components/UserRepositories.vue `setup` function
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted } from 'vue'
// in our component
setup (props) {
const repositories = ref([])
const getUserRepositories = async () => {
repositories.value = await fetchUserRepositories(props.user)
}
onMounted(getUserRepositories) // on `mounted` call `getUserRepositories`
return {
repositories,
getUserRepositories
}
}
現在我們使用watch來監聽user
// 組合式API
import { ref, watch } from 'vue'
// 如同vue2我們可以從vue中匯入watch,他們的功能基本相同,現在watch接收三個引數:
//1,一個回應式回應或者我們想要監聽的getter函式
//2,一個回呼
//3,可選的配置項
const counter = ref(0)
watch(counter, (newValue, oldValue) => {
console.log('The new counter value is: ' + counter.value)
})
我們來看一下和vue2(選項式API)的對比
// 選項式API
export default {
data() {
return {
counter: 0
}
},
watch: {
counter(newValue, oldValue) {
console.log('The new counter value is: ' + this.counter)
}
}
}
現在配合我們上面的例子來繼續vue3組合式API開發的模式來完成代碼
// src/components/UserRepositories.vue `setup` function
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted, watch, toRefs } from 'vue'
// 在我們組件中
setup (props) {
// 使用 `toRefs` 創建對prop的 `user` property 的回應式參考
const { user } = toRefs(props)
const repositories = ref([])
const getUserRepositories = async () => {
// 更新 `prop.user` 到 `user.value` 訪問參考值
repositories.value = await fetchUserRepositories(user.value)
}
onMounted(getUserRepositories)
// 在用戶 prop 的回應式參考上設定一個偵聽器
watch(user, getUserRepositories)
return {
repositories,
getUserRepositories
}
}
你可能已經注意到在我們的 setup 的頂部使用了 toRefs,這是為了確保我們的偵聽器能夠對 user prop 所做的更改做出反應,
有了這些變化,我們就把第一個邏輯關注點移到了一個地方,我們現在可以對第二個關注點執行相同的操作——基于 searchQuery 進行過濾,這次是使用計算屬性,先來看下代碼
//與ref 和 watch類似,也可以使用從vue匯入的computed 函式在vue組件外部創建計算屬性
//下面是counter的例子
import { ref, computed } from 'vue'
const counter = ref(0)
const twiceTheCounter = computed(() => counter.value * 2)
counter.value++
console.log(counter.value) // 1
console.log(twiceTheCounter.value) // 2
// vue3簡直太頂了,作者忍不住要夸一下,牛*
在這里,computed函式回傳一個作為computed的第一個引數傳遞的getter類回呼的輸出的一個只讀的回應式參考,為了訪問新創建的計算變數的value,我們需要像使用ref一樣使用.value property
接下來就是搜索功能,同樣使用vue3的組合式API
// src/components/UserRepositories.vue `setup` function
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted, watch, toRefs, computed } from 'vue'
// in our component
setup (props) {
// 使用 `toRefs` 創建對 props 的 `user` property 的回應式參考
const { user } = toRefs(props)
const repositories = ref([])
const getUserRepositories = async () => {
// 更新 `props.user ` 到 `user.value` 訪問參考值
repositories.value = await fetchUserRepositories(user.value)
}
onMounted(getUserRepositories)
// 在用戶 prop 的回應式參考上設定一個偵聽器
watch(user, getUserRepositories)
const searchQuery = ref('')
const repositoriesMatchingSearchQuery = computed(() => {
return repositories.value.filter(
repository => repository.name.includes(searchQuery.value)
)
})
return {
repositories,
getUserRepositories,
searchQuery,
repositoriesMatchingSearchQuery
}
}
看完上面的代碼,你會發現,組合式API不就是把選項式API組合起來放到setup中使其具有聚合功能的作用嗎?那說明你已經好好地看了本篇文章的上半部分,但實戰卻剛剛開始,接下來就讓我們一起看實戰中組合式API是如何使用的:
//封裝組合式函式--根據回應式的引數動態獲取介面資料并回傳
// src/composables/useUserRepositories.js
import { retApi } from '@/api/repositories'
import { ref, onMounted, watch} from 'vue'
export default function userRepositories(user){
const repositories = ref([])
const getUserRepositor = async() =>{
repositories.value = await retApi(user.value)
}
onMounted(getUserRepositor)
watch(user,getUserRepositor)
return {
repositories,
getUserRepositor
}
}
將搜索功能也同樣封裝(聰明的小伙伴已經開始跟著作者敲代碼了 )
// src/composables/useRepositoryNameSearch.js
//搜索功能顯然要寫在computed函式里面
import { ref, computed } from 'vue'
export default function userSearch(repositories){
const searchQuery = ref('')
const repositoriesMatchingSearchQuery = computed(()=>{
return repositories.value.filter(repository=>{
return repository.name.includes(searchQuery.value)
})
})
return{
searchQuery,
repositoriesMatchingSearchQuery
}
}
功能函式封裝好了,接下來我們來完成組件部分:
// src/components/UserRepositories.vue
import useUserRepositories from '@/composables/useUserRepositories'
import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch'
import { roRefs } from 'vue'
export default {
components:{
RepositoriesFilters,
RepositoriesSortBy,
RepositoriesList
},
props:{
user:{ type: String }
},
setup(props){
const { user } = toRefs(props)
const { repositories, getUserRepositories } = useUserRepositories(user)
const {
searchQuery,
repositoriesMatchingSearchQuery
} = useRepositoryNameSearch(repositories)
return {
// 因為我們并不關心未經過濾的倉庫
// 我們可以在 `repositories` 名稱下暴露過濾后的結果
repositories: repositoriesMatchingSearchQuery,
getUserRepositories,
searchQuery,
}
},
data () {
return {
filters: { ... }, // 3
}
},
computed: {
filteredRepositories () { ... }, // 3
},
methods: {
updateFilters () { ... }, // 3
}
}
繼續更新,補全代碼---------
// src/components/UserRepositories.vue
import { toRefs } from 'vue'
import useUserRepositories from '@/composables/useUserRepositories'
import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch'
import useRepositoryFilters from '@/composables/useRepositoryFilters'
export default {
components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
props: {
user: { type: String }
},
setup(props) {
const { user } = toRefs(props)
const { repositories, getUserRepositories } = useUserRepositories(user)
const {
searchQuery,
repositoriesMatchingSearchQuery
} = useRepositoryNameSearch(repositories)
const {
filters,
updateFilters,
filteredRepositories
} = useRepositoryFilters(repositoriesMatchingSearchQuery)
return {
// 因為我們并不關心未經過濾的倉庫
// 我們可以在 `repositories` 名稱下暴露過濾后的結果
repositories: filteredRepositories,
getUserRepositories,
searchQuery,
filters,
updateFilters
}
}
}
隨著前端生態的不斷發展,前端崗位對于開發人員的挑戰也越來越大,釋放焦慮,才有動力,有壓力,才有成長!
本文章參考vue3檔案
第一篇 end
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/266682.html
標籤:其他
上一篇:webpack使用教程
下一篇:無重復字符的最長子串
