插槽
在編寫組件時,可能存在這種情況,頁面需要顯示不同的內容,但是頁面結構是類似的,在這種情況下,雖然也可以使用傳參來進行,但傳參時,還需要編寫props等邏輯,略顯重復,而且數據的結構還需要是類似的,不能顯示十分不同的數據,但可以用插槽解決這個問題。
默認插槽
當父組件使用子組件時,可以在子組件的標簽體中編寫HTML。當Vue解析到標簽體中的內容時,也會對標簽體進行解析,但是Vue不知道解析好的DOM放在子組件具體哪個位置,在子組件中,通過<slot>標簽可以解決這個問題,表示把解析好的DOM放在<slot>的位置。
插槽中內容的樣式,可以寫在子組件中,也可以寫在父組件中。
在<slot>標簽中,還可以設置默認HTML,當調用子組件并且沒有編寫標簽體內容時,就會顯示slot標簽中的默認值。
具名插槽
如果一個子組件中需要使用多個插槽,每個插槽中需要放置的內容不同,可以指定哪些內容放在哪個插槽:
在父組件調用子組件時,標簽體中通過slot屬性,slot=“插槽名”,表示該標簽放在插槽名對應的插槽中。在子組件中,在slot標簽中添加name屬性。
如果子組件中有多個未命名的插槽,父組件中也未給插槽命名,則每個子組件的插槽都是一樣的,且都是整個標簽體。
如果在父組件中,有多個標簽都要添加到一個slot中,則不會產生覆蓋,這些內容都會添加到對應的slot。可以通過給多個標簽添加一樣的slot,使這些內容都添加到一個slot。
但也有一種更好的方法,是把需要放在一個插槽中的內容包在template中,在template標簽中,想把指定元素放在指定的插槽有兩種寫法,一個是v-slot:插槽名,一個是slot="插槽名"。
作用域插槽
如果需要放到插槽中的數據,存儲在子組件中,這就無法在父組件中直接獲得數據,而父組件又需要使用這個數據,當然一種方法是子父組件通信,但是插槽提供了一種父組件能夠使用子組件包含的數據的方法。
在子組件的插槽中以屬性的形式上傳父組件要使用的參數,:變量名="數據"。這樣些之后,數據會被傳給插槽的使用者,也就是父組件。在父組件中,在標簽體內部,標簽體的內容必須放在template標簽中,且通過scope屬性獲得數據,語法是scope="變量名",或者slot-scope="變量名",而且在父組件中,scope對應的變量名,和子組件傳遞的變量名可以不一樣。當子組件傳遞多個變量時,多個變量會以一個大對象的方式傳遞給父組件。
作用域插槽也可以命名,命名方法和具名插槽一樣。但是,作用域和命名一起使用時,命名只能用slot形式,用v-slot會引發報錯。
Vuex
Vuex是實現集中式管理數據的Vue插件。
和集中式相反的是分布式,分布式是指數據分布在各個地方,而Vuex數據集中管理在倉庫中。
Vuex也是一種組件通信的方式,并且可以用于任意組件通信。
和其他的組件間通信相比,如果想要實現組件A、B、C之間數據的讀寫,通常要給每個組件和想要通信的組件之間各綁定一個$emit和一個$on,當互相通信的組件變多時,會變得有些難以維護。而在Vuex中,Vuex不屬于任何一個組件,它是一個數據倉庫,當組件想請求或者修改數據的時候,只需要和倉庫通信就可以。
當1.多個組件依賴于同一個狀態,2.來自不同組件的行為需要變更同一狀態時,可以考慮使用Vuex。
工作原理:
Actions(一個Object,用于處理邏輯,并觸發Mutations)
Mutations (一個Object,用于修改State中的數據)
State(一個Object,用于存放數據)
VueComponents(Vue組件)
在VC中,使用dispatch(要觸發的actions,參數)去調用API,觸發Actions對應的函數,在這個函數中,通過commit(要觸發的mutations,參數)觸發mutations,在mutations對應的函數中,修改State中的數據。當State中的數據修改后,會重新解析調用dispatch的VC,并重新渲染。
為什么要通過Actions觸發Mutations,才修改State,而不是直接用VC觸發mutations:Actions可以用于處理ajax請求,如果前端在往倉庫里存儲數據的時候,不知道需要存儲的數據,要進行一次前后端交互,就可以通過Actions觸發Mutations,如果前端知道數據,不需要發送請求,也可以在VC中通過commit直接觸發Mutations。除此之外,Actions中一般用來編寫業務邏輯,如果前端交互時,沒有很多業務邏輯,也可以不使用Actions。
Store(用于管理Actions、Mutations、State),調用dispatch、commit等方法時,都是通過store,this.$store.dispatch、this.$store.commit。
Store
要為項目引入$store,首先要安裝vuex:npm i vuex@3,要注意,如果使用的是Vue2,要安裝vuex3版本,在Vue3中,使用vuex4版本。
一般來說,Vuex不會在入口文件中配置,推薦的配置方法是在src目錄下創建store文件夾,在store文件夾的index.js中對Vuex進行配置。
在index.js中,對store進行創建:
引入:import Vuex from 'vuex'
使用:Vue.use(Vuex)
思路是在Index.js中寫好store,在入口文件處對store進行引入和配置,在這種情況下,要先use(Vuex),才能獲得store方法。但由于import的優先級高于普通的代碼,也就是說,當代碼運行時,會先對整個文件中的Import語句進行掃描,并把Import語句按順序都提升到代碼最前方,所以對vuex的引入和use需要寫在index.js中,不能寫在入口文件。
use(Vuex)之后,在Vue實例和VueComponent組件實例上,就有了$store,在創建Vue實例時,就可以傳輸store配置項了。
然后對actions、mutations、state進行創建。通過new Vuex.Store(配置對象)創建store。配置對象中需要傳遞actions、mutations、state。
最后將store進行暴露。
將store配置寫好后,還要記得將這個配置項寫入new Vue的配置對象中,才能生效:
?state
存儲數據的對象。
通過this.$store.state.變量名,可以獲取倉庫中的數據。
actions
在組件中,通過觸發dispatch來間接修改倉庫中的數據。
dispatch觸發actions中對應名字的方法:dispatch(要觸發的actions方法名,參數)。
actions中定義對應的函數,它的參數是一個類似store的對象(精簡版store,為context),以及dispatch傳遞的參數。
context身上有store相關的方法,通過它的commit方法觸發mutations。
在actions中,context身上也有dispatch方法,可以在一個actions方法中觸發另一個actions方法;context身上也具有state,而且在actions中修改state中的數值,也是可以的,state中的數據也會更新,但是這會導致vuex開發者工具不起效果,這種寫法不夠規范。
mutations
在mutations中,方法名一般大寫。在mutations里,盡量不要寫業務邏輯,也不要發送ajax請求。
如果在組件中往倉庫中寫數據時,不涉及業務邏輯,也不需要發送ajax請求,也可以在組件中直接使用this.$store.commit觸發mutations方法。
在mutations中,方法的參數為state,以及commit時傳遞的參數。對state中的數據的修改只能在mutations中進行。
、
getters
getters也是Vuex中提供的一種API,但是,它并不是必須要使用的,當提取倉庫中數據的代碼過長時,getters可以簡化語法。
getters也是一個配置對象,對象中可以定義多個函數,函數的參數為state,函數的返回值為想獲取的數據,通過函數名就能獲得返回值,可以在每次獲取數據時,不需要手寫很長的獲取代碼,在組件中,通過this.$store.getters.函數名即可獲得數據。
mapState
通過計算屬性簡化數據的獲取:當需要獲得倉庫中的數據時,每次都需要寫this.$store.state.是十分重復的,可以把這種數據的獲取寫在computed中、
但與此同時,把數據都寫在computed中,也是十分重復的,Vuex提供了mapState方法可以批量生成computed方法,mapState通過import {mapState} from 'vuex'引入。、
mapState需要寫在computed中。mapState的返回值是通過配置項生成包含所有配置函數的對象,在computed中,需要獲取的是對象內部的函數,而不是對象,所以需要通過...語法把mapState返回的對象中的函數依次取出,放入computed中。
mapState的參數有多種寫法:
其中之一是寫一個配置對象,對象中的內容以key:value的形式編寫,key對應的是computed中定義的函數名,value是computed方法中,return部分的簡寫,對應于this.$store.state.后面的部分,且是字符串形式。
mapState中,除了寫配置對象,還可以寫數組:數組中每個元素都是key:value形式,key:value的邏輯規則和對象形式是一樣的。如果key和value的名字是一樣的,可以省略成字符串形式的一個名字。
mapGetters
和mapState的思想類似,this.$store.getters也有簡寫形式,而且mapGetters的思路和mapState是一模一樣的。
在mapGetters配置項中,value對應的是this.$store.getters.后面的部分。
mapActions
返回this.$store.dispatch的函數也可以批量生成。
對象方法:在mapActions的配置對象中,key是methods方法名,value是想觸發的actions的方法名。參數也是通過調用methods方法時傳遞。
數組寫法:同樣,如果actions方法名和methods方法名一樣,可以用數組的形式寫,數組中每個元素都是一個字符串形式的方法名。
mapMutations
返回this.$store.commit的函數也可以批量生成,語法和其他的map方法是一樣的。
對象寫法:key是methods方法名,value是commit想要觸發的方法名。且參數需要在調用methods方法時傳遞。
數組寫法:當commit要觸發的方法名,和methods想定義的方法名是一樣時,可以在數組中只寫一個字符串形式的方法名。
模塊化開發
對于項目中的數據,可能有非常非常多,把所有數據和相關操作都寫在一個store的index.js下,最后整個index文件里的代碼會非常非常多。Vuex支持模塊化開發,可以把不同功能的數據存放在不同的倉庫中。
只要把不同功能的數據的actions、mutations、state、getters分別分裝在不同的對象中,在new Vuex.Store中引入這些對象就可以完成模塊化。引入時,配置語法是key是modules,values是一個對象,對象中的key是倉庫名,value是倉庫的配置,當倉庫名和配置名一樣時,可以使用簡寫形式。
如果使用模塊化開發,mapState、mapGetters、mapMutations、mapActions的語法會發生一點變化,不能直接對store中的內容進行操作,因為store分了模塊。如果想訪問某個倉庫,比如說home倉庫下的數據,在引入內容時,可以使用home獲取整個倉庫。
也可以通過在調用map方法時多配置一個參數,第一個參數為對應的倉庫名,后面的參數為數組或對象形式的語法,和之前的邏輯是一樣的,使用這種方法時,要給每個倉庫的配置對象設置namespaced:true。
如果不使用map方法,想通過原生的語法調用某個倉庫中的方法,使用this.$store.state.倉庫名.變量名、this.$store.commit('倉庫名/方法名')、this.$store.dispatch('倉庫名/方法名')、this.$store.getters[`倉庫名/方法名`]來進行指定。
要注意,雖然this.$store.getters的邏輯是一樣的,但是getters無法使用字符串的形式獲取當前數據,要用[]語法,表示是gtters.倉庫名.方法名。