一. 大致的使用方法
<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)
// 他自己触发一个意图,打算添加一个更新
}
},
}