likes
comments
collection
share

(08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

作者站长头像
站长
· 阅读数 19
转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

1 需求

首页的“图标分类区域”一页展示 8 个图标,超过 8 个切换至第二页展示。

(08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

2 图标区域布局

1️⃣在 home 下的 components 文件夹中,新建“图标区域组件” Icons.vue(08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

<template>
  <div> <!-- 1️⃣-②:添加文字内容。 -->
    Icons
  </div>
</template>

<script>
export default {
  name: 'HomeIcons' // 1️⃣-①:给组件命名为 HomeIcons;
}
</script>

<style lang="stylus" scoped>
</style>

2️⃣打开 Home.vue ,在首页使用 Icons.vue 组件:

<template>
  <div>
    <home-header></home-header>
    <home-swiper></home-swiper>
    
    <home-icons></home-icons> <!-- 2️⃣-③:使用 Icons 组件。 -->
  </div>

</template>

<script>
import HomeHeader from './components/Header'
import HomeSwiper from './components/Swiper'

import HomeIcons from './components/Icons' // 2️⃣-①:引入 Icons.vue;

export default {
  name: 'Home',
  components: {
    HomeHeader,
    HomeSwiper,

    HomeIcons // 2️⃣-②:在 Home.vue 中注册 Icons 组件;
  }
}
</script>

<style>
</style>

保存后,返回页面查看效果,“Icons”出现在首页轮播下方,页面无报错: (08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

3️⃣根据设计稿可以知道,图标区域的宽高比大致为 2:1,每个图标所占区域宽、高为整个图标区域宽的 25%,且每个图标下方有一个文字描述区域: (08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

<template>
  <div class="icons"> <!-- 3️⃣-①:最外层 div 类名为 icons; -->

    <div class="icon"> <!-- 3️⃣-②:添加一个小的图标区域,类名为 icon,里面包含一个 div
											 和一个 p 标签; -->
      
      <div class="icon-img"> <!-- 3️⃣-③:div 类名为 icon-img,里边是一个
														 图标图片的 img 标签; -->

        <!-- 3️⃣-④:给图标图片添加类名 icon-img-content; -->
        <img class="icon-img-content" src="https://qdywxs.github.io/travel-images/iconList01.png">
      </div>

      <p class="icon-desc">景点门票</p> <!-- 3️⃣-⑤:p 标签类名为 icon-desc,显示图标的
																			描述文字; -->
    </div>

  </div>
</template>

<script>
export default {
  name: 'HomeIcons'
}
</script>

<style lang="stylus" scoped>

.icons /* 3️⃣-⑥:设置 .icons 区域的高度为宽度的 50%(即:设置 .icons 宽高比为 2:1); */
  overflow: hidden
  height: 0
  padding-bottom: 50%

  background: #ccc /* ❗️设置背景色为灰色,方便观察。 */

  .icon
    position: relative /* 
  										 3️⃣-⑥:给 .icon 添加定位为 relative,
  										 让 .icon-img 相对于它绝对定位;
   											*/

    overflow: hidden /* 3️⃣-④:设置每个 .icon 的宽、高为父元素宽的 25%,左浮动; */
    float: left
    width: 25%
    height: 0
    padding-bottom: 25%

    background: red /* ❗️设置背景色为红色,方便观察。 */

    .icon-img /*
  						3️⃣-⑤:让 .icon-img 绝对定位,设置 bottom 为 0.44rem,
  						给 p 标签的内容预留位置;
   						 */
      position: absolute
      top: 0
      left: 0
      right: 0
      bottom: .44rem

      box-sizing: border-box /*
  													 3️⃣-⑦:在 .icon-img 上设置 box-sizing 为 border-box,
                             padding 为 0.1 rem 增加图标间距;
  														*/
      padding: .1rem

      background: blue /* ❗️设置背景色为蓝色,方便观察。 */

      .icon-img-content /* 3️⃣-⑧:设置图片 display 为 block,在父元素内居中,高度为 100%; */
        display: block
        margin: 0 auto
        height: 100%

    .icon-desc /*
  						 3️⃣-⑨:在 .icon-img 同级的位置,编写 .icon-desc 的样式,
  						 设置 .icon-desc 绝对定位,高度和行高为 0.44rem,内容居中显示,字体颜色为 #333。
  							*/
      position: absolute
      left: 0
      right: 0
      bottom: 0
      height: .44rem
      line-height: .44rem
      text-align: center
      color: #333
</style>

保存后,返回页面查看效果: (08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

这里的“景点门票”文字颜色,在页面的其他地方,可能也会使用到,所以我们可以给这个颜色设置一个变量。

4️⃣打开 src 下 assets 中 styles 里的 varibles.styl

$bgColor = #00bcd4
$darkTextColor = #333 /* 4️⃣-①:定义颜色变量 $darkTextColor; */

4️⃣-②:打开 home 下的 components 里的 Icons.vue

<template>
  <div class="icons">
    <!-- ❗️复制 .icon,在首页展示 8 个图标查看效果。 -->
    <div class="icon">
      <div class="icon-img">
        <img class="icon-img-content" src="https://qdywxs.github.io/travel-images/iconList01.png">
      </div>
      <p class="icon-desc">景点门票</p>
    </div>
    <div class="icon">
      <div class="icon-img">
        <img class="icon-img-content" src="https://qdywxs.github.io/travel-images/iconList01.png">
      </div>
      <p class="icon-desc">景点门票</p>
    </div>
    <div class="icon">
      <div class="icon-img">
        <img class="icon-img-content" src="https://qdywxs.github.io/travel-images/iconList01.png">
      </div>
      <p class="icon-desc">景点门票</p>
    </div>
    <div class="icon">
      <div class="icon-img">
        <img class="icon-img-content" src="https://qdywxs.github.io/travel-images/iconList01.png">
      </div>
      <p class="icon-desc">景点门票</p>
    </div>
    <div class="icon">
      <div class="icon-img">
        <img class="icon-img-content" src="https://qdywxs.github.io/travel-images/iconList01.png">
      </div>
      <p class="icon-desc">景点门票</p>
    </div>
    <div class="icon">
      <div class="icon-img">
        <img class="icon-img-content" src="https://qdywxs.github.io/travel-images/iconList01.png">
      </div>
      <p class="icon-desc">景点门票</p>
    </div>
    <div class="icon">
      <div class="icon-img">
        <img class="icon-img-content" src="https://qdywxs.github.io/travel-images/iconList01.png">
      </div>
      <p class="icon-desc">景点门票</p>
    </div>
    <div class="icon">
      <div class="icon-img">
        <img class="icon-img-content" src="https://qdywxs.github.io/travel-images/iconList01.png">
      </div>
      <p class="icon-desc">景点门票</p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'HomeIcons'
}
</script>

<style lang="stylus" scoped>

/* 4️⃣-③:引入 varibles.styl; */
@import '~styles/varibles.styl'

.icons
  overflow: hidden
  height: 0
  padding-bottom: 50%

  /* background: #ccc ❗️删除无用代码; */

  .icon
    position: relative
    overflow: hidden
    float: left
    width: 25%
    height: 0
    padding-bottom: 25%

    /* background: red ❗️删除无用代码; */

    .icon-img
      position: absolute
      top: 0
      left: 0
      right: 0
      bottom: .44rem
      box-sizing: border-box
      padding: .1rem

      /* background: blue ❗️删除无用代码。 */
  
      .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 /* 4️⃣-④:使用颜色变量。 */
</style>

保存后,返回页面查看效果: (08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

3 图标区域逻辑

图标区域的图标较多、数量不定。很明显的,这一块儿的代码也是通过循环数据来展示的。

❓那么,当图标超过 8 个时,如何让第一页仅显示八个,超出的内容展示到第二页呢? 答:这里,我们也可以用轮播来处理。

5️⃣打开 Icons.vue

<template>
  <div class="icons">

    <swiper> <!-- 5️⃣-⑥:添加 swiper 标签; -->
      
      <swiper-slide> <!-- 5️⃣-⑦:使用 swiper-slide 包裹每个图标区域。 -->

        <!-- 5️⃣-①:保留一个图标; -->
        <!-- 5️⃣-③:循环 iconList 数组,绑定 key 值为循环项的 id; -->
        <div class="icon" v-for="item of iconList" :key="item.id">
          
          <div class="icon-img">

            <img class="icon-img-content" :src="item.imgUrl"> <!-- 5️⃣-④:绑定图标图片
                                                              的地址为循环项的 imgUrl;
																															-->
          </div>
          <p class="icon-desc">{{item.desc}}</p> <!-- 5️⃣-⑤:渲染图标描述信息为循环项
																								 的 desc; -->
        </div>
      </swiper-slide>
    </swiper>

  </div>
</template>

<script>
export default {
  name: 'HomeIcons',
  data () {
    return {
      iconList: [{ /*
      						 5️⃣-②:在 data 函数中返回数据 iconList 数组,里面包含 9 个图标的数据,
      						 包括 id、图标图片地址和图标描述信息; 
                   	*/
        id: '0001',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList01.png',
        desc: '景点门票'
      }, {
        id: '0002',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList02.png',
        desc: '滑雪季'
      }, {
        id: '0003',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList03.png',
        desc: '泡温泉'
      }, {
        id: '0004',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList04.png',
        desc: '动植园'
      }, {
        id: '0005',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList05.png',
        desc: '游乐园'
      }, {
        id: '0006',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList06.png',
        desc: '必游榜单'
      }, {
        id: '0007',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList07.png',
        desc: '演出'
      }, {
        id: '0008',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList08.png',
        desc: '城市观光'
      }, {
        id: '0009',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList09.png',
        desc: '一日游'
      }]
    }
  }
}
</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.icons
  overflow: hidden
  height: 0
  padding-bottom: 50%
  .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
</style>

❌保存后,返回页面发现轮播没问题,数据也正确渲染。但,第九个图标被隐藏了,它的位置被继续排列在了下方区域,没有显示在第二页:

(08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

❓如何让第九个图标正确显示到轮播的第二页呢? 答:我们可以利用计算属性。

6️⃣打开 home 中的 components 里的 Icons.vue

<template>
  <div class="icons">
    <swiper>
      <swiper-slide>
        <div class="icon" v-for="item of iconList" :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',
  data () {
    return {
      iconList: [{
        id: '0001',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList01.png',
        desc: '景点门票'
      }, {
        id: '0002',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList02.png',
        desc: '滑雪季'
      }, {
        id: '0003',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList03.png',
        desc: '泡温泉'
      }, {
        id: '0004',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList04.png',
        desc: '动植园'
      }, {
        id: '0005',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList05.png',
        desc: '游乐园'
      }, {
        id: '0006',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList06.png',
        desc: '必游榜单'
      }, {
        id: '0007',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList07.png',
        desc: '演出'
      }, {
        id: '0008',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList08.png',
        desc: '城市观光'
      }, {
        id: '0009',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList09.png',
        desc: '一日游'
      }]
    }
  },
  computed: {  /* 6️⃣-①:在 data 后新增 computed,定义一个 pages 计算属性; */
    pages () {

      const pages = [] /* 6️⃣-②:定义轮播页数为 pages,初始化为一个空数组; */

      this.iconList.forEach((item, index) => { /*
      																				 6️⃣-③:循环 iconList 里的每一项数据,
      																				 接收循环项 item 和下标 index 两个参数;
                                               	*/

        const page = Math.floor(index / 8) /*
        																	 6️⃣-④:定义 page 变量,指当前下标对应的
        																	 数据项展示在轮播的第几页(即轮播的页码);
        																	 6️⃣-⑤:用下标除以 8 来限制一页为八个数据,
                                           通过 Math.floor 取得当前数据展示的页数
                                           page(若当前数据下标为 3,3/8 小于 1,向下取整,
                                           则 page 为 0,即展示在第一页;若当前数据下标
                                           为 8,8/8 等于 1,向下取整,则 page 为 1,
                                           即展示在第二页);
                                            */

        if(!pages[page]) { /*
        									 6️⃣-⑥:如果 pages 下的 page 不存在,则让 pages[page] 
        									 等于一个空数组(即初始化 pages[page] 为一个空数组);
                            */
          pages[page] = []
        }

        pages[page].push(item) /*
        											 6️⃣-⑦:把循环项放入 pages[page] 中(若当前循环项下标为 3,
        											 则 page 为 0,当前循环项放入轮播第一页;若当前循环项下标为 8,
                               则 page 为 1,当前循环项放入轮播第二页);
                                */
      })
      
      return pages /* 6️⃣-⑧:循环完毕后,返回 pages。 */
    }
  }
}
</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.icons
  overflow: hidden
  height: 0
  padding-bottom: 50%
  .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
</style>

❓当我们写完计算属性 pages 后,如何能查看数据是否正确呢? 答:安装“Chrome 网上应用店”的 Vue.js devTools 插件,可以友好的调试 Vue 项目,或查看 Vue 中组件的数据等。

打开 Chrome 网上应用店搜索 vue devtools ,找到提供方为 https://vuejs.org 的插件,点击 “添加至 Chrome” 即可安装插件: (08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

安装插件后,在控制台找到插件并打开(未找到插件,可关闭浏览器重新打开项目页面): (08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

这里面,可以看到我们页面上所有的组件。点击 HomeIcons(即 Icons.vue ),可以在下方看见其中的数据。

比如,iconList 数组中有 9 个数据。 computed 里有一个 pages,它是一个二维数组(即数组里的元素也是数组)。pages 里的第一个数组有八个数据,即展示在第一页的数据;第二个数组有一个数据,即展示在第二页的数据: (08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

(⚠️computed 里的逻辑,就是让我们把 iconList 里的数据,拆分为 pages 这样的二维数组,让“页码 page”和数据项进行关联。)

7️⃣在对 iconList 中的数据进行处理后,我们成功获取到图标轮播有几页,接下来就可以对数据进行渲染:

<template>
  <div class="icons">
    <swiper>
      
      <!-- 7️⃣-①:在 swiper-slide 上循环 pages,获取轮播有几页; -->
      <swiper-slide v-for="(page, index) of pages" :key="index">

        <!-- 7️⃣-②:icon 中改为对 page 进行循环,即循环每一页上的数据。 -->
        <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',
  data () {
    return {
      iconList: [{
        id: '0001',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList01.png',
        desc: '景点门票'
      }, {
        id: '0002',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList02.png',
        desc: '滑雪季'
      }, {
        id: '0003',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList03.png',
        desc: '泡温泉'
      }, {
        id: '0004',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList04.png',
        desc: '动植园'
      }, {
        id: '0005',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList05.png',
        desc: '游乐园'
      }, {
        id: '0006',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList06.png',
        desc: '必游榜单'
      }, {
        id: '0007',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList07.png',
        desc: '演出'
      }, {
        id: '0008',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList08.png',
        desc: '城市观光'
      }, {
        id: '0009',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList09.png',
        desc: '一日游'
      }]
    }
  },
  computed: {
    pages () {
      const pages = []
      this.iconList.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'
.icons
  overflow: hidden
  height: 0
  padding-bottom: 50%
  .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
</style>

❌保存后,返回页面查看,图标区域超过 8 个图标的部分,放入了轮播的第二页。但,这里的轮播是不需要自动播放的:

(08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

8️⃣我们通过vue-awesome-swiper 插件的一个属性,关闭图标区域轮播的自动播放:

<template>
  <div class="icons">
    
    <swiper :options="swiperOption"> <!-- 8️⃣-①:在 swiper 标签绑定 options; -->

      <swiper-slide v-for="(page, index) of pages" :key="index">
        <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',
  data () {
    return {

      swiperOption: {
        autoplay: false /*
        								8️⃣-②:在 data 中定义 swiperOption,设定 autoplay 为 false,
        								关闭轮播的自动播放。
                         */
      },
      iconList: [{
        id: '0001',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList01.png',
        desc: '景点门票'
      }, {
        id: '0002',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList02.png',
        desc: '滑雪季'
      }, {
        id: '0003',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList03.png',
        desc: '泡温泉'
      }, {
        id: '0004',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList04.png',
        desc: '动植园'
      }, {
        id: '0005',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList05.png',
        desc: '游乐园'
      }, {
        id: '0006',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList06.png',
        desc: '必游榜单'
      }, {
        id: '0007',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList07.png',
        desc: '演出'
      }, {
        id: '0008',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList08.png',
        desc: '城市观光'
      }, {
        id: '0009',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList09.png',
        desc: '一日游'
      }]
    }
  },
  computed: {
    pages () {
      const pages = []
      this.iconList.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'
.icons
  overflow: hidden
  height: 0
  padding-bottom: 50%
  .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
</style>

保存后,返回页面查看,轮播不再自动播放,图标区域显示正常:

(08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

❓当 iconList 数据少于八个时,图标区域能否正常显示呢? 答:我们可以保留 iconList 中的四个数据,进行测试。

<template>
  <div class="icons">
    <swiper :options="swiperOption">
      <swiper-slide v-for="(page, index) of pages" :key="index">
        <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',
  data () {
    return {
      swiperOption: {
        autoplay: false
      },
      iconList: [{
        id: '0001',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList01.png',
        desc: '景点门票'
      }, {
        id: '0002',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList02.png',
        desc: '滑雪季'
      }, {
        id: '0003',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList03.png',
        desc: '泡温泉'
      }, {
        id: '0004',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList04.png',
        desc: '动植园'
      }] /* ❗️保留 4 个数据,进行测试。 */
    }
  },
  computed: {
    pages () {
      const pages = []
      this.iconList.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'
.icons
  overflow: hidden
  height: 0
  padding-bottom: 50%
  .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
</style>

保存后,返回页面可以看到,当数据少于 8 个时,数据渲染没有问题。但,整个 .icons 区域中,有图标的区域才有轮播,在下半部分拖动时,则没有效果:

(08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

9️⃣通过上面的视频可以知道,能拖动的区域就是 .swiper-container 这个轮播区:

<template>
  <div class="icons">
    <swiper :options="swiperOption">
      <swiper-slide v-for="(page, index) of pages" :key="index">
        <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',
  data () {
    return {
      swiperOption: {
        autoplay: false
      },
      iconList: [{
        id: '0001',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList01.png',
        desc: '景点门票'
      }, {
        id: '0002',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList02.png',
        desc: '滑雪季'
      }, {
        id: '0003',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList03.png',
        desc: '泡温泉'
      }, {
        id: '0004',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList04.png',
        desc: '动植园'
      }]
    }
  },
  computed: {
    pages () {
      const pages = []
      this.iconList.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'

.icons >>> .swiper-container /*
  													 9️⃣-①:由于 .swiper-container 是第三方插件的样式,所以这里
  													 通过深度作用选择器,设置它的宽高比为整个图标区域的宽高比(swiper 
  													 的样式自带 overflow: hidden,所以这里省略);
  														*/
  height: 0
  padding-bottom: 50%

.icons /* 9️⃣-②:给图标区域增加 0.1rem 的 margin-top,调整图标区域间隙。 */
  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
</style>

保存后,返回页面查看效果,整个图标区域基本没有问题了:

(08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

4 细节优化

当图标下方的描述文字过多时,信息显示不全。而当信息显示不全时,页面也没有明显的指示: (08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

在这里,就可以给“溢出的文字加点”。在我们的项目中,其他部分也可能需要用到,所以可以直接对它进行封装,在需要用到时,再进行引用。

🔟在 src 下 assets 中的 styles 里新建一个 mixins.styl 的文件: (08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

🔟-①:在 mixins.styl 中,定义一个 ellipsis 方法;

ellipsis() /* ❗️ellipsis 方法不需要参数,只需要写入“文字溢出加点”的三行代码即可。 */
  overflow: hidden
  white-space: nowrap
  text-overflow: ellipsis

🔟-②:返回 home 下 components 里的 Icons.vue ,使用 ellipsis 方法;

<template>
  <div class="icons">
    <swiper :options="swiperOption">
      <swiper-slide v-for="(page, index) of pages" :key="index">
        <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',
  data () {
    return {
      swiperOption: {
        autoplay: false
      },
      iconList: [{
        id: '0001',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList01.png',
        desc: '景点门票'
      }, {
        id: '0002',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList02.png',
        desc: '滑雪季'
      }, {
        id: '0003',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList03.png',
        desc: '泡温泉'
      }, {
        id: '0004',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList04.png',
        desc: '动植园'
      }, {
        id: '0005',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList05.png',
        desc: '游乐园'
      }, {
        id: '0006',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList06.png',
        desc: '必游榜单'
      }, {
        id: '0007',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList07.png',
        desc: '演出'
      }, {
        id: '0008',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList08.png',
        desc: '城市观光'
      }, {
        id: '0009',
        imgUrl: 'https://qdywxs.github.io/travel-images/iconList09.png',
        desc: '一日游'
      }] /* ❗️恢复为原数据。 */
    }
  },
  computed: {
    pages () {
      const pages = []
      this.iconList.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'

/* 🔟-③:从 styles 下引入 mixins.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() /* 🔟-④:在 .icon-desc 调用 ellipsis 方法。 */
</style>

保存后,返回页面查看效果,当文字超出时,已经显示为“点”: (08)首页开发——③ 图标区域组件 | Vue.js 项目实战: 移动端“旅游网站”开发1 需求 首页的“图标分类区域

以上,我们就完成了“图标区域组件” Icons.vue

🏆本篇总结:

  1. 通过拆分 iconList 中的数据为二维数组,实现图标数据分页展示;
  2. “文字溢出加点”多处会用到时,单独封装为方法,需要时再调用。

祝好,qdywxs ♥ you!

转载自:https://juejin.cn/post/7399952146254020659
评论
请登录