Vue.js学习记录-14-Vue去哪儿网项目实战:城市列表页开发-Alphabet + 细节配置补充

  • Alphabet:字母表导航条 (增量式)

    组件data初始化:

      name: 'CityAlphabet',
      props: {
        cities: Object
      },
      data() {
        return {
           touchStatus: false,
           startY: 0,
           timer: null
        }
      },
    

    父组件通过属性进行数据传递:

      <city-alphabet :cities="cities" @change="handleLetterChange"></city-alphabet>
    

    功能点4:用户可以在城市列表页右侧的字母导航条中进行点击具体字母项进行准确的城市信息定位,也可以通过上下拖动字母表导航条进行字母城市列表的随动检索。

    <template>:

      <ul class="list-alphabet">
        <li
          class="item-alphabet"
          :ref="item"
          v-for="item of letters" :key="item"
          @click="handleLetterClick"
          @touchstart="handleTouchStart"
          @touchmove="handleTouchMove"
          @touchend="handleTouchEnd"
          >{{item}}</li>
      </ul>
    

    letter数组的产生:对应上述模板

      computed: {
        letters() {
          // 定义空字母数组
          const letters = []
          // 遍历cities对象,将字母存入该数组
          for (let i in this.cities) {
            letters.push(i)
          }
          return letters
        }
      },
    

    1. 字母导航条点击具体字母后进行准确的城市定位区域定位:

    change事件接收letter
    更新letter并传递
    通过ref引用定位到具体字母表项
    Alphabet组件
    City组件
    List组件
    区块滚动

    字母表点击事件:

      handleLetterClick(e) {
        // 向外触发事件,传递点击的元素内容
        this.$emit('change', e.target.innerText)
      },
    

    父组件City接收change事件,对letter变量进行赋值:

      handleLetterChange(letter) {
        this.letter = letter
      }
    

    将letter作为属性向组件List传递:

      <city-list :cities="cities" :hot="hotCities" :letter="letter"></city-list>
    

    组件List侦听letter变化:

      watch: {
        // 监听器:监听右字母表发生变化后触发
        letter() {
          if (this.letter) {
            // 通过ref定位到指定DOM结构
            const element = this.$refs[this.letter][0]
            // 将element传递后进行区块的滚动
            this.scroll.scrollToElement(element)
          }
        }
      }
    

    侦听器内部的this.refs[this.letter][0],对应List组件模板中的字母表城市信息DOM:

      <div class="area" v-for="(item, key) of cities" :key="key" :ref="key">
    

    对象结构:(item, key) – ([A1,A2,…], A),element变量值即为该模板区域的字母项,利用scrollToElement方法便可滚动到指定element区域。

    2. 拖动字母表导航条进行字母城市列表的随动检索:

      三个事件,其中start、end函数是围绕move函数展开,通过touchStatus值的变化。
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
    

    初始化touchStatus:

      touchStatus: false
    

    handleTouchStart:

      handleTouchStart() {
        this.touchStatus = true
      },
    

    handleTouchEnd:

      handleTouchEnd() {
        this.touchStatus = false
      }
    

    handleTouchMove:当touchStatus标识符为True时,进行随动效果的实现。

      handleTouchMove(e) {
        // 只有当touchStatus标识符为true时,进行城市列表的随动效果实现
        if (this.touchStatus) {
      	// 采用了定时器进行列表性能的优化
          if (this.timer) {
            clearTimeout(this.timer)
          }
          // 性能优化2 16毫秒时间间隔延迟执行手指滚动,函数节流,降低该函数的执行频率
          this.timer = setTimeout(() => {
            // 记录出当前触摸点距离窗口可视区域的Y坐标,减去Header + Search的高度(79像素)
            const touchY = e.touches[0].clientY - 79
            // 算法重点:touchY - startY 差值为滑动的距离,已知每个item的高度为20像素,由此可以计算出当前触摸点的item的下标
            const index = Math.floor((touchY - this.startY) / 20)
            if (index >= 0 && index <= this.letters.length) {
              // 满足item下标限制条件向父组件City触发change事件
              this.$emit('change', this.letters[index])
            }
          }, 16)
        }
      },
    

    结合实际图示有利于理解上述方法:
    在这里插入图片描述
    由于startY的计算是在每次letter的值变化时候才触发,所以将startY的计算添加至updated这个钩子函数:

      // 性能优化1 从父组件city重新改变传递letter值时,该组件会重新进行渲染
      updated() {
        // 记录字母表中首字母A距离父元素list的顶端高度 74像素
        this.startY = this.$refs['A'][0].offsetTop
      },		
    
  • 细节配置补充:

    • keep-alive优化网页性能

      在业务开发中,会有路由跳转但是返回需要保留数据的场景,返回DOM并且不刷新DOM,vue中提供了keep-alive来处理。

      坐标:根组件 APP.vue

        <template>
          <div id="app">
            <!-- Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。 -->
            <keep-alive>
              <!-- 当前路由地址所对应的内容 -->
              <router-view/>
            </keep-alive>
          </div>
        </template>
      

      在实际场景之中,此项做法虽然可以进行页面优化,但是DOM的不刷新可能会带来一些不好的用户体验,比如博主之前在Search组件中提到的下拉列表的滞留问题。

    • 关于在stylus中使用scoped实现私有化样式的问题

      为了防止CSS样式污染,针对Vue的单文件组件应用上给出了scoped概念,但是在使用scoped样式的时候还是会有些许问题出现。

      博主遇到的问题是组件内的样式被污染了,scoped配置无效,参考了以下文章:

      https://segmentfault.com/a/1190000012184604?utm_source=tuicool&utm_medium=referral

      https://segmentfault.com/a/1190000010971143

    • 列表性能优化:setTimeout

    至此,城市列表页的开发结束了,实际前几天就学习完了。博文的整理的确需要时间,也相当于再复习一遍,互勉。
    项目源码在码云上有公开仓库,有需要的童鞋可以移步:Travel项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程小透明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值