前端專案框架搭建隨筆---Tab元件的編寫

王聖鬆發表於2018-08-29

低下頭看了看自己的手環。距離自己的flag已經跳票3天了。。。

前端專案框架搭建隨筆---Tab元件的編寫

不為什麼,因為我懶#滑稽 #滑稽#滑稽

咳咳,我們們今天進入正題---Tab元件的編寫

首先還是先看Tab預覽圖:

Tab預覽圖

前端專案框架搭建隨筆---Tab元件的編寫


很簡單的功能,很簡潔的UI。

首先還是獻上Tab html程式碼和css程式碼(我css基礎不好 各位可以忽略#滑稽)

為了自由度高一點,我們採用 Tab+TabPanel 的方式製作。這種製作方式也是大部分UI框架的製作方式

Tab-HTML程式碼

<template>
  <div class="tab-wrapper">
    <div class="tab__header">
      <div class="tab__header__item">
        <div style="width: 100%;">
          <div class="tab__item">
            <span>驗證碼登入</span>
          </div>
          <div class="tab__item">
            <span>密碼登入</span>
         </div>
        </div>
      </div>
    </div>
    <div class="tab__content">
      <slot></slot>
    </div>
  </div>
</template>複製程式碼

Tab-CSS程式碼

<style scoped>
  .iconfont {
    font-size: 1.5rem;
  }

  .tab__header {
    display: flex;
  }

  .tab__header__item {
    margin: 0;
  }

  .tab__header__item > div {
    display: flex;
    flex-direction: row;
    white-space: nowrap;
    transition: transform .3s;
  }

  .tab__item {
    font-size: 1.3rem;
    cursor: pointer;
    margin-right: 1rem;
    flex: 1;
    text-align: center;
  }

  .tab--active > span {
    border-bottom: 2px solid #1890FF;
    color: #1890FF;
    padding-bottom: .5rem;
  }

  .tab__header__btn--left {
    margin-right: .5rem;
    cursor: pointer;
  }

  .tab__header__btn--right {
    margin-left: .5rem;
    cursor: pointer;
  }

  .tab--panel-wrapper {
    display: none;
  }

  .tab--panel-wrapper--active {
    display: block !important;
  }
</style>
複製程式碼


TabPanel程式碼:

<template>
  <div class="tab--panel-wrapper" :name="name">
    <div class="tab--panel-content">
      <slot></slot>
    </div>
  </div>
</template>

<script>
  export default {
    name: "ZbTabPanel",
    props: {
      name: { //Tab模組名
        required: true
      }
    }
  }
</script>

<style scoped>

</style>
複製程式碼



先開始製作基礎功能:Tab切換

Tab切換功能的製作

首先一上來就會出現理解性的問題:

以往我們寫Tab 頭部寫頭部的東西,內容寫內容的東西。兩者分開來寫。便於理解

但如果是這種元件套元件的方式,看起來用法簡單了不少。但是增加了編寫難度

還有一點,父元件怎麼去控制子元件的顯示隱藏情況?

那就一步步來唄。

為了方便便於編寫起來好理解。我選擇內容插入,頭部遍歷的方式去製作

<template>
  <div class="tab-wrapper">
    <div class="tab__header" ref="tabHeaderItem">
      <div class="tab__header__item">
        <div style="width: 100%;">
          <div class="tab__item"
               @click="tabItemClick(item.name,key)" //tab的點選事件
               @touchstart="tabItemClick(item.name,key)" //tab的移動端點選事件
               v-for="(item,key) in tabList" //迴圈list
               :class="{'tab--active':activeTab.index===key}"> //如果當前tabtitle的下標 =已啟用的tabtitle下標
            <span>{{item.name}}</span> 
          </div>
        </div>
      </div>
    </div>
    <div class="tab__content"
         ref="content">
      <slot></slot>
    </div>
  </div>
</template>

複製程式碼


js方面:

data() {
  return {
    tabList: [], //tab標題列表
    activeTab: { //已啟用的tab資訊
      index: 0, //下標
      name: '' //名稱
    }
  }
}複製程式碼


既然是插槽slot,那我們就用點插槽該做的事情 #嘿嘿嘿


於是我在 mounted 函式內,看一下$slot的內容

結果還真的有

前端專案框架搭建隨筆---Tab元件的編寫

不過出現了一個空插槽值。。。但是無關緊要,我們可以加一層空值判斷嘛~~

let self = this; //外層新建變數引用this
this.$slots.default.forEach((components) => { //迴圈default內的內容
  if (components.tag && components.componentOptions) { //如果子元素tag鍵&&componentOptions有內容。
    self.tabList.push(components.componentOptions.propsData) 
    // 在components.componentOptions這個鍵內 有propsDate這個屬性。我們可以通過這個屬性拿到子元件的props值
  }
});
this.$nextTick(() => { //避免data未更新
  this.activeTab = { //給activeTab賦初始值 
    index: 0, //預設選中第一個
    name: this.tabList[0].name //尋找tabList第一個元素 還有他的名字
  };
});複製程式碼

這樣切換頭部功能實現了。但是底部主體內容無動於衷

所以我們在watch函式內,監聽一下activeTab變數的資料變化:

watch: {
  activeTab(newValue, oldValue) {
    this.$refs.content.children[oldValue.index].className = "tab--panel-wrapper";
    this.$refs.content.children[newValue.index].className = "tab--panel-wrapper--active";
  }
}複製程式碼

這樣基礎內容就大功告成了。


用法參考

<zb-tab>
  <zb-tab-panel name="驗證碼登入">
    <!--這是驗證碼登入的內容-->
  </zb-tab-panel>
  <zb-tab-panel name="密碼登入">
    <!--這是密碼登入的內容-->
  </zb-tab-panel>
</zb-tab>複製程式碼

因為name屬性不能少 所以是必填



這樣一來遇到個問題,我們的tab是用flex編寫的。但是如果tab多了橫向滾動怎麼辦?

這裡安利一個滴滴出行@ustbhuangyi 開發的滾動元件: better-scroll

首先我們先安裝他:

better-scroll文件

npm install better-scroll --save複製程式碼

接著在vue元件內引入:

import BScroll from 'better-scroll'複製程式碼

這裡不做過多介紹。所以我們簡單使用。詳細使用請看文件

_initScroll: function () {
  new BScroll(this.$refs.tabHeaderItem, {
    scrollX: true, //是否支援X滾動
    bounce: true //是否開啟回彈動畫
  });
}複製程式碼

掛載函式內

setTimeout(() => {
  this.$nextTick(() => { //避免data未更新
      this._initScroll();
    }
  )
}, 20)複製程式碼

如果看到行內樣式有css動畫。說明就掛載成功了

這樣遇到了一個小bug。掛載成功是可以。但是無法滾動。如圖

前端專案框架搭建隨筆---Tab元件的編寫


經查:是因為他掛載的那個元素,我們寫個width:100%。導致他丟失了實際長度。無法掛載。

但是去掉width:100%後,元素始終不會平鋪開。會左浮動一樣的排列

前端專案框架搭建隨筆---Tab元件的編寫


所以我們為了兩種都要,加個props外部控制吧~~

props: {
  floatLeft: { //是否開啟左浮動模式
    default: false
  }
}複製程式碼

html:

<div class="tab__header__item"
     :style="floatLeft? '': 'width:100%'">複製程式碼


這樣一個不算很完美的tab就完成了。希望製作思想可以幫到大家


相關文章