VUE 實現 Studio 管理後臺(五):手風琴式摺疊組件(Accordion)

作爲一個有目標的人(目標是做一個好用的 Bootstrap 可視化編輯器,第一個版本已經實現,演示地址:https://vular.cn/rxeditor/,代碼地址:https://github.com/vularsoft/rxeditor),工作比較積極,思維也比較活躍,睡眠相對較少。今早 6:30 就起牀了,喫早飯前,實現了一個手風琴式摺疊組件,具體效果如下:


一般情況,這樣的控件有兩種表現形式:

1、排他展開,也就是一次只有一個項目展開,其它閉合,類似 QQ 的好友分組。

2、隨意展開,不拍它,可以同時展開多個

只實現第二種方式,相對比較容易,每個子項目控制自己的狀態就可以,不用跟其它項目交互。我的目標式做一個控件,兩種方式都支持,通過屬性參數 multiple 確定是否可以同時展開多個。

添加新的文件跟目錄:


跟上次實現 Tabs 控件一樣,有一個通用的子組件:CollapsibleItem,基於這個組件實現摺疊組件:SimpleAccordion。如果以後像實現其它風格的摺疊組件,可以共用 CollapsibleItem 組件。根據我個人的習慣,首先設想這個組件的使用方式,應該是這樣:

<SimpleAccordion :multiple='true'>

    <CollapsibleItem>

    <template #heading>標題1</template>

    <template #body>內容1....</template>

    </CollapsibleItem>

    <CollapsibleItem>

    <template #heading>標題2</template>

    <template #body>內容2....</template>

    </CollapsibleItem>

</SimpleAccordion>

按照這樣的需求,先寫 SimpleAccordion 的模板代碼:

<template>

  <div class="simple-accordion">

    <slot></slot>

  </div>

</template>

看起來非常簡單,接下來再寫 CollapsibleItem 的模板代碼:

<template>

  <div class="collapsible-item" :class="!isActive ? 'item-collapse' : ''">

    <div class="item-heading" @click="click">

      <slot name="heading"></slot>

    </div>

    <div class="item-body">

      <slot name="body"></slot>

    </div>

  </div>

</template>

兩個 slot 分別對應每個摺疊項的標題跟內容。如果該項被摺疊的話,那麼放置 css class: item-collapse。標題容器 DIV 接收 click 事件。腳本代碼:

export default {

  name: 'CollapsibleItem',

  props: {

    selected: { default: false}

  },

  data() { return {

      isActive: false };

  },

  methods: {

    click() { this.$emit('itemClick', this)

    }

  },

  mounted() { this.isActive = this.selected;

  }

}

其他部分跟 tabs 控件一樣,並不難理解,需要注意的是 click 方法,這個方法接收到鼠標點擊事件後,在分發給它的父組件,本例中父組件就是 SimpleAccordion。

再看 SimpleAccordion 的腳本代碼:

export default {

  name: 'SimpleAccordion',

  props: {

    multiple: { default: false}

  },

  data() { return {items: [] }

  },

  created() { this.items = this.$children

  },

  mounted () { this.items.forEach(item=>{

      item.$on('itemClick', this.itemClick)

    })

  },

  methods: {

    itemClick(clickedItem) {

      clickedItem.isActive = !clickedItem.isActive if(!this.multiple){ this.items.forEach(item => { if(item !== clickedItem){

            item.isActive = false }

        })

      }

    }

  }

}

在 mounted 的方法中,在所有的子項上註冊事件 “itemClick”,這個事件在子組件中分發。事件處理方法 itemClick 根據需要,激活相應的項目。

這樣這個控件就完成了,對應的 CSS:

  .simple-accordion{

    flex: 1;

    width: 100%;

    overflow: auto;

    height: 0;

    display: flex;

    flex-flow: column;

    margin-top: 2px;

  }

  .simple-accordion .collapsible-item{

    display: flex;

    flex-flow: column;

    width: 100%;

  }

  .simple-accordion .item-heading{

    display: flex;

    flex-flow: row;

    flex-wrap: wrap;

    align-items: center;

    font-size: 12px;

    color:#f0f1ef;

    padding-left: 10px;

    padding-top:10px;

    padding-bottom:10px;

    padding-right:20px;

    position: relative;

    border-top:#484848 solid 1px;

    border-bottom:#282828 solid 1px;

    cursor: default;

  }

  .simple-accordion .item-heading:hover{

    background: #383838;

  }

  .simple-accordion .collapsible-item .item-heading span{

    margin-right: 5px;

  }

  .simple-accordion .collapsible-item .item-heading small{

    white-space:nowrap;

    color: #aaa;

    font-size: 11px;

  }

  .simple-accordion .collapsible-item .item-heading::after{

    position: absolute;

    content: '';

    width: 0;

    height: 0;

    top: calc(50% -1px);

    right: 19px;

    border-width: 4px;

    border-style: solid;

    border-color: #f0f1ef transparent transparent  transparent;

  }

  .simple-accordion .item-body{

    border-top:#282828 solid 1px;

    padding: 10px;

  }

  .simple-accordion .collapsible-item.item-collapse .item-heading::after{

    position: absolute;

    content: '';

    width: 0;

    height: 0;

    top: calc(50% -1px);

    right: 17px;

    border-width: 4px;

    border-style: solid;

    border-color:transparent transparent  transparent #f0f1ef;

  }

  .simple-accordion .collapsible-item.item-collapse .item-body{

    display: none;

  }

  .simple-accordion .item-body .element{

    -webkit-user-select: none;

    -moz-user-select: none;

    -ms-user-select: none;

    user-select: none;

    cursor: move;

    color: #c2c2c2;

    font-size: 13px;

    padding:5px 5px;

    margin:3px;

    display: flex;

    flex-flow: row;

    justify-content: space-between;

    align-items: center;

  }

  .simple-accordion .item-body .element:hover{

    color: #75b325;

    box-shadow: 2px 2px 5px 0px rgba(0, 0, 0, 0.4);

  }

做這個控件時,碰到了一些細小問題,調整了項目的 CSS,其中比較重要的有以下幾點:

1、窗口拖動時,拖動把手會被擠沒,在把手的 CCS 中添加:

flex-shrink: 0;

這樣可以避免 handle 被擠小擠沒

2、SimpleAccordion 寬度設爲 100%, 他會把父組件 WidgetTabs 撐大,失去拖放效果。後來追蹤到是 WidgetTabs 的父元素沒有設置寬度,從 widgettabs 到固定寬度的父容器,全部設置寬度 100%:

.left-inner{

  width:100%;

}

.top-area{

  width:100%;

}

3、用於顯示展開閉合的箭頭,使用 css 繪製,具體繪製原理,請自行百度。

整個項目在這個歷史節點的代碼,請到我的 Github 上查看:https://github.com/vularsoft/studio-ui

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章