请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

子组件怎么获取父组件ajax回来的数据

https://img1.sycdn.imooc.com/szimg//58e5f65f0001e45725601446.jpg

子组件源代码:

<template>
   <div class="slide" @mouseover="clearInv" @mouseout="runInv" ref="slide">
       <div class="slide-img">
           <a class="clearFloat" :href="options.slides[nowIndex].href">
               <transition name="slide-trans">
                   <img v-if="isShow" :src="options.slides[nowIndex].src" ref="slideImg">
               </transition>
               <transition name="slide-trans-old">
                   <img v-if="!isShow" :src="options.slides[nowIndex].src">
               </transition>
           </a>
       </div>
       <div class="title">{{options.slides[0].title}}</div>
       <ul class="page-nub">
           <li @click="goToSlide(prevIndex)"><</li>
           <li v-for="(slide,index) in options.slides" @click="goToSlide(index)" :class="{active: index === nowIndex}">
               {{index + 1}}
</li>
           <li @click="goToSlide(nextIndex)">></li>
       </ul>
   </div>
</template>
<script type="text/ecmascript-6">
   import Vue from 'vue'
export default {
       data() {
           return {
               nowIndex: 0,
               isShow: true
}
       },
       props: {
           options: {
               type: Object,
               default(){
                   return {
                       slides: [],
                       invTime: 1000
}
               }
           }
       },
       computed: {
           prevIndex () {
               if (this.nowIndex === 0) {
                   return this.options.slides.length - 1
}
               else {
                   return this.nowIndex - 1
}
           },
           nextIndex () {
               if (this.nowIndex === this.options.slides.length - 1) {
                   return 0
}
               else {
                   return this.nowIndex + 1
}
           }
       },
       watch:{
           /*
           options(){
               this.runInv();
           }
           */
},
       mounted() {
           console.log(this.options.invTime);   //结果是:undefined     怎么从这个位置获取this.options.invTime?且页面不报错?
setTimeout(() => {
               console.log(this.options.invTime);   //结果是:2000
this.setSlideHeight();
               this.runInv();
           },20);
       },
       methods: {
           goToSlide(index){
               this.isShow = false;
               setTimeout(() => {
                   this.isShow = true;
                   this.nowIndex = index;
               }, 10)
           },
           runInv () {
               this.invId = setInterval(() => {
                   this.goToSlide(this.nextIndex)
               }, this.options.invTime)
           },
           clearInv () {
               clearInterval(this.invId)
           },
           setSlideHeight(){
               let slideImg = this.$refs.slideImg;
               let slide = this.$refs.slide;
               slideImg.onload = function () {
                   let imgHeight = slideImg.getBoundingClientRect().height + 'px';
                   slide.style.height = imgHeight;
               };
           }
       }
   };
</script>
<style lang="less" type="text/css" rel="stylesheet/less" scoped>
   .slide {
       width: 100%;
       position: relative;
       overflow: hidden;
       color: #fff;
       .slide-img {
           img {
               position: absolute;
               display: block;
               width: 100%;
           }
           .slide-trans-enter-active {
               transition: all .5s;
           }
           .slide-trans-enter {
               transform: translateX(100%);
           }
           .slide-trans-old-leave-active {
               transition: all .5s;
               transform: translateX(-100%);
           }
       }
       .title {
           position: absolute;
           left: 0;
           bottom: 0;
           background: rgba(0, 0, 0, 0.5);
           width: 100%;
           height: 50px;
           line-height: 50px;
           text-align: left;
           padding-left: 15px;
       }
       .page-nub {
           position: absolute;
           right: 30px;
           bottom: 0;
           height: 50px;
           line-height: 50px;
           li {
               float: left;
               padding: 0 10px;
               &.active {
                   color: #fff700;
               }
           }
       }
   }
</style>
父组件源代码:

