1 city

Home.vue新增一个属性:

<template>
   <div>
     <home-header :city="city"></home-header>
     <home-swiper></home-swiper>
     <home-icons></home-icons>
     <home-recommend></home-recommend>
     <home-weekend></home-weekend>
   </div>
 </template>
export default {
   name: 'Home',
   // 声明 局部组件,注册到 Home 组件之后,Home的模板里就能使用它了
   components: {
     HomeHeader,
     HomeSwiper,
     HomeIcons,
     HomeRecommend,
     HomeWeekend
   },
   data () {
     return {
       city: ''
     }
   },

修改对应的 Header 组件:

<script>
 export default {
   name: 'HomeHeader',
   props: {
     city: String
   }
 }
 </script>

ajax请求到数据后,要拿到数据内容:

Vue项目首页实战 - 父子组组件间传值_ico

效果:

Vue项目首页实战 - 父子组组件间传值_ios_02

别急,还有获得的其他字段呢。

2 Swiper.vue

将之前定义的 list 删除,并新增一个 props:

【Swiper.vue】

<template>
 <!--  div来包裹整个轮播图,防止图片还未加载出来导致轮播图区域下面的东西提前显示
 最后又移动位置了-->
   <div class="wrapper">
 <!--    通过v-if来判断是否展示轮播图,如果list数组有数据则展示,否则不展示-->
     <swiper :options="swiperOption" v-if="showSwiper">
       <swiper-slide v-for="item of list" :key="item.id">
         <img class="swiper-img" :src="item.imgUrl" />
       </swiper-slide>
 <!--      在swiper标签里面使用了一个不带页码的点号显示,通过slot来实现-->
       <div class="swiper-pagination"  slot="pagination"></div>
     </swiper>
   </div>
 </template>
 
 <script>
 export default {
   name: 'HomeSwiper',
   props: {
     list: Array
   },
   // 子组件中定义 data 时,必须是个函数 ES6中可省略 function 简化代码
   data () {
     return {
       swiperOption: {
         pagination: '.swiper-pagination',
         // 轮播图支持循环轮播
         loop: true
       }
     }
   },
   computed: {
     // 判断list数组是否有数据,如果有则返回true,展示轮播图
     showSwiper () {
       return this.list.length
     }
   }
 }
 </script>
 
 <style lang="stylus" scoped>
 // <<<  符号表示使用深度选择器,可以选择父级的所有后代元素。
 .wrapper >>> .swiper-pagination-bullet-active
   // 将轮播图的当前页码的背景颜色设为白色
   background: #fff
 .wrapper
   overflow: hidden
   width: 100%
   height: 0
   // 这里是为了实现固定的宽高比(标准写法)
   padding-bottom: 31.25%
   background: #eee
   .swiper-img
     width: 100%
 </style>

连带修改,得到 AJAX 接收到的值:

【Home.vue】

data () {
   return {
     city: '',
     // 新增
     swiperList: []
   }
 },
 methods: {
   getHomeInfo () {
     axios.get('/api/index.json')
       .then(this.getHomeInfoSuccess)
   },
   getHomeInfoSuccess (res) {
     res = res.data
     if (res.ret && res.data) {
       const data = res.data
       this.city = data.city
       // 新增
       this.swiperList = data.swiperList
     }
   }
 },

效果:

Vue项目首页实战 - 父子组组件间传值_ios_03

3 icons

【Icons.vue】修改如下:

<!--在页面上显示一个图标集合,通过Swiper实现分页滑动效果-->
 <template>
   <div class="icons">
     <!-- 在模板中,使用Swiper组件 并将swiperOption作为参数传入 swiperOption中设置了autoplay为false。-->
     <swiper :options="swiperOption">
       <!-- v-for循环遍历page数组中的每个元素,即每一页中的每个图标-->
       <swiper-slide v-for="(page, index) of pages" :key="index">
         <!-- 使用div包裹每个图标,并设置其样式。-->
         <div class="icon" v-for="item of page" :key="item.id">
           <div class='icon-img'>
             <img class='icon-img-content' :src='item.imgUrl'/>
           </div>
           <p class="icon-desc">{{ item.desc }}</p>
         </div>
       </swiper-slide>
     </swiper>
   </div>
 </template>
 
 <script>
 export default {
   name: 'HomeIcons',
   props: {
     list: Array
   },
   computed: {
     pages () {
       const pages = []
       // 将list数组中的每个元素,按8个为一组进行分页
       // 存储在pages数组
       this.list.forEach((item, index) => {
         const page = Math.floor(index / 8)
         if (!pages[page]) {
           pages[page] = []
         }
         pages[page].push(item)
       })
       return pages
     }
   }
 }
 </script>
 
 <!--设置图标的基本样式,包括宽高、位置 图标图片和描述的样式。-->
 <style lang="stylus" scoped>
 @import '~styles/varibles.styl'
 @import '~styles/mixins.styl'
 .icons >>> .swiper-container
   height: 0
   padding-bottom: 50%
 
 .icons
   margin-top: .1rem
 
   .icon
     position: relative
     overflow: hidden
     float: left
     width: 25%
     height: 0
     padding-bottom: 25%
 
     .icon-img
       position: absolute
       top: 0
       left: 0
       right: 0
       bottom: .44rem
       box-sizing: border-box
       padding: .1rem
 
       .icon-img-content
         display: block
         margin: 0 auto
         height: 100%
 
     .icon-desc
       position: absolute
       left: 0
       right: 0
       bottom: 0
       height: .44rem
       line-height: .44rem
       text-align: center
       color: $darkTextColor
       ellipsis()
 </style>

【Home.vue】

<template>
   <div>
     <home-header :city="city"></home-header>
     <home-swiper :list="swiperList"></home-swiper>
     <home-icons :list="iconList"></home-icons>
     <home-recommend></home-recommend>
     <home-weekend></home-weekend>
   </div>
 </template>
 
 <script>
 import HomeHeader from './components/Header'
 import HomeSwiper from './components/Swiper'
 import HomeIcons from './components/Icons'
 import HomeRecommend from './components/Recommend'
 import HomeWeekend from './components/Weekend'
 import axios from 'axios'
 
 export default {
   name: 'Home',
   // 声明 局部组件,注册到 Home 组件之后,Home的模板里就能使用它了
   components: {
     HomeHeader,
     HomeSwiper,
     HomeIcons,
     HomeRecommend,
     HomeWeekend
   },
   data () {
     return {
       city: '',
       swiperList: [],
       iconList: []
     }
   },
   methods: {
     getHomeInfo () {
       axios.get('/api/index.json')
         .then(this.getHomeInfoSuccess)
     },
     getHomeInfoSuccess (res) {
       res = res.data
       if (res.ret && res.data) {
         const data = res.data
         this.city = data.city
         this.swiperList = data.swiperList
         this.iconList = data.iconList
         this.recommendList = data.recommendList
         this.weekendList = data.weekendList
       }
     }
   },
   mounted () {
     this.getHomeInfo()
   }
 }
 </script>
 
 <style>
 </style>

效果:

Vue项目首页实战 - 父子组组件间传值_ico_04

4 recommend && weekend

<!--用于在页面上展示商品列表-->
 <!--组件接受一个名为list的数组作为参数,每个元素包含商品的标题、描述和图片等信息。
 组件会在页面上渲染一个标题“热销推荐”和一个商品列表,
 每个商品都包含标题、描述、图片和一个“查看详情”的按钮。
 当用户点击某个商品时,组件会跳转到该商品的详情页。-->
 
 <!--代码中的<template>部分定义了组件的HTML结构,包括一个标题和一个商品列表。
 商品列表中的每个商品都是一个<router-link>标签,用于实现页面跳转。
 :v-for指令用于遍历list数组中的每个元素,并将其绑定到变量item上,
 :key指令用于为每个商品设置一个唯一的标识符。-->
 <template>
   <div>
     <div class="title">热销推荐</div>
     <ul>
       <router-link
         tag="li"
         class="item border-bottom"
         v-for="item of list"
         :key="item.id"
         :to="'/detail/' + item.id"
       >
         <img class="item-img" :src="item.imgUrl"/>
         <div class="item-info">
           <p class="item-title">{{ item.title }}</p>
           <p class="item-desc">{{ item.desc }}</p>
           <button class="item-button">查看详情</button>
         </div>
       </router-link>
     </ul>
   </div>
 </template>
 
 <script>
 export default {
   name: 'HomeRecommend',
   props: {
     list: Array
   }
 }
 </script>
 
 <!-- 样式都是基于flex布局实现的,以便在不同设备上适应不同的屏幕尺寸。-->
 <style lang="stylus" scoped>
 @import '~styles/mixins.styl'
 // 设置标题的样式
 .title
   margin-top: .2rem
   line-height: .8rem
   background: #eee
   text-indent: .2rem
 
 // .item样式用于设置商品的样式,包括图片、标题、描述和按钮等。
 .item
   overflow: hidden
   display: flex
   height: 1.9rem
 
   .item-img
     width: 1.7rem
     height: 1.7rem
     padding: .1rem
 
   .item-info
     flex: 1
     padding: .1rem
     min-width: 0
 
     .item-title
       line-height: .54rem
       font-size: .32rem
       ellipsis()
 
     .item-desc
       line-height: .4rem
       color: #ccc
       ellipsis()
 
     .item-button
       line-height: .44rem
       margin-top: .16rem
       background: #ff9300
       padding: 0 .2rem
       border-radius: .06rem
       color: #fff
 </style>
 

[Home.vue]

<template>
   <div>
     <home-header :city="city"></home-header>
     <home-swiper :list="swiperList"></home-swiper>
     <home-icons :list="iconList"></home-icons>
     <home-recommend :list="recommendList"></home-recommend>
     <home-weekend></home-weekend>
   </div>
 </template>
 
 <script>
 import HomeHeader from './components/Header'
 import HomeSwiper from './components/Swiper'
 import HomeIcons from './components/Icons'
 import HomeRecommend from './components/Recommend'
 import HomeWeekend from './components/Weekend'
 import axios from 'axios'
 
 export default {
   name: 'Home',
   // 声明 局部组件,注册到 Home 组件之后,Home的模板里就能使用它了
   components: {
     HomeHeader,
     HomeSwiper,
     HomeIcons,
     HomeRecommend,
     HomeWeekend
   },
   data () {
     return {
       city: '',
       swiperList: [],
       iconList: [],
       recommendList: []
     }
   },
   methods: {
     getHomeInfo () {
       axios.get('/api/index.json')
         .then(this.getHomeInfoSuccess)
     },
     getHomeInfoSuccess (res) {
       res = res.data
       if (res.ret && res.data) {
         const data = res.data
         this.city = data.city
         this.swiperList = data.swiperList
         this.iconList = data.iconList
         this.recommendList = data.recommendList
         this.weekendList = data.weekendList
       }
     }
   },
   mounted () {
     this.getHomeInfo()
   }
 }
 </script>
 
 <style>
 </style>
 

[weekend.vue]

<template>
   <div>
     <div class="title">周末去哪儿</div>
     <ul>
       <li
         class="item border-bottom"
         v-for="item of list"
         :key="item.id"
       >
         <div class="item-img-wrapper">
           <img class="item-img" :src="item.imgUrl" />
         </div>
         <div class="item-info">
           <p class="item-title">{{item.title}}</p>
           <p class="item-desc">{{item.desc}}</p>
         </div>
       </li>
     </ul>
   </div>
 </template>
 
 <script>
 export default {
   name: 'HomeWeekend',
   props: {
     list: Array
   }
 }
 </script>
 
 <style lang="stylus" scoped>
   @import '~styles/mixins.styl'
   .title
     line-height: .8rem
     background: #eee
     text-indent: .2rem
   .item-img-wrapper
     overflow: hidden
     height: 0
     padding-bottom: 37.09%
     .item-img
       width: 100%
   .item-info
     padding: .1rem
     .item-title
       line-height: .54rem
       font-size: .32rem
       ellipsis()
     .item-desc
       line-height: .4rem
       color: #ccc
       ellipsis()
 </style>
 

效果:

Vue项目首页实战 - 父子组组件间传值_ci_05

Vue项目首页实战 - 父子组组件间传值_ios_06