实现的效果类似element-ui的Collapse折叠面板组件,地址链接。
使用效果
<collapse>
<collapse-item>
<template slot="title">
一致性 Consistency
</template>
<div>与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;</div>
<div>在界面中一致:所有的元素和结构需保持一致,比如:设计样式、图标和文本、元素的位置等。</div>
</collapse-item>
</collapse>
复制代码
布局collapse
组件
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {
methods: {
changeState (id) {
this.$children.forEach(child => {
if (child._uid !== id) {
child.isShow = false
} else {
child.isShow = !child.isShow
}
})
}
}
}
</script>
复制代码
布局collapse-item
组件
<template>
<div>
<div @click="handleClick" >
<slot name="title">
标题
</slot>
</div>
<transition>
<div v-show="isShow" class="content">
<slot></slot>
</div>
</transition>
</div>
</template>
<script>
export default {
data () {
return {
isShow: false
}
},
methods: {
handleClick () {
this.$parent.changeState(this._uid)
}
}
}
</script>
<style scoped>
.content {
overflow: hidden;
}
</style>
复制代码
基本的功能已经完成,但是缺少动画,transition
标签内置了很多JS动画钩子函数,通过这些函数来实现动画。控制动画的方式有JS和CSS两种方式。
JS控制动画
beforeEnter (el) {
// 动画之前
el.style.height = 0
},
enter (el, done) {
// 动画过程
let height = el.scrollHeight
let step = height / 300 * 20
let distance = 0
let change = () => {
distance += step
if (distance < height) {
el.style.height = `${distance}px`
requestAnimationFrame(change)
} else {
el.style.height = `${height}px`
done()
}
}
requestAnimationFrame(change)
},
afterEnter (el) {
// 动画之后
console.log('展开动画完成')
},
leave (el, done) {
// 动画过程
let height = el.scrollHeight
let step = height / 300 * 20
let change = () => {
height -= step
if (height > 0) {
el.style.height = `${height}px`
requestAnimationFrame(change)
} else {
el.style.height = 0
done()
}
}
requestAnimationFrame(change)
},
afterLeave (el) {
// 动画之后
console.log('关闭动画完成')
}
复制代码
CSS控制动画
beforeEnter (el) {
// 动画之前
el.style.height = 0
},
enter (el, done) {
// 动画过程
let height = el.scrollHeight
el.style.transition = this.elTransition
el.style.height = `${height}px`
el.addEventListener('transitionend', () => {
done()
})
},
afterEnter (el) {
// 动画之后
console.log('展开动画完成')
},
leave (el, done) {
// 动画过程
el.style.height = 0
el.addEventListener('transitionend', () => {
done()
})
},
afterLeave (el) {
// 动画之后
console.log('关闭动画完成')
}
复制代码
动画功能已经完成,给transition
加上这些方法。
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@leave="leave"
@after-leave="afterLeave"
>
<div v-show="isShow" class="content">
<slot></slot>
</div>
</transition>
复制代码
抽象组件
最后实现一个抽象组件折叠/展开的效果,类似element-ui里面的折叠展开效果,地址链接
<collapse-abstract title="展开/收起">
<div>
<div>与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;</div>
<div>在界面中一致:所有的元素和结构需保持一致,比如:设计样式、图标和文本、元素的位置等。</div>
</div>
</collapse-abstract>
复制代码
抽象组件与普通组件类似。他们只是添加额外的行为。
<script>
export default {
// 在 Vue 中启用抽象组件
abstract: true,
props: {
title: {
type: String,
default: '操作'
}
},
data () {
return {
height: 0,
isShow: false
}
},
render: function (createElement) {
if (this.$slots.default) {
this.height = this.$slots.default[0]
} else {
this.height = 0
}
return createElement(
'div',
[
createElement(
'div',
{
on: {
click: this.clickHandler
},
},
[this.title]
),
createElement(
'div',
{
style: {
height: 0,
transition: '0.3s height ease-in-out',
overflow: 'hidden'
},
ref: 'myRef',
},
this.$slots.default
)
]
)
},
methods: {
clickHandler () {
this.isShow = !this.isShow
if (this.isShow) {
let height = this.height.elm.offsetHeight
this.$refs.myRef.style.height = `${height}px`
this.$refs.myRef.addEventListener('transitionend', () => {
this.$emit('openEnd')
})
} else {
this.$refs.myRef.style.height = 0
this.$refs.myRef.addEventListener('transitionend', () => {
this.$emit('closeEnd')
})
}
}
}
}
</script>
复制代码
代码在这里,点击链接