Vue組件實現景深卡片輪播示例

前言

朋友的朋友做瞭個首頁,首頁用到一個卡片輪播,大概就是這個樣子的:

第一版他們是開發出來瞭,但是各種bug,希望我幫忙改一下。

看完代碼以後,發現他們整合瞭一個縫合怪出來,各個樓層都是從其他地方 CV 過來的,而且各個樓層引用瞭 n 多個js 和 css 文件,看瞭一下效果以後,覺得改他的東西確實比重新開發一個要麻煩的多得多,所以就重新寫瞭一下。

在此記錄一下,以便於後續復用。

需求拆解

  • 初始化渲染5個容器,用來承載圖片和標題,按照景深的效果排列,越靠近自己越大。
  • 點擊中間一塊的左邊的整體向右旋轉一格,點擊右邊的向左旋轉一格,點擊中間的沒有效果。
  • 中間一項顯示 content 和 查看更多 按鈕,其他不顯示。

開發思路(vue2)

  • 景深效果可以選擇使用 css3 的轉換來制作,通過對每個容器進行不通比例的縮放來實現5個容器大小不一致的效果。
  • 因為使用到瞭css3的轉換,就需要用到過渡,動畫效果就使用 transition-group 來實現。
  • 至此就可以輪播就可以滾動起來瞭,隻需要給5個容器循環賦值css樣式,就可以實現縮放和位置轉換,結合漸變,就成瞭一個循環動畫效果。
  • 點擊事件,一開始的思路是通過獲取點擊事件中的鼠標的坐標,如果在左半個屏幕就走左邊的邏輯,但是頁面有個最小寬度 1280,當分辨率被拖動的時候就不行瞭,所以pass掉瞭。最後選擇的方案是,給容器一套下標(_id)的同時全局聲明一個變量用來記錄當前展示的容器的下標,每次點擊都要和展示項作比較,通過比較結果來確定左右邏輯。
  • 思維發散:
    • 可以擴展為7個甚至更多容器的輪播
    • 擴展為n個容器,但是隻顯示5個的輪播
    • 景深效果以及動畫效果改變

開發過程

首先是html+css部分,這部分很簡單,而且很普通。

  • 寫 5 個div,每個都用絕對定位的方式鋪滿整個屏幕,每個寬度都是 20%。
  • 綁定各數據,並用 幾個 狀態值來控制 content 的顯示隱藏,以及當前展示項。

代碼如下:

<script>
// 引入圖片資源
import loop1 from '@assets/images/loop1.png';
import loop2 from '@assets/images/loop2.png';
import loop3 from '@assets/images/loop3.png';
import loop4 from '@assets/images/loop4.png';
import loop5 from '@assets/images/loop5.png';
/**
 * 根據 id 獲取下標
 * @params arr object[]
 * @params id number
 * @result number n>=-1
 */
