低下頭看了看本身的手環。距離本身的flag已經跳票3天了。。。css
不爲何,由於我懶#滑稽 #滑稽#滑稽 html
咳咳,我們今天進入正題---Tab組件的編寫vue
首先仍是先看Tab預覽圖:git
很簡單的功能,很簡潔的UI。github
首先仍是獻上Tab html代碼和css代碼(我css基礎很差 各位能夠忽略#滑稽)npm
爲了自由度高一點,咱們採用 Tab+TabPanel 的方式製做。這種製做方式也是大部分UI框架的製做方式bash
<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>複製代碼
<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>
複製代碼
<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 頭部寫頭部的東西,內容寫內容的東西。二者分開來寫。便於理解函數
但若是是這種組件套組件的方式,看起來用法簡單了很多。可是增長了編寫難度
還有一點,父組件怎麼去控制子組件的顯示隱藏狀況?
那就一步步來唄。
爲了方便便於編寫起來好理解。我選擇內容插入,頭部遍歷的方式去製做
<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多了橫向滾動怎麼辦?
首先咱們先安裝他:
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就完成了。但願製做思想能夠幫到你們