1. 程式人生 > >Vue.js學習記錄-15-Vue去哪兒網專案實戰:景點詳情頁開發-功能點概述 + Detail + Banner(通用元件:Gallery、Fade)

Vue.js學習記錄-15-Vue去哪兒網專案實戰:景點詳情頁開發-功能點概述 + Detail + Banner(通用元件:Gallery、Fade)

3. 景點詳情頁開發

  • 功能點概述

    • 使用者首頁點選熱銷推薦景點,即可跳轉景點詳情頁面。詳情頁面包括三部分內容:頂部圖片展示、景點門票詳情、隱藏頁面頭。(拖動至下方會出現)
      在這裡插入圖片描述
    • 使用者點選頂部圖片展示,進入圖片輪播區域(全屏),可左右滑動進行圖片瀏覽,點選圖片區域外進行返回景點詳情頁,過渡動畫的使用,圖片輪播區域配置首頁返回按鈕。
      在這裡插入圖片描述
    • 使用者向下拖動景點詳情頁,即可看見隱藏頁面頭部,同時具備返回按鈕,可以返回至首頁。
      在這裡插入圖片描述
    • 景點門票詳情,針對返回的多層資料,進行元件的遞迴呼叫展示。
  • Detail:城市詳情父元件

    • 路由配置

      在該模組中,路由採用了動態引數的形式,進行路由配置,座標/router/index.js:

        import Detail from '@/pages/detail/Detail'
        {
          // 繫結動態引數
          path: '/detail/:id',
          name: 'detail',
          component: Detail
        }
      

      其中 :id 綁定了動態的URL引數,在元件中可以通過:this.$route.params.id 進行獲取

    • 元件管理:

      • 子元件引入及註冊:Banner、Header、List
        • 引入

            import DetailBanner from './components/Banner'
            import DetailHeader from './components/Header'
            import DetailList from './components/List'
          
        • 註冊

            components: {
                DetailBanner,
                DetailHeader,
                DetailList
            }
          
    • 元件互動:三個互動點

      • 首頁熱銷推薦景點點選路由跳轉

        座標:Home.Recommend,路由跳轉時,

        攜帶item.id

          <!-- 採用router-link進行頁面跳轉,tag標識標籤轉換為li,to攜帶引數進行頁面跳轉 -->
          <router-link
              tag="li"
              :to="'/detail/' + item.id"
              class="item border-bottom"
              v-for="item of list"
              :key="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>
        
      • Banner、Header點選返回按鈕路由跳轉

        座標:Header,下文詳細元件中進行介紹

    • 資料傳遞:採用axios進行資料傳遞

      • axios引入

          import axios from 'axios'
        
      • 初始化data

          data() {
            return {
              sightName: '',
              bannerImg: '',
              gallaryImgs: [],
              list: []
            }
          }
        
      • 資料請求

        • 觸發資料請求

            //頁面渲染時觸發方法
            mounted() {
              this.getDetailInfo()
            }
          
        • 資料請求:注意請求拼裝URL的方式,前面已經提到了呼叫動態引數的方法:this.$route.params.id

            methods: {
                getDetailInfo() {
                  axios.get('/api/detail.json?', {
                    params: {
                      id: this.$route.params.id
                    }
                  }).then(this.handleGetDataSucc)
                },
                handleGetDataSucc(res) {
                  res = res.data
                  if (res.ret && res.data) {
                    const data = res.data
                    this.sightName = data.sightName
                    this.bannerImg = data.bannerImg
                    this.gallaryImgs = data.gallaryImgs
                    this.list = data.categoryList
                }
              }
            },			
          
      • 資料傳遞:三個資料項傳遞給Banner元件、一個數據項傳遞給List元件

          <template>
            <div>
              <detail-banner :sightName="sightName" :bannerImg="bannerImg" :gallaryImgs="gallaryImgs"></detail-banner>
              <detail-header></detail-header>
              <div class="content">
                <detail-list :list="list"></detail-list>
              </div>
            </div>
          </template>
        
  • Banner:景點圖片畫廊(通用元件)

    寫在開頭,這一部分要實現的具體功能細節有:

    1. 景點主圖片、景點名稱、畫廊圖片數目展示

    2. 點選主圖片進入圖片畫廊,圖片畫廊可以左右滑動,點選非圖片區域可退回景點詳情頁

    細節1實現:

    根據上文可知,父元件Detail以屬性繫結的方式向Banner元件傳遞了三個資料項,分別是:

    1. sightName:景點名稱
    2. bannerImg:景點主圖片
    3. gallaryImgs:畫廊圖片集

    資料獲取

      props: {
        sightName: String,
        bannerImg: String,
        gallaryImgs: Array
      },
    

    資料對映渲染:該DOM上綁定了點選事件:handleBannerClick,細節2中會提到。

      <div class="banner" @click="handleBannerClick">
          <img class="banner-img" :src="bannerImg" alt=""/>
          <div class="banner-info">
              <div class="banner-title">
                  {{this.sightName}}
              </div>
              <div class="banner-number">
                  <span class="iconfont banner-icon">&#xe67b;</span>
                  {{this.gallaryImgs.length}}
              </div>
          </div>
       </div>
    

    細節2實現:通用元件Gallery、Fade的使用

    在該部分的實現中,將Gallery畫廊元件以及Fade簡單動畫元件做了封裝,封裝為通用元件,也方便其他元件進行呼叫。

    Gallery:畫廊元件

    關於畫廊元件,本質上是Swiper元件,進行了些定製化的配置。比如,鋪滿全屏,分頁器樣式,狀態檢查等。

    關於Swiper元件,詳情API及使用方法見:https://3.swiper.com.cn/api/index.html

    <template>:迴圈資料項、點選事件:handleGallaryClick,控制是否進入景點圖片畫廊

      <template>
        <div class="container" @click="handleGallaryClick">
          <div class="wrapper">
            <swiper :options="swiperOptions">
              <!-- slides -->
              <swiper-slide v-for="(item, index) in imgs" :key="index">
                <img class="gallary-img" :src="item">
              </swiper-slide>
              <!-- Optional controls -->
              <div class="swiper-pagination" slot="pagination"></div>
            </swiper>
          </div>
        </div>
      </template>
    

    迴圈資料項:由於Gallery元件為公共元件,呼叫該元件的即為其父元件(這裡是Banner)。Banner元件將gallaryImgs陣列傳遞給Gallery元件,在模板中通過index為索引進行了遍歷輸出。

      props: {
        imgs: {
          type: Array,
      	// 預設值為空陣列
          default() {
            return []
          }
        }
      },
    

    點選事件:handleGallaryClick,當點選區域時觸發點選事件,向父元件(Banner)觸發close事件,關閉通用畫廊元件。

      methods: {
        handleGallaryClick() {
          // 關閉公共畫廊事件
          this.$emit('close')
        }
      },
    

    定製化配置:Swiper3 相關配置 https://3.swiper.com.cn/api/

      data() {
        return {
          swiperOptions: {
            pagination: '.swiper-pagination',
            // 分式分頁器
            paginationType: 'fraction',
            // 將observe應用於Swiper的父元素。當Swiper的父元素變化時,例如window.resize,Swiper更新。
            observeParents: true,
            // 啟動動態檢查器(OB/觀眾/觀看者),當改變swiper的樣式(例如隱藏/顯示)或者修改swiper的子元素時,自動初始化swiper。
            observer: true
          }
        }
      },
    

    官網API說明: https://3.swiper.com.cn/api/
    在這裡插入圖片描述
    在這裡插入圖片描述
    在這裡插入圖片描述
    Fade:簡單CSS動畫元件

    該通用元件實質上為過渡效果的動畫元件,之前文章中也提到過,CSS簡單的動畫過渡效果,這裡同一封裝為元件方便其他元件使用。

    其他元件在使用Fade元件時候,外層巢狀元件標籤即可,元件將以插槽的方式包裹在<transition>標籤內部。

      <template>
        <transition>
          <slot></slot>
        </transition>
      </template>
      
      <script>
      export default {
        name: 'Fade'
      }
      </script>
      
      <style lang="stylus" scoped>
        .v-enter, .v-leave-to
          opacity: 0
        .v-enter-active, .v-leave-active
          transition: opacity .5s
      </style>
    

    我們回到Banner元件中,引入並使用這兩個通用元件。

    • 引入並註冊通用元件

        import CommonGallary from 'common/gallary/Gallary'
        import FadeAnimation from 'common/fade/Fade'
      
        components: {
          CommonGallary,
          FadeAnimation
        }
      
    • 使用通用元件

      <template>

        <!-- 新增動畫效果:漸隱漸現,內部common-gallary元件以插槽的方式嵌入 -->
        <fade-animation>
          <!-- 公用圖片畫廊 父子元件互動 + 展示控制-->
          <common-gallary
            :imgs="gallaryImgs"
            @close="handleGallaryClose"
            v-show="showGallary"></common-gallary>
        </fade-animation>
      

      這裡可以看到傳遞給Gallery元件傳遞給父元件Banner的close的事件:handleGallaryClose,並且該元件上採用v-show做了元件展示的控制,控制變數為showGallary。

      預設情況下:

        data() {
          return {
            showGallary: false
          }
        },
      

      點選景點主圖片區域時:

        handleBannerClick() {
      		this.showGallary = true
        }
      

      點選通用元件Gallary區域時:

        handleGallaryClose() {
          this.showGallary = false
        }