前端項目框架搭建隨筆---Tab組件的編寫

低下頭看了看本身的手環。距離本身的flag已經跳票3天了。。。css


不爲何,由於我懶#滑稽 #滑稽#滑稽 html

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

首先仍是先看Tab預覽圖:git

Tab預覽圖



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

首先仍是獻上Tab html代碼和css代碼(我css基礎很差 各位能夠忽略#滑稽)npm

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

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切換app

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的內容

結果還真的有


不過出現了一個空插槽值。。。可是可有可無,咱們能夠加一層空值判斷嘛~~

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。掛載成功是能夠。可是沒法滾動。如圖



經查:是由於他掛載的那個元素,咱們寫個width:100%。致使他丟失了實際長度。沒法掛載。

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



因此咱們爲了兩種都要,加個props外部控制吧~~

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

html:

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


這樣一個不算很完美的tab就完成了。但願製做思想能夠幫到你們

相關文章
相關標籤/搜索