<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 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> {} </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!