vue父組件異步獲取動態數據傳遞給子組件 獲取不到值的問題已完美解決 附demo

前幾天遇到一個問題,在父組件中使用axios獲取異步數據傳給子組件,但是發現子組件在渲染的時候並沒有數據,在created裏面打印也是空的,結果發現一開始子組件綁定的數據是空的,在請求數據沒有返回數據時,子組件就已經加載了,並且他綁定的值也是空的,問題找到了,怎麼解決那?有兩種方法解決,請看下面代碼。

方法一、

開始的時候讓子組件隱藏,然後等數據返回的時候,讓子組件顯示。
<template>
  <div class="list">
    <ul v-if="list.length != 0">
      <li v-for="(item,index) in list" :key="index"</li>
    </ul>
  </div>
</template>
<script>
export default {
  props:['getList'], //接收一個數組
    data(){
      return {
        list: []
      }
    },
    watch:{   // 使用監聽的方式,監聽數據的變化
      getList(val){
        this.list = val;
      }
    }
}
</script>
不過這樣方式不太合適,有bug,比如我點擊一個按鈕去獲取數據,然後在彈框裏面展示數據,彈框是一個子組件,在獲取數據的這段過程有可能幾百毫秒,也有可能十秒或者更長時間,難道我要在點擊按鈕過十秒才讓彈框顯示嗎?這這這絕對不行,推薦使用方法二

方法二、 推薦使用

大概邏輯:使用vuex全局狀態管理,其實簡單,利用vuex的輔助函數(mapState,mapMutations)mapState是將state裏面的數據映射到計算中(computed),mapMutations也是類似,把vuex中mutations的方法映射到組件裏面,就可以在組件裏面直接使用方法了,在vuex中使用異步(actions)去掉用接口,然後在接口成功的函數裏面取觸發同步(mutations)裏面的方法,把得到數據傳給mutations裏面的方法裏並且給state裏面的屬性賦值,然後就可以在子組件中使用computed計算中去獲取數據並且渲染到頁面上,其實說的有點繞( -_-"),但是看代碼就明白了 。
vuex / index.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex) 
export default new Vuex.Store({  
    //定義初始數據
    state: {  
        title: '',
        list: [],
        isShow: false
    },
    //同步的方法
    mutations: {
        //向state 裏面設置數據
        changeListMutation(state, list) {
            state.list = list
        },
        //在list.vue裏面點擊下拉選項的時候觸發 給state.title賦值
        changeTitleMutation(state, title) {
            state.title = title
        },
        //selectinput.vue裏面點擊input的時候觸發 給state.isShow賦值
        toggleShow(state, isShow) {
            state.isShow = isShow 
        }
    },
    //異步的方法
    actions: {
        //在list.vue裏面created生命週期裏面觸發
        getListAction({ commit }) {
            axios.get('/mock/5afd9dc0c088691e06a6ab45/example/dataList')
                .then((res) => {
                    commit('changeListMutation', res.data) //調用mutations下面的changeListMutation方法並且傳值過去
                })
                .catch((error) => {
                    console.log(error)
                })

        }
    }
})
// 觸發異步裏面的方法是用 this.$store.dispatch('這裏是方法名')
// 觸發同步裏面的方法是用 this.$store.commit('這裏是方法名')
父組件 select.vue
這個頁面只是引入兩個子組件,沒有什麼好說的
<template>
  <div class="select">
    <div class="wrap">
        <selectInput></selectInput>
        <list></list>
    </div>
  </div>
</template>
<script>
  // 引入子組件 
  import selectInput from '@/components/selectInput'  
  import list from '@/components/list'
  export default {
    components:{   //加載子組件
      selectInput,
      list
    },
  }
</script>
<style>
  .select{
    background:#4a56fe;
    width: 400px;
    margin: 100px auto 0;
    padding: 40px;
    border-radius: 10px;
  }
  .wrap{
    background: #e3e5fe;
    border-radius: 10px;
    padding: 40px;
  }
  ul{
    list-style: none;
  }
</style>
子組件 list.vue
該組件就是展示下拉選項,並且調用數據渲染
<template>
  <div class="list">
    <ul>
      <li v-for="(item,index) in list" :key="index" v-show="initShow" @click="changeTitle(item.title)">{{item.title}}</li>
    </ul>
  </div>
</template>

<script>
    import {mapState,mapMutations} from 'vuex'  // 將vuex中的state數據和mutations中的方法映射到組件中
    export default {
        //vue 生命週期(created)在實例創建之後,在數據初始化之前被調用
        created(){  
            this.$store.dispatch('getListAction')  //調用vuex 中的 getListAction異步方法
        },
        //計算state數據
        computed:{
            ...mapState({
              list:'list',
              initShow:'isShow'
            })
        },
        methods:{
            changeTitle(title){
              this.$store.commit('changeTitleMutation',title)
              this.$store.commit('toggleShow',!this.initShow)
            }
        }
    }
</script>
// 觸發異步裏面的方法是用 this.$store.dispatch('這裏是方法名')
// 觸發同步裏面的方法是用 this.$store.commit('這裏是方法名')

<style>
  .list{
    padding: 10px 0;
    text-align: center;
  }
  li{
    line-height: 30px;
    height: 30px;
    border-radius: 15px;
    cursor: pointer;
    color:#535353;
  }
  li:hover{
    background: #ff705b;
    color: #fff;
  }
</style>
子組件 selectinput.vue
該組件展示選中的數據
<template>
  <div class="inputBox">
    <input type="text" readonly :value="getTitle" @click="toggleShow" placeholder="你喜歡什麼">
  </div>
</template>

<script>
export default {
  computed:{
    // 獲取vuex中的state數據並賦值綁定到 value上面  computed 裏面的方法名其實就是相當於 data裏面的數據,可以用this.getTitle 去訪問
    getTitle(){ 
      return this.$store.state.title
    },
    // 初始化控制下拉選項顯示隱藏的狀態,如果isShow是false 則不限是下拉菜單,默認是false
    initShow(){
        return this.$store.state.isShow
    }
  },
  methods:{
    //點擊input的時候調用該方法,這個方法去觸發mutations下面的toggleShow,去改變isShow的狀態,默認是isShow等於false, 然後在點擊的時候去改變isShow 等於true ,  !this.initShow就是true,如果是true的話,下拉選項才能出來,並將改變過後的值傳給toggleShow方法,去給vuex/store.js 裏面的state.isShow賦值。
    toggleShow(){
      this.$store.commit('toggleShow',!this.initShow)
    }
  }
}
</script>

<style>
input{
  outline: none;
  width: 100%;
  height: 40px;
  line-height: 40px;
  border-radius: 10px;
  border: 1px solid #d3d3d3;
  text-indent: 20px;
  color: #535353;
}
</style>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章