<template>
   <div class="index-wrap">
       <div class="index-left">
           <div class="index-left-block">
               <h2>全部产品</h2>

               <template v-for="product in productList">
                   <h3>{{ product.title}}</h3>
                   <ul>
                       <li v-for="item in product.list">
                           <a :href="item.url">{{ item.name }}</a>
                           <span v-if="item.hot" class="hot-tag">HOT</span>
                       </li>
                   </ul>
                   <div v-if="!product.last" class="hr"></div>
               </template>
           </div>
           <div class="index-left-block lastest-news">
               <h2 class="news">最新消息</h2>
               <ul>
                   <li v-for="item in newsList">
                       <a :href="item.url" class="new-item">{{ item.title }}</a>
                   </li>
               </ul>
           </div>
       </div>
       <div class="index-right">
           <slide :options="options" ref="indexSlide"></slide>
           <div class="index-board-list">
               <div class="index-board-item" v-for="(item, index) in boardList"
:class="[{'line-last' : index % 2 !== 0}]">
                   <div class="index-board-item-inner" :class="['index-board-' + item.id]">
                       <h2>{{ item.title }}</h2>
                       <p>{{ item.description }}</p>
                       <div class="index-board-button">
                           <router-link class="button" :to="{path: 'detail/' + item.toKey}">立即购买</router-link>
                       </div>
                   </div>
               </div>
           </div>
       </div>
   </div>
</template>
<script type="text/ecmascript-6">
   import slide from '@/components/slide';
   export default {
       created () {
           this.fetchData();
       },
       data(){
           return {
               options: {},
               boardList: [],
               newsList: [],
               productList: {}
           }
       },
       methods: {
           fetchData () {
               const url = 'api/getIndexData';
               this.$http.post(url).then((res) => {
                   this.newsList = res.data.newsList;
                   this.boardList = res.data.boardList;
                   this.productList = res.data.productList;
                   //this.options = res.data.options;
this.$set(this,'options',res.data.options);
                   //console.log(this.$refs.indexSlide.options);
                   //this.$refs.indexSlide.al();
}).catch((err) => {
                   console.log(err)
               })
           }
       },
       components: {
           slide
       }
   };
</script>
<style lang="less" type="text/css" rel="stylesheet/less" scoped>
   .index-wrap {
       width: 100%;
       display: flex;
       .index-left {
           flex: 1 0 0;
           .index-left-block {
               margin: 15px 15px 15px 0;
               background: #fff;
               box-shadow: 0 0 1px #ddd;
               &.lastest-news {
                   max-height: 461px;
               }
               h2 {
                   background: #4fc08d;
                   color: #fff;
                   padding: 10px 15px;
                   margin-bottom: 20px;
               }
               h3 {
                   padding: 0 15px 5px 15px;
                   font-weight: bold;
                   color: #222;
               }
               .hr {
                   margin-bottom: 20px;
               }
               .news {
                   margin-bottom: 5px;
               }
               ul {
                   padding: 10px 15px;
                   li {
                       padding: 5px;
                       .new-item {
                           display: block;
                           text-overflow: ellipsis;
                           white-space: nowrap;
                           overflow: hidden;
                           width: 235px;
                       }
                   }
                   .hot-tag {
                       display: inline-block;
                       font-size: 12px;
                       height: 18px;
                       line-height: 18px;
                       font-weight: 300;
                       background: #ff0000;
                       color: #fff;
                       padding: 0 5px;
                   }
               }
           }
       }
       .index-right {
           flex: 3 0 0;
           margin-top: 15px;
           .index-board-list {
               margin-top: 15px;
               overflow: hidden;
               .index-board-item {
                   float: left;
                   width: 400px;
                   background: #fff;
                   box-shadow: 0 0 1px #ddd;
                   padding: 20px;
                   margin-right: 20px;
                   margin-bottom: 20px;
                   &.line-last {
                       margin-right: 0;
                   }
                   .index-board-item-inner {
                       min-height: 125px;
                       padding-left: 120px;
                       &.index-board-car {
                           background: url(../assets/img/1.png) no-repeat;
                       }
                       &.index-board-loud {
                           background: url(../assets/img/2.png) no-repeat;
                       }
                       &.index-board-earth {
                           background: url(../assets/img/3.png) no-repeat;
                       }
                       &.index-board-hill {
                           background: url(../assets/img/4.png) no-repeat;
                       }
                       h2 {
                           font-size: 18px;
                           font-weight: bold;
                           color: #000;
                           margin-bottom: 15px;
                       }
                       .index-board-button {
                           margin-top: 20px;
                           .button {
                               background: #4fc08d;
                               color: #fff;
                               display: inline-block;
                               padding: 10px 20px;
                               cursor: pointer;
                           }
                       }
                   }
               }
           }
       }
   }
