Vue2.5从零开发猫眼⑦——City组件开发

Vue2.5从零开发猫眼系列以更新完毕

Vue2.5从零开发猫眼①——前言 

Vue2.5从零开发猫眼②——项目开始前准备

Vue2.5从零开发猫眼③——启动页开发

Vue2.5从零开发猫眼④——Home页开发

Vue2.5从零开发猫眼⑤——影院页开发

Vue2.5从零开发猫眼⑥——个人中心组件开发

Vue2.5从零开发猫眼⑦——City组件开发

Vue2.5从零开发猫眼⑧——引入store、LocalStorage和优化上线

City组件开发

  • 获取数据

在static\mock目录创建city.json,由于数据太多这里就不粘贴,需要的话从项目源代码里面下载。

在src\api目录创建city.js

import axios from 'axios'

export function getCityList() {
    return axios.get('/api/city.json', {}).then((res) => {
        return Promise.resolve(res.data)
    })
}
  • 在src目录创建pages\city\City.vue ```html
?> 因为City组件引用了List组件和Alphabet组件,我们分别创建此组件

## 创建List组件
```html
<template>
  <div class="list">
    <scroll class="wrap_content" :data="cities">
      <div>
        <div class="area">
          <div class="title scale-1px">当前城市</div>
          <div class="button-list">
            <div class="button-wrapper">
              <div class="button">北京</div>
            </div>
          </div>
        </div>
        <div class="area">
          <div class="title scale-1px">热门城市</div>
          <div class="button-list">
            <div
              class="button-wrapper"
              v-for="item of hot"
              :key="item.id"
            >
              <div class="button">{{item.name}}</div>
            </div>
          </div>
        </div>
        <div
          class="area"
          v-for="(item, key) of cities"
          :key="key"
          :ref="key"
        >
          <div class="title scale-1px">{{key}}</div>
          <div class="item-list">
            <div
              class="item scale-1px"
              v-for="innerItem of item"
              :key="innerItem.id"
            >
              {{innerItem.name}}
            </div>
          </div>
        </div>
      </div>
    </scroll>
  </div>
</template>

<script>
import Scroll from '@/components/scroll/Scroll'
export default {
  name: 'List',
  props: {
    hot: Array,
    cities: Object,
    letter: String
  },
  components: {
    Scroll
  }
}
</script>

<style lang="stylus" scoped>
  @import '~stylus/variable.styl'
  .list
    width: 100%
    top: 50px
    bottom: 0
    left: 0
    right: 0
    position: fixed
    .wrap_content
      overflow: hidden
      height: 100%      
      .title
        line-height: 27px
        background: #eee
        padding-left: 10px
        color: #666
        font-size: 12px
      .button-list
        overflow: hidden
        padding: 6px 10px 6px 6px;
        .button-wrapper
          float: left
          width: 33.33%
          .button
            margin: 4px
            padding: 4px 0
            text-align: center
            border: 1px solid #ccc
            border-radius: 4px
      .item-list
        .item
          line-height: 32px
          padding-left: 12px
</style>

创建Alphabet组件

<template>
  <ul class="list">
    <li
      class="item"
      v-for="item of letters"
      :key="item"
      :ref="item"
    >
      {{item}}
    </li>
  </ul>
</template>

<script>
export default {
  name: 'Alphabet',
  props: {
    cities: Object
  },
  computed: {
    letters () {
      const letters = []
      for (let i in this.cities) {
        letters.push(i)
      }
      return letters
    }
  },
  data () {
    return {
    }
  },
  methods: {
  }
}
</script>

<style lang="stylus" scoped>
  @import '~stylus/variable.styl'
  .list
    display: flex
    flex-direction: column
    justify-content: center
    position: absolute
    top: 20px
    right: 12px
    bottom: 0
    width: 12px
    .item
      line-height: 20px
      text-align: center
      color: $bgColor
</style>

至此我们的城市页面已经完成,如下图 image

逻辑开发

点击右侧的字符序列,左侧内容跟着切换,主要实现逻辑就是鼠标点下去获取当前的位置的下标,移动开发到结束这段的距离除以每个字符的高度,再加上开始移动的下标位置,就是移动到哪个位置,然后通过scrollToElement移动左侧的位置。

监听字符序列移动时间,纪录当前移动的位置,向父组件出发change事件

  methods: {
    onTouchStart(e) {
      this.touch.initiated = true
      let anchorIndex = e.target.getAttribute('data-index')
      let firstTouch = e.touches[0]
      this.touch.y1 = firstTouch.pageY
      this.currentIndex = anchorIndex;
      this.$emit('change', this.letters[this.currentIndex])
    },
    onTouchMove(e) {
      if (!this.touch.initiated) {
        return
      }
      let firstTouch = e.touches[0];
      this.touch.y2 = firstTouch.pageY;
      let delta = (this.touch.y2 - this.touch.y1) / 20 | 0;
      let index = parseInt(this.currentIndex) + delta;
      this.$emit('change', this.letters[index])
    },
    onTouchEnd(e) {
      this.touch.initiated = false
      this.$emit('end')   
    }
  }

父组件接受change组件,记录当前的letter,向List组件传递

change(letter) {
  this.letter = letter
}

List组件接动态监听letter,移动对应的位置

watch: {
    letter () {
      if (this.letter) {
        this.$refs.scroll.scrollToElement(this.$refs[this.letter][0])
      }
    }
}

List组件也可以显示当前的letter

<transition name="fade">
  <p class="currentIndex" v-if="letter">{{letter}}</p>
</transition> 
<style lang="stylus" scoped>
  .currentIndex
    display: inline-block;
    background: #000;
    position: absolute;
    top: 50%;
    left: 50%;
    width: 50px;
    height: 46px;
    text-align: center;
    line-height: 46px;
    border-radius: 6px;
    color: #ccc;
    opacity: .6;
    font-size:20px;
    margin-left: -25px;
    margin-top: -25px;
    &.fade-enter, &.normal-leave-to
        opacity: 0
    &.fade-enter-active, &.fade-leave-active
        transition: opacity .5s;
</style>

当移动结束后,Aplhabet向List触发end事件

onTouchEnd(e) {
  this.touch.initiated = false
  this.$emit('end')   
}

List接收end,移除letter

end() {
  setTimeout(() => {
    this.letter = ''
  }, 800);  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值