Vue made wheels - accordion assembly

1, General usage

<div id="app" style="padding-left: 100px">
  <g-collpase>
    <g-collapse-item title="Heading 1">Content 1</g-collapse-item>
    <g-collapse-item title="Heading 2">Content 2</g-collapse-item>
    <g-collapse-item title="Heading 3">Content 3</g-collapse-item>
  </g-collpase>
</div>

2, Finish the outermost style

//collapse
<style lang="scss" scoped>
  $grey: #ddd;
  $border-radius: 4px;
  .collapse {
    border: 1px solid $grey;
    border-radius: $border-radius;
  }
</style>

//collapse-item.vue
<style lang="scss" scoped>
  $grey: #ddd;
  $border-radius: 4px;
  .collapseItem {
    > .title {
      border: 1px solid $grey;
      margin-top: -1px;
      margin-left: -1px;
      margin-right: -1px;
    }
    &:first-child {
      > .title {
        border-top-left-radius: $border-radius;
        border-top-right-radius: $border-radius;
      }
    }
  }
</style>

3, Further style adjustment

// collapse-item
<style lang="scss" scoped>
  $grey: #ddd;
  $border-radius: 4px;
  .collapseItem {
    > .title {
      border: 1px solid $grey;
      margin-top: -1px;
      margin-left: -1px;
      margin-right: -1px;
      min-height: 32px;
      display: flex;
      align-items: center;
      padding: 0 8px;
    }
    &:first-child {
      > .title {
        border-top-left-radius: $border-radius;
        border-top-right-radius: $border-radius;
      }
    }
    > .content{
      padding: 8px;
    }
  }
</style>

4, The default content is folded and clicked to switch, and the basic style and basic functions are completed

// collapse-item
    data (){
      return {
        open: false
      }
    }

    <div class="content" v-if="open" @click="open=!open">
      <slot></slot>
    </div>

5, The first point is to open and the second point is to close

  • Because the structure is relatively simple, the parent-child communication can be used for the two components.
    mounted(){
      this.eventBus.$on('update:selected', (vm)=>{
        if (vm !== this){
          this.close()
        }
      })
    },
    methods:{
      toggle(){
        if(this.open) {
          this.open = false
        }else{
          this.open = true
          this.eventBus.$emit('update:selected', this)
        }
      },
      close(){
        this.close()
      }
    }

6, Can multiple functions be selected

  • Scheme 1. Whether to control eventBus with single variable
    // Add the single option. If there is a single option, inject it. If there is no option, inject it
    // But it's not perfect. There's a warning
    props: {
      single: {
        type: Boolean,
        default: false
      }
    },
    provide() {
      if(this.single){
        return {
          eventBus: this.eventBus
        }
      }
    }

7, Default selected can be set

// index.html

    <div id="app" style="padding: 100px">
      <g-collapse selected="2">
        <g-collapse-item title="Heading 1" name="1">Content 1</g-collapse-item>
        <g-collapse-item title="Heading 2" name="2">Content 2</g-collapse-item>
        <g-collapse-Item title="Heading 3" name="3">Content 3</g-collapse-Item>
      </g-collapse>
    </div>

// collapse-item.vue
    mounted(){
      this.eventBus && this.eventBus.$on('update:selected', (name)=>{
        if (name !== this.name){
          this.close()
        }else{
          this.show()
        }
      })
    },

8, Go back and solve whether child elements can be opened multiple times

  • Pass to collapse item through collapse.vue
// index.js
  <div id="app" style="padding: 100px">
    <g-collapse :selected="selectedTab" :selected.sync="selectedTab" single>
      <g-collapse-item title="Heading 1" name="1">Content 1 Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus consequatur </g-collapse-item>
      <g-collapse-item title="Heading 2" name="2">Content 2 Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquid cupiditate dolore d! </g-collapse-item>
      <g-collapse-Item title="Heading 3" name="3"> Content 3 Lorem ipsum dolor sit amet, consectetur adipisicing elit. Excepturi, magnam. </g-collapse-Item>
      {{selectedTab}}
    </g-collapse>
  </div>
// collapse.vue
 mounted(){
      this.eventBus.$emit('update:selected',this.selected)
      this.eventBus.$on('update:selected', (name)=>{
        this.$emit('update:selected',name)
      })
      this.$children.forEach((vm)=>{
        vm.single = this.single
        console.log(vm)
      })
    }