const findIdxById = (arr, id) => {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === id) {
      return i;
    }
  }
  return -1;
};
export default {
  data() {
    return {
      // 輪播數據
      baseData: [
        {
          desc:
            '可折疊式智能移動影院Royle-X展現瞭驚人的高科技技術和全球首創的可折疊設計,配備瞭柔宇科技自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折疊計自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折',
          title: '這裡是標題',
          cover: loop1,
        },
        {
          desc:
            '可折疊式智能移動影院Royle-X展現瞭驚人的高科技技術和全球首創的可折疊設計,配備瞭柔宇科技自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折疊計自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折',
          title: '這裡是標題',
          cover: loop2,
        },
        {
          desc:
            '可折疊式智能移動影院Royle-X展現瞭驚人的高科技技術和全球首創的可折疊設計,配備瞭柔宇科技自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折疊計自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折',
          title: '這裡是標題',
          cover: loop3,
        },
        {
          desc:
            '可折疊式智能移動影院Royle-X展現瞭驚人的高科技技術和全球首創的可折疊設計,配備瞭柔宇科技自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折疊計自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折',
          title: '這裡是標題',
          cover: loop4,
        },
        {
          desc:
            '可折疊式智能移動影院Royle-X展現瞭驚人的高科技技術和全球首創的可折疊設計,配備瞭柔宇科技自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折疊計自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折自助研發的首款智能移動顯示操作系統,設計非常人性化。可能會可折',
          title: '這裡是標題',
          cover: loop5,
        },
      ],
      // 當前展示項
      loopCenterIdx: 2,
      // 輪播樣式模板,用來循環賦值給 容器
      loopModules: [
        {
          loopIdx: 0,
          style: {
            'z-index': 7,
            background: '#fff',
            transform: `scale(${1})`,
            left: 'calc(100% / 5 * 0)',
            height: '320px',
            opacity: 0.8,
          },
        },
        {
          loopIdx: 1,
          style: {
            'z-index': 8,
            transform: `scale(${1.4})`,
            background: '#fff',
            left: 'calc(100% / 5 * .9)',
            height: '320px',
            opacity: 0.9,
          },
        },
        {
          loopIdx: 2,
          style: {
            transform: `scale(${1.7})`,
            'z-index': 9,
            background: '#fff',
            left: 'calc(100% / 5 * 2)',
            opacity: 1,
            'box-shadow': '0 0 5px #ccc',
            height: '370px',
          },
        },
        {
          loopIdx: 3,
          style: {
            transform: `scale(${1.4})`,
            'z-index': 8,
            background: '#fff',
            left: 'calc(100% / 5 * 3.1)',
            opacity: 0.9,
            height: '320px',
          },
        },
        {
          loopIdx: 4,
          style: {
            'z-index': 7,
            transform: `scale(${1})`,
            background: '#fff',
            left: 'calc(100% / 5 * 4)',
            height: '320px',
            opacity: 0.8,
          },
        },
      ],
    };
  },
  created(){
    // todo Ajax ...
  },  
  mounted() {
    // 初始化輪播
    this.initLoop();
    console.log('centerIdx = ', this.loopCenterIdx);
  },
  methods: {
    // 初始化輪播
    initLoop() {
      this.loopModules = this.loopModules.map((item, idx) => {
        item.desc = this.baseData[idx];
        return item;
      });
      console.log(this.loopModules);
    },
    // 下一張
    handleNext() {
      this.loopCenterIdx = this.loopCenterIdx + 1 > 4 ? 0 : this.loopCenterIdx + 1;
      this.loopModules = this.loopModules.map((item, idx) => {
        item.desc = this.baseData[idx];
        return item;
      });
      this.loopModules.unshift(this.loopModules.pop());
    },
    // 上一張
    handleLast() {
      this.loopCenterIdx = this.loopCenterIdx - 1 < 0 ? 4 : this.loopCenterIdx - 1;
      this.loopModules = this.loopModules.map((item, idx) => {
        item.desc = this.baseData[idx];
        return item;
      });
      this.loopModules.push(this.loopModules.shift());
    },
    // 點擊容器
    handleLoop(checkId) {
      console.log('checkId = ', checkId, ', loopCenterIdx = ', this.loopCenterIdx);
      // 當前項
      if (checkId === this.loopCenterIdx) {
        return;
      }
      if (checkId > this.loopCenterIdx) {
        if (this.loopCenterIdx === 0 && checkId === 4) {
          return this.handleLast(checkId);
        } else {
          return this.handleNext(checkId);
        }
      }
      if (checkId < this.loopCenterIdx) {
        if (checkId === 0 && this.loopCenterIdx === 4) {
          return this.handleNext(checkId);
        } else {
          return this.handleLast(checkId);
        }
      }
    },
  },
};
</script>

js代碼裡面有兩個地方需要註意的:

  • 可以看到在上一張和下一張對應的方法裡面,有兩個一行代碼。其作用就是讓5個容器轉起來。
this.loopModules.unshift(this.loopModules.pop());
// [1,2,3,4] =&gt; [2,3,4,1]
this.loopModules.push(this.loopModules.shift());
// [1,2,3,4] =&gt; [4,1,2,3]
  • 在 handleLoop 方法中,需要註意展示項為 第一個 和 最後一個 的時候,和正常判斷邏輯相反。

後記

輪播作為一個日常開發中最常見的組件,想必每一個前端都在學習js的時候將他作為一個很有意思的 demo 練過手,而景深卡片輪播算是比基礎輪播稍微難一點的效果瞭。

這個組件值得記錄下來的是把數據驅動視圖的思路更好的進行瞭一次展示,這也是基於框架開發和原生開發的一個重要的轉變。如果在 jquery 中,可能會用 $(selector).animate() 去控制動畫效果,原生 js 中也會封裝一個類似 animate() 的方式去逐幀的實現一系列的動畫,而在 vue 中,直接修改數據的順序,或者修改數據值,就讓 dom 動起來瞭。

數據驅動視圖的思路下,我們就不必去關註視圖的變化,也不用頻繁的去操作dom元素,隻需考慮清除一組可以控制視圖變化的鏈路就好瞭。例如:分頁組件隻需要關註當前頁碼和每頁顯示數量,表格組件隻需要關註列數據的變化等等。其他的部分框架已經做瞭很多。

路還很長,每走一步都有新感悟!

以上就是Vue組件實現景深卡片輪播示例的詳細內容,更多關於Vue景深卡片輪播的資料請關註WalkonNet其它相關文章!

推薦閱讀: