一. 大致的使用方法
<div id="app" style="padding-left: 100px">
<g-collpase>
<g-collapse-item title="標題1">內容1</g-collapse-item>
<g-collapse-item title="標題2">內容2</g-collapse-item>
<g-collapse-item title="標題3">內容3</g-collapse-item>
</g-collpase>
</div>
二. 完成最外部的樣式
//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>
三. 進一步調節樣式
// 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>
四. 默認內容折疊起來和點擊切換,基本樣式和基本功能完成
// collapse-item
data (){
return {
open: false
}
}
<div class="content" v-if="open" @click="open=!open">
<slot></slot>
</div>
五. 完善功能第一個點開,第二個就關閉
- 因為結構比較簡單,就父子兩個組件,可以用父子通信來做。
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()
}
}
六. 增加功能是否可以選擇多個
- 方案一.用 single 變量是否需要控制 eventBus
// 添加single選項,有single就注入,沒有就不注入
// 但是這種方式不太完美會有警告
props: {
single: {
type: Boolean,
default: false
}
},
provide() {
if(this.single){
return {
eventBus: this.eventBus
}
}
}
七. 可以設置默認 selected
// index.html
<div id="app" style="padding: 100px">
<g-collapse selected="2">
<g-collapse-item title="標題1" name="1">內容1</g-collapse-item>
<g-collapse-item title="標題2" name="2">內容2</g-collapse-item>
<g-collapse-Item title="標題3" name="3">內容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()
}
})
},
八. 回頭解決子元素是否可以多個打開
- 通過 collapse.vue 傳給 collapse-item
// index.js
<div id="app" style="padding: 100px">
<g-collapse :selected="selectedTab" :selected.sync="selectedTab" single>
<g-collapse-item title="標題1" name="1">內容1 Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus consequatur </g-collapse-item>
<g-collapse-item title="標題2" name="2">內容2 Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquid cupiditate dolore d! </g-collapse-item>
<g-collapse-Item title="標題3" name="3"> 內容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.進一步修改,把選中的值改為數組
// 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) // 通知兒子
this.$emit('update:selected',this.selected) // 通知外面
})
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)
// 移除一個被選中的東西
}else{
this.eventBus && this.eventBus.$emit('update:addSelected', this.name)
}
},
}
10. 將所有數據流讓父組件統一管理。
- 不能直接操作 props 要先深拷貝
// 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) // 通知兒子
this.$emit('update:selected',selectedCopy) // 通知外面
})
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. 數據流的核心
- 不要出現兩個東西互相讓對方更新的狀態
// collapse.vue 爸爸
mounted(){
this.eventBus.$emit('update:selected',this.selected) // 一開始就通知所有兒子,該選中就選中
this.eventBus.$on('update:addSelected', (name)=>{
let selectedCopy = JSON.parse(JSON.stringify(this.selected))
// 如果用戶添加一個我就把selected拷貝一份,因為vue不支持直接修改props
if(this.single){
selectedCopy = [name]
}else{
selectedCopy.push(name)
}
this.eventBus.$emit('update:selected',selectedCopy) // 得到最新被選中的item之后,通知兒子
this.$emit('update:selected',selectedCopy) // 通知外面
})
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)
})
}¡
// collapse-item.vue 兒子
mounted(){
this.eventBus && this.eventBus.$on('update:selected', (names)=>{
// 監聽eventBus,只要他爸爸要說更新,他就更新
console.log(names)
if (names.indexOf(this.name )>= 0){
this.open = true
}else{
this.open = false
}
})
},
methods:{
toggle(){
if(this.open) {
// 這里也沒有修改自己的OPEN,而是在mounted中等爸爸通知我們修改open,所以他的open永遠是爸爸在操作,兒子不操作
this.eventBus &&this.eventBus.$emit('update:removeSelected', this.name)
// 他自己觸發一個意圖,打算移除一個更新
// 移除一個被選中的東西
}else{
this.eventBus && this.eventBus.$emit('update:addSelected', this.name)
// 他自己觸發一個意圖,打算添加一個更新
}
},
}