1. 程式人生 > >Vue.js學習記錄-14-Vue去哪兒網專案實戰:城市列表頁開發-Alphabet + 細節配置補充

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. 字母導航條點選具體字母后進行準確的城市定位區域定位:

    字母表點選事件:

      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專案