</style>

老师子组件要怎么获取props里面的数据且页面不报错?

正在回答

2回答

fishenal 2017-04-06 19:29:58
  1. 首先,子组件里options的default没有生效,因为父组件options是个空对象已经传进去了,只有options这个字段没有的时候,子组件才回去使用default值

  2. 你的思路是,所有幻灯片的options都来自服务端,ajax异步请求,这其实并不合理,比如间隔时间invTime,这显然是前端控制的事情,修改起来也更加灵活,这是其一,其二,options,数据列表等不同的数据从同一个接口返回,也不合理,前端压力很大,结构不清晰,所以我觉得有必要改成invTime就是父组件的一个同步选项,不需要异步获取。

  3. 顺着你的逻辑来说,就是invTime是异步获取的,子组件只有拿到invTime才能runInv。我刚才试了一下watch,好像对props不生效,那么我能想到的办法,如果不用vuex的话就是eventBus了,我在最后一刻有讲到。


两个组件都引入

import { eventBus } from '../../eventBus'


异步拿到invTime后,发一个全局事件, 这里也可以把invtime设计成另外一个接口,在子组件里调用

created: function () {
    this.$http.get('api/getNewsList')
    .then((res) => {
      this.newsList = res.data
      // this.options.dt = res.data
      // this.invTime = 5000
      eventBus.$emit('afterGetInvTime', res.data.invTime)
    }, (err) => {
      console.log(err)
    })
  },

子组件监听这个事件,回调里调用runInv

mounted () {
    eventBus.$on('afterGetInvTime', (invTime) => {
      this.inv = invTime
      this.runInv()  
    })
  }


*正如代码里写的一样,通过eventBus 都不需要保存invTime,完全作为事件的参数从父组件传到子组件

1 回复 有任何疑惑可以回复我~
  • 提问者 慕容4022837 #1
    非常感谢!
    回复 有任何疑惑可以回复我~ 2017-04-07 23:13:49
  • 提问者 慕容4022837 #2
    谢谢老师的回答,就算invTime不从后台异步获取!  图片信息应该是从后台异步获取的吧!   我这里涉及到一个获取图片高度的问题!只有拿到图片的高度才好设置轮播图的高度!因为图片是position: absolute;脱离了文档流没有高度!所以需要拿到图片高度来设置轮播图最外层高度!要不然看不到轮播图!这个要怎么处理?也是得用到vuex或者eventBus吗?后面的vuex还没看!是在不行那就用vuex来实现吧!  其实好多组件的数据都是后台获取的!比如那个下拉选框组件!里面的数据基本是从后端过来的!
    回复 有任何疑惑可以回复我~ 2017-04-07 23:14:53
  • fishenal 回复 提问者 慕容4022837 #3
    select都好办,直接传进去都能更新,麻烦的就是高度这种,拿到数据的时候页面已经渲染完了,这时候就要事件再去通知页面更新
    回复 有任何疑惑可以回复我~ 2017-04-09 17:22:29
提问者 慕容4022837 2017-04-07 23:13:00

谢谢老师的回答,就算invTime不从后台异步获取!  图片信息应该是从后台异步获取的吧!   我这里涉及到一个获取图片高度的问题!只有拿到图片的高度才好设置轮播图的高度!因为图片是position: absolute;脱离了文档流没有高度!所以需要拿到图片高度来设置轮播图最外层高度!要不然看不到轮播图!这个要怎么处理?也是得用到vuex或者eventBus吗?后面的vuex还没看!是在不行那就用vuex来实现吧!  其实好多组件的数据都是后台获取的!比如那个下拉选框组件!里面的数据基本是从后端过来的!

0 回复 有任何疑惑可以回复我~
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信