Realizing studio management background with Vue (5): Accordion

Time:2021-6-1

As a person with a goal (the goal is to make an easy-to-use visual editor of bootstrap. The first version has been implemented. Demo address:https://vular.cn/rxeditor/, code address:https://github.com/vularsoft/rxeditor)They work actively, think actively and sleep less. I got up at 6:30 this morning. Before breakfast, I realized an accordion type folding assembly. The specific effects are as follows:

Realizing studio management background with Vue (5): Accordion

Generally, there are two forms of such controls:

1. Exclusive expansion, that is, only one project at a time, other closed, similar to QQ friends group.

2. Unfold it at will. You can unfold multiple images at the same time without shooting it

It’s relatively easy to implement the second way only. Each subproject can control its own state without interacting with other projects. My goal is to make a control, which supports both methods. The attribute parameter multiple is used to determine whether multiple controls can be expanded at the same time.

Add a new file and Directory:

Realizing studio management background with Vue (5): Accordion

Just like the previous implementation of the tabs control, there is a common sub component: collapsible item. Based on this component, the folding component: simpleaccordion is implemented. If you want to implement other styles of collapsible components in the future, you can share the collapsible item component. According to my personal habits, first of all, I think the usage of this component should be as follows:

<SimpleAccordion :multiple='true'> 
    <CollapsibleItem>
    < template? Heading > Heading 1 < / template >
    < template? Body > content 1... < / template >
    </CollapsibleItem>
    <CollapsibleItem>
    < template? Heading > Heading 2 < / template >
    < template body > content 2... < / template > content 2
    </CollapsibleItem>
</SimpleAccordion>

According to this requirement, first write the template code of simpleaccordion

<template>
  <div class="simple-accordion">
    <slot></slot>
  </div>
</template>

It looks very simple. Next, write the template code of collapsileitem:

<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>

Two slots correspond to the title and content of each fold item. If the item is collapsed, place CSS class: item collapse. The header container div receives the click event. Script code:

export default {
  name: 'CollapsibleItem',
  props: {
    selected: { default: false}
  },
  data() { return {
      isActive: false };
  },

  methods: {
    click() { this.$emit('itemClick', this)
    }
  },

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

Like the tabs control, other parts are not difficult to understand. Note the click method. After receiving the mouse click event, this method distributes it to its parent component. In this case, the parent component is simpleaccordion.

Look at the script code of simpleaccordion again

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 }
        })
      }
    }
  }
}

In the mounted method, register the event “itemclick” on all the child items, and this event is distributed in the child components. The event handling method itemclick activates the corresponding project as needed.

In this way, the control is completed. The corresponding 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); 
  }

When doing this control, I encountered some minor problems and adjusted the CSS of the project. The more important ones are as follows:

1. When dragging the window, the handle will be squeezed out. Add the following in the CCS of the handle:

flex-shrink: 0;

This will prevent the handle from being squeezed

2. If the width of simpleaccordion is set to 100%, it will make the parent component widgettabs bigger and lose the drag and drop effect. Later, it was found that the parent element of widgettabs did not set the width. From widgettabs to the parent container with fixed width, the width was set to 100%

.left-inner{
  width:100%;
}
.top-area{
  width:100%;
}

3. Used to display the expanded and closed arrow, using CSS drawing, specific drawing principle, please do it yourself.

For the code of the whole project in this history node, please check it on my GitHubhttps://github.com/vularsoft/studio-ui

How to find the history node:

Realizing studio management background with Vue (5): Accordion

Rxeditor is a visual editing tool for bootstrap code. This series records the development process of the software. If you have any questions, please leave a message on ithub.

This work adoptsCC agreementReprint must indicate the author and the link of this article