// collapse-item.vue
  mounted(){
      this.eventBus && this.eventBus.$on('update:selected', (name)=>{
        if (name !== this.name){
          if(this.single){
            this.close()
          }
        }else{
          this.show()
        }
      })
    },

9. Further modify to change the selected value to an array

    // collapse.vue
    mounted(){
      this.eventBus.$emit('update:selected',this.selected)
      this.eventBus.$on('update:addSelected', (name)=>{
        this.selected.push(name)
        this.eventBus.$emit('update:selected',this.selected)  // Notify son
        this.$emit('update:selected',this.selected) // Notice outside
      })
      this.eventBus.$on('update:removeSelected', (name)=>{
        let index = this.selected.indexOf(name)
        this.selected.splice(index,1)
        this.eventBus.$emit('update:selected',this.selected)
        this.$emit('update:selected',this.selected)
      })
      this.$children.forEach((vm)=>{
        vm.single = this.single
        console.log(vm)
      })
    }
    // collapse-item.vue
    methods:{
      toggle(){
        if(this.open) {
          this.open = false
          this.eventBus && this.eventBus.$emit('update:removeSelected', this.name)
          // Remove a selected item
        }else{
          this.eventBus && this.eventBus.$emit('update:addSelected', this.name)
        }
      },
    }

####10. Let the parent component manage all data flows in a unified way.

  • Cannot operate props directly
  // collapse.vue
      mounted(){
      this.eventBus.$emit('update:selected',this.selected)
      this.eventBus.$on('update:addSelected', (name)=>{
        let selectedCopy = JSON.parse(JSON.stringify(this.selected))
        if(this.single){
          selectedCopy = [name]
        }else{
          selectedCopy.push(name)
        }
        this.eventBus.$emit('update:selected',selectedCopy)  // Notify son
        this.$emit('update:selected',selectedCopy) // Notice outside
      })
      this.eventBus.$on('update:removeSelected', (name)=>{
        let selectedCopy = JSON.parse(JSON.stringify(this.selected))
        let index = selectedCopy.indexOf(name)
        selectedCopy.splice(index,1)
        this.eventBus.$emit('update:selected',selectedCopy)
        this.$emit('update:selected',selectedCopy)
      })
      this.$children.forEach((vm)=>{
        vm.single = this.single
        console.log(vm)
      })
    }

11. The core of data flow

  • Don't let two things update each other
  // collapse.vue Dad
      mounted(){
      this.eventBus.$emit('update:selected',this.selected) // Inform all sons at the beginning, and select the right one
      this.eventBus.$on('update:addSelected', (name)=>{
        let selectedCopy = JSON.parse(JSON.stringify(this.selected))
        // If the user adds one, I will copy the selected one, because vue does not support modifying props directly
        if(this.single){
          selectedCopy = [name]
        }else{
          selectedCopy.push(name)
        }
        this.eventBus.$emit('update:selected',selectedCopy)  // After getting the latest selected item, inform the son
        this.$emit('update:selected',selectedCopy) // Notice outside
      })

      this.eventBus.$on('update:removeSelected', (name)=>{
        let selectedCopy = JSON.parse(JSON.stringify(this.selected))
        let index = selectedCopy.indexOf(name)
        selectedCopy.splice(index,1)
        this.eventBus.$emit('update:selected',selectedCopy) // If the user wants to remove it, he also informs his son to remove it
        this.$emit('update:selected',selectedCopy)
      })
      this.$children.forEach((vm)=>{
        vm.single = this.single
        console.log(vm)
      })
    }ยก
    // collapse-item.vue son
        mounted(){
      this.eventBus && this.eventBus.$on('update:selected', (names)=>{
        // Monitor eventBus, as long as his father wants to say update, he will update
        console.log(names)
        if (names.indexOf(this.name )>= 0){
          this.open = true
        }else{
            this.open = false
        }
      })
    },
    methods:{
      toggle(){
        if(this.open) {
          // There is no change to his own open here, but in the mounted medium, dad tells us to change open, so his open is always operated by his father, but not by his son
          this.eventBus &&this.eventBus.$emit('update:removeSelected', this.name)
          // He triggers an intention to remove an update
          // Remove a selected item
        }else{
          this.eventBus && this.eventBus.$emit('update:addSelected', this.name)
          // He triggered an intention to add an update
        }
      },
    }

Finally, personal wechat, welcome to exchange!

This article is based on the platform of blog one article multiple sending OpenWrite Release!

Tags: Front-end Vue JSON

Posted on Sat, 01 Feb 2020 11:58:35 -0500 by Berone