前端入職學習筆記-第二週第三天(vue元件傳值:Bus傳值、路由傳值、Vuex傳值)
Bus匯流排
1 定義Bus匯流排
在main.js中定義Bus匯流排
constBus=newVue()然後將Bus新增到new Vue中的data裡面
data:{ Bus }Bus也可以定義在assets資料夾下的js檔案中,需要用到時可以引入該檔案,但是在webpack打包時,該檔案會分解成多個Bus,從而報錯,該方法不推薦使用。
2 傳值
呼叫$root下的Bus,使用$emit函式在需要傳值的元件中進行傳值,且設定觸發事件的欄位"city"
this.$root.Bus.$emit("city",cityArr)3 接收值
呼叫$root下的Bus,使用$on函式在需要接收值的元件中響應之前的"city"欄位,從而在回撥函式中接收傳過來的值並進行後續操作。
this.$root.Bus.$on("city",(data)=>{ console.log(data); this.cityName=data[0] this.cityBool=data[2] })注意:回撥函式最好使用箭頭函式,不然this的指向會變向。
Bus傳值可能會出現元件銷燬時,再次建立元件,之前的響應會被多次觸發,可以在周期函式beforeDestroy中用this.$root.Bus.$off()來消除
路由傳值
在需要傳值的元件的router-link中設定需要傳的值params
<router-linkclass="movieLink":to="{name:'movie',params:{hid:i}}"> <h3>{{item.title}}</h3> <span>{{item.language}}</span> <p>{{item.actors|ellipsis(20)}}</p> <p>{{item.plot_simple|ellipsis(40)}}</p> </router-link>index.js中可以把路由附加上傳的值hid
{ path:'/movie/:hid', name:'movie', component:movie }在需要接受值的元件中呼叫傳過來的值hid
this.movieDeteil=res.data.result[this.$route.params.hid]Vuex傳值
安裝vuex
npm install vuex --save
1.在src目錄下新建store資料夾並在該資料夾下新建index.js檔案。 在 store/index.js寫入:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
strict:true, // 開啟嚴格模式 確保state 中的資料只能 mutations 修改
state:{
count:0
}
})
export default store;
在main.js中引入:
import store from './store'
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
此時可以在元件中使用this.$store.state.count
獲取store中state的值。如:
// 在元件的computed中使用
computed:{
count(){
return this.$store.state.count;
}
}
<template>
<div class="hello">
<h2>{{count}}</h2>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
computed:{
count(){
return this.$store.state.count;
}
}
}
</script>
很多時候咱們要對state裡的值進行操作,在vuex提供了一個方法mutations
mutations用法(使用mutations可以修改state的值)
在store/index.js中寫入:
//
...
state:{
count:0
},
mutations:{ // 更改資料的方法
add(state){
state.count++
},
//提交載荷用法
// add(state,n){
// state.count += n
// },
sub(state){
state.count--
}
}
...
//
在元件中使用mutations中對應的方法
<template>
<div class="hello">
<button @click="add">+</button>
<h2>{{count}}</h2>
<button @click="sub">-</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
computed:{
count(){
return this.$store.state.count;
}
},
methods:{
add(){
this.$store.commit('add');
},
//提交載荷用法
// add(){
// this.$store.commit('add',10);
// },
//物件風格的提交方式
// store.commit({
// type: 'add',
// n: 10
// })
sub(){
this.$store.commit('sub');
}
}
}
</script>
此時就可以對count進行修改了。
補充1:mutation接收單個引數和多個引數
利用$store.commit 裡面 寫引數相當於 mutation的函式名字
在元件裡面:
第一種方式: this.$store.commit("addIncrement",{name:'stark',age:18,n:5})
第二種方式:
this.$store.commit({
type:"addIncrement",
n:5,
age:18,
name:'stark.wang'
})
在vuex裡面接收:接收第二個引數相當於前面傳過來的引數,如果多個這個就是物件,如果是一個引數,這個第二個引數payload就是前面的引數,例如
let store = new Vuex.Store({
state: {
num: 100
},
mutations: {
// 任何時候改變state的狀態都通過提交 mutation 來改變
// 裡面可以定義多個函式,當觸發這個函式就會改變state狀態
addIncrement(state, stark) {
console.log(stark);
// 接收一個state作為引數, 相當於上面的state
// 在vuex裡面接收:接收第二個引數相當於前面傳過來的引數,如果多個這個就是物件,如果是一個引數,這個第二個引數payload就是前面的引數。
// mutations設計原則是同步的
//state.num += stark;
state.num += stark.n;
},
minIncrement(state) {
state.num -= 5;
}
}
})
補充2:遇到在元件input中直接修改state中資料的問題
在元件中寫入
<div class="form-control amis-control"> <input name="name" placeholder="" type="text" autocomplete="off" :value="activeFormData.title" @input="updataMessage($event,'t1.title')"> </div>
<script>
...
computed:{
activeFormData(){
return this.$store.state.formData.t1
}
},
methods:{
updataMessage(e,dataposition){
let newposition = dataposition.split('.);
this.$store.commit('updataMessage',{newval:e.target.value,curposition:newposition})
}
}
</script>
在store.js中寫入
mutations:{
...
updataMessage(state, stark) {
if (stark.curposition.length == 2) {
state.formData[stark.curposition[0]][stark.curposition[1]] = stark.newval
} else if (stark.curposition.length == 3) {
state.formData[stark.curposition[0]][stark.curposition[1]][stark.curposition[2]] = stark.newval
}
},
}
當你想非同步操作的時候,由於mutation必須是同步的這一點,此時不能採用mutation對state 進行修改。action派上用場了,action就是一個函式集合,在裡面怎麼操作都可以,只要最後觸發mutation 就可以了。
註解mutation不能非同步操作的原因:
mutations: {
add (state) {
api.callAsyncMethod(() => {
state.count++
})
}
}
現在想象,我們正在 debug 一個 app 並且觀察 devtool 中的 mutation 日誌。每一條 mutation 被記錄,devtools 都需要捕捉到前一狀態和後一狀態的快照。然而,在上面的例子中 mutation 中的非同步函式中的回撥讓這不可能完成:因為當 mutation 觸發的時候,回撥函式還沒有被呼叫,devtools 不知道什麼時候回撥函式實際上被呼叫——實質上任何在回撥函式中進行的狀態的改變都是不可追蹤的。
Action 用法
在store/index.js中寫入
mutations:{ // 更改資料的方法
add(state){
state.count++
},
sub(state){
state.count--
}
},
++++
actions:{
addAction(context){ // context 與 store 例項具有相同方法和屬性(但不是store 例項)
setTimeout(()=>{
context.commit('add');
},1000)
}
}
++++
元件中使用getters裡對應的方法:
<template>
<div class="hello">
<button @click="add">+</button>
++++
<button @click="add_action">action +</button>
++++
<h2>{{count}}</h2>
<button @click="sub">-</button>
<div>
test: {{doneTodos[0].text}} <br>
length: {{doneTodosLength}}
</div>
</div>
</template>
export default {
methods:{
add(){
this.$store.commit('add');
// console.log(this);
},
sub(){
this.$store.commit('sub');
},
++++
add_action(){
this.$store.dispatch('addAction');
}
++++
}
}
實際非同步操作
元件methods中:
在store/index.js中引入axios :
import axios from 'axios'
看到這裡有沒有想過當我們使用state中某一個數據時,我們只想用該資料中符合條件的資料。比如:
state:{
count:0,
todos: [
{ id: 1, text: 'text1--true', done: true },
{ id: 2, text: 'text2--false', done: false }
]
}
此時我們只想獲取state.todos中done為true的資料時我們應該怎麼獲取?可能會有以下兩種方案:
1.每個在元件中首先獲取todos,然後使用filter方法過濾;
2.寫一個公共函式在每個元件中呼叫以下;
如果用到todos中done為true的元件很多,這兩種方法都是很不理想的。Vuex為此為我們引入了一個方法Getter。
Getter 用法
官方解釋:Vuex 允許我們在 store 中定義“getter”(可以認為是 store 的計算屬性)。就像計算屬性一樣,getter 的返回值會根據它的依賴被快取起來,且只有當它的依賴值發生了改變才會被重新計算。
在store\index.js寫入: mutations:{ // 更改資料的方法
add(state){
state.count++
},
sub(state){
state.count--
}
},
+++
getters:{ // 用法類似元件中的 computed, 可以認為是store的計算屬性
doneTodos:state => { // Getter 接受 state 作為其第一個引數:
return state.todos.filter(todo => todo.done) // -> [{ id: 1, text: 'text1--true', done: true }]
},
// Getter 也可以接受其他 getter 作為第二個引數
doneTodosLength:(state,getters) => {
return getters.doneTodos.length // -> 1
},
+++
}
在元件中使用getter對應的方法:
<template>
<div class="hello">
<button @click="add">+</button>
<h2>{{count}}</h2>
<button @click="sub">-</button>
+++
<div>
test: {{doneTodos[0].text}} <br>
length: {{doneTodosLength}}
</div>
+++
</div>
</template>
<script>
export default {
//...
computed:{
+++
doneTodos(){
return this.$store.getters.doneTodos // -> [{ id: 1, text: 'text1--true', done: true }]
},
doneTodosLength(){
return this.$store.getters.doneTodosLength // -> 1
}
+++
}
}
</script>
詳細可參考:vue元件通訊傳值——Vuex