Vue2.5 去哪儿App 项目学习总结(2)——项目实战 - 旅游网站首页开发

1  iconfont 的使用和代码优化

(1)收藏图标并下载至本地

(2)修改iconfont.css文件中的引用路径

(3)在main.js中引入iconfont.css

import Vue from 'vue'
import App from './App'
import router from './router'
// 引入iconfont文件
import 'styles/iconfont.css'

(4)使用iconfont中的icon

<div class="iconfont back-icon"></div>

(5)修改路径的别名

在webpack.base.conf.js中,简化常用路径的名称

resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
      'styles': resolve('src/assets/styles'),
      'common': resolve('src/common'),
    }
  },

 

2  首页轮播图

(1)安装vue-awesome-swiper插件(2.6.7版本较为稳定)

npm install vue-awesome-swiper@2.6.7 –save

(2)使用插件

import VueAwesomeSwiper from 'vue-awesome-swiper'
import 'swiper/dist/css/swiper.css'
Vue.use(VueAwesomeSwiper)

(3)使用swiper模板

<swiper :options="swiperOption" ref="mySwiper" @someSwiperEvent="callback">
    <!-- slides -->
    <swiper-slide>I'm Slide 1</swiper-slide>
    <swiper-slide>I'm Slide 2</swiper-slide>
    <swiper-slide>I'm Slide 3</swiper-slide>
    <swiper-slide>I'm Slide 4</swiper-slide>
    <swiper-slide>I'm Slide 5</swiper-slide>
    <swiper-slide>I'm Slide 6</swiper-slide>
    <swiper-slide>I'm Slide 7</swiper-slide>
    <!-- Optional controls -->
    <div class="swiper-pagination"  slot="pagination"></div>
    <div class="swiper-button-prev" slot="button-prev"></div>
    <div class="swiper-button-next" slot="button-next"></div>
    <div class="swiper-scrollbar"   slot="scrollbar"></div>
  </swiper>

 

3  图标区域页面布局(重点)

该组件的css写法独特,值得借鉴。

(1)组件接收list数据

(2)由于有多个图标,采用swiper组件进行分页显示

(3)在计算属性中将list分成以8为基数的二维数组,每页显示8个icon

(4)默认关闭swiper组件的自动轮播功能,在需要的时候手动翻页

<template>
  <div class="icons">
    <!-- swiperOption的参数关闭轮播图的自动滚动 -->
    <swiper :options="swiperOption">
      <!-- 遍历轮播图标页面 -->
      <swiper-slide v-for="(page, index) of pages" :key="index">
        <!-- 遍历图标List -->
        <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
  },
  data () {
    return {
      // 默认关闭自动轮播
      swiperOption: {
        autoplay: false
      }
    }
  },
  computed: {
    pages () {
      // 将多个icon构成的一维数组,以8为基础,拆分成二维数组
      // 一页显示8个icon,多余的下一页显示
      const 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外边框的大小
    .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图标大小及居中显示
        .icon-img-content
          display: block
          margin: 0 auto
          height: 100%
      // 绝对定位,控制icon文字位置、大小、居中显示、超出部分省略
      .icon-desc
        position: absolute
        left: 0
        right: 0
        bottom: 0
        height: .44rem
        line-height: .44rem
        text-align: center
        color: $darkTextColor
        // 多余描述文字的省略显示模式
        // 该方法在mixins.styl文件中
        ellipsis()
</style>

 

4 热销推荐组件开发

(1)动态路由,通过id指向不同的组件

<ul>
  <!-- border-bottom用来设置下部1px的边框 -->
  <!-- 因为引入了1px边框的解决方案 -->
  <!-- router-link会自动将li变成a标签,此处将li写到tag中,可以保证将其渲染成li标签 -->
  <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>

(2)通过设定最小宽度让省略方法起作用

设置了flex为1的div,再对其设置min-width为0,保证内容不超出外层容器

.item-info
  // 自动撑开宽度
  flex: 1
  padding: .1rem
  // 可以让item-title和item-desc多余文字的省略方法起作用
  // 设置了flex为1的div,再对其设置min-width为0,保证内容不超出外层容器
  min-width: 0
  .item-title
    line-height: .54rem
    font-size: .32rem
    ellipsis()
  .item-desc
    line-height: .4rem
    color: #ccc
    ellipsis()

(3)ellipsis方法,单行省略

ellipsis()
  overflow: hidden
  white-space: nowrap
  text-overflow: ellipsis

 

5  开发周末游组件

(1)控制图片div的宽高比

(2)全框显示图片

<div class="item-img-wrapper">
  <img class="item-img" :src="item.imgUrl" />
</div>

// 控制图片的宽高比
.item-img-wrapper
  overflow: hidden
  height: 0
  padding-bottom: 37.09%
  // 让图片撑满整个容器
  .item-img
    width: 100%

 

6  使用 axios 发送 ajax 请求

(1)使用axios,在页面的mounted生命周期函数中,发起ajax请求

(2)模拟后台数据

在vue项目目录中,static文件夹是存放的静态文件,只有该文件夹下的文件可以被外界访问到(验证方法:地址栏输入对应static文件夹下面json文件的正确路径如:http://localhost:8080/static/mock/index.json)。发现,对应的模拟数据index.json文件的内容,可以看到,如下:

(3)不希望上传模拟数据至线上,需要做忽略上传处理。

具体做法是:打开.gitignore文件,在忽略的文件中,添加上模拟数据所在的文件路径(static、mock)即可。

(4)vue中webpack-dev-server提供了代理功能。

具体做法如下:在config下的index.js中proxyTable,将对api的请求,转发到本地的8080端口,并且将路径重写到mock目录中。注意:修改配置项的文件后,需要重启项目。

proxyTable: {
  '/api': {
    target: 'http://localhost:8080',
    pathRewrite: {
      '^/api': '/static/mock'
    }
  }
}

 

7  首页父子组组件间传值

(1)解决页面渲染bug——默认显示不是第一幅图

data() {
  return {
    lastCity: '', // 记录上一次城市
    swiperList: [],
    iconList: [],
    recommendList: [],
    weekendList: []
  }
}

这是因为swiper是根据swiperList的空数组创建的,

getHomeInfoSucc(res) {
  res = res.data
  if (res.ret && res.data) {
    const data = res.data
    this.swiperList = data.swiperList
    this.iconList = data.iconList
    this.recommendList = data.recommendList
    this.weekendList = data.weekendList
  }
}

当通过ajax获取数据之后,又重新渲染的页面,所以会出现bug

解决办法就是,只有在有数据时,才渲染页面

<template>
  <div class="wrapper">
    <!-- showSwiper只在有数据的时候,才渲染页面 -->
    <swiper :options="swiperOption" v-if="showSwiper">
      <!-- 轮播图的循环播放 -->
      <!-- id是json数据中有的,且是唯一的 -->
      <swiper-slide v-for="item of list" :key="item.id">
        <!-- item.imgUrl是个变量,需要用v-bind绑定数据 -->
        <img class="swiper-img" :src="item.imgUrl" />
      </swiper-slide>
      <!-- swiper-pagination用于展现分页器(小圆点) -->
      <div class="swiper-pagination" slot="pagination"></div>
    </swiper>
  </div>
</template>

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值