You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
402 lines
8.8 KiB
402 lines
8.8 KiB
<template> |
|
<view class="uni-collapse-item"> |
|
<!-- onClick(!isOpen) --> |
|
<view @click="onClick(!isOpen)" class="uni-collapse-item__title" |
|
:class="{'is-open':isOpen &&titleBorder === 'auto' ,'uni-collapse-item-border':titleBorder !== 'none'}"> |
|
<view class="uni-collapse-item__title-wrap"> |
|
<slot name="title"> |
|
<view class="uni-collapse-item__title-box" :class="{'is-disabled':disabled}"> |
|
<image v-if="thumb" :src="thumb" class="uni-collapse-item__title-img" /> |
|
<text class="uni-collapse-item__title-text">{{ title }}</text> |
|
</view> |
|
</slot> |
|
</view> |
|
<view v-if="showArrow" |
|
:class="{ 'uni-collapse-item__title-arrow-active': isOpen, 'uni-collapse-item--animation': showAnimation === true }" |
|
class="uni-collapse-item__title-arrow"> |
|
<uni-icons :color="disabled?'#ddd':'#bbb'" size="14" type="bottom" /> |
|
</view> |
|
</view> |
|
<view class="uni-collapse-item__wrap" :class="{'is--transition':showAnimation}" |
|
:style="{height: (isOpen?height:0) +'px'}"> |
|
<view :id="elId" ref="collapse--hook" class="uni-collapse-item__wrap-content" |
|
:class="{open:isheight,'uni-collapse-item--border':border&&isOpen}"> |
|
<slot></slot> |
|
</view> |
|
</view> |
|
|
|
</view> |
|
</template> |
|
|
|
<script> |
|
// #ifdef APP-NVUE |
|
const dom = weex.requireModule('dom') |
|
// #endif |
|
/** |
|
* CollapseItem 折叠面板子组件 |
|
* @description 折叠面板子组件 |
|
* @property {String} title 标题文字 |
|
* @property {String} thumb 标题左侧缩略图 |
|
* @property {String} name 唯一标志符 |
|
* @property {Boolean} open = [true|false] 是否展开组件 |
|
* @property {Boolean} titleBorder = [true|false] 是否显示标题分隔线 |
|
* @property {Boolean} border = [true|false] 是否显示分隔线 |
|
* @property {Boolean} disabled = [true|false] 是否展开面板 |
|
* @property {Boolean} showAnimation = [true|false] 开启动画 |
|
* @property {Boolean} showArrow = [true|false] 是否显示右侧箭头 |
|
*/ |
|
export default { |
|
name: 'uniCollapseItem', |
|
props: { |
|
// 列表标题 |
|
title: { |
|
type: String, |
|
default: '' |
|
}, |
|
name: { |
|
type: [Number, String], |
|
default: '' |
|
}, |
|
// 是否禁用 |
|
disabled: { |
|
type: Boolean, |
|
default: false |
|
}, |
|
// #ifdef APP-PLUS |
|
// 是否显示动画,app 端默认不开启动画,卡顿严重 |
|
showAnimation: { |
|
type: Boolean, |
|
default: false |
|
}, |
|
// #endif |
|
// #ifndef APP-PLUS |
|
// 是否显示动画 |
|
showAnimation: { |
|
type: Boolean, |
|
default: true |
|
}, |
|
// #endif |
|
// 是否展开 |
|
open: { |
|
type: Boolean, |
|
default: false |
|
}, |
|
// 缩略图 |
|
thumb: { |
|
type: String, |
|
default: '' |
|
}, |
|
// 标题分隔线显示类型 |
|
titleBorder: { |
|
type: String, |
|
default: 'auto' |
|
}, |
|
border: { |
|
type: Boolean, |
|
default: true |
|
}, |
|
showArrow: { |
|
type: Boolean, |
|
default: true |
|
} |
|
}, |
|
data() { |
|
// TODO 随机生生元素ID,解决百度小程序获取同一个元素位置信息的bug |
|
const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}` |
|
return { |
|
isOpen: false, |
|
isheight: null, |
|
height: 0, |
|
elId, |
|
nameSync: 0 |
|
} |
|
}, |
|
watch: { |
|
open(val) { |
|
this.isOpen = val |
|
this.onClick(val, 'init') |
|
} |
|
}, |
|
updated(e) { |
|
this.$nextTick(() => { |
|
this.init(true) |
|
}) |
|
}, |
|
created() { |
|
this.collapse = this.getCollapse() |
|
this.oldHeight = 0 |
|
this.onClick(this.open, 'init') |
|
}, |
|
// #ifndef VUE3 |
|
// TODO vue2 |
|
destroyed() { |
|
if (this.__isUnmounted) return |
|
this.uninstall() |
|
}, |
|
// #endif |
|
// #ifdef VUE3 |
|
// TODO vue3 |
|
unmounted() { |
|
this.__isUnmounted = true |
|
this.uninstall() |
|
}, |
|
// #endif |
|
mounted() { |
|
if (!this.collapse) return |
|
if (this.name !== '') { |
|
this.nameSync = this.name |
|
} else { |
|
this.nameSync = this.collapse.childrens.length + '' |
|
} |
|
if (this.collapse.names.indexOf(this.nameSync) === -1) { |
|
this.collapse.names.push(this.nameSync) |
|
} else { |
|
console.warn(`name 值 ${this.nameSync} 重复`); |
|
} |
|
if (this.collapse.childrens.indexOf(this) === -1) { |
|
this.collapse.childrens.push(this) |
|
} |
|
this.init() |
|
}, |
|
methods: { |
|
init(type) { |
|
// #ifndef APP-NVUE |
|
this.getCollapseHeight(type) |
|
// #endif |
|
// #ifdef APP-NVUE |
|
this.getNvueHwight(type) |
|
// #endif |
|
}, |
|
uninstall() { |
|
if (this.collapse) { |
|
this.collapse.childrens.forEach((item, index) => { |
|
if (item === this) { |
|
this.collapse.childrens.splice(index, 1) |
|
} |
|
}) |
|
this.collapse.names.forEach((item, index) => { |
|
if (item === this.nameSync) { |
|
this.collapse.names.splice(index, 1) |
|
} |
|
}) |
|
} |
|
}, |
|
onClick(isOpen, type) { |
|
if (this.disabled) return |
|
this.isOpen = isOpen |
|
if (this.isOpen && this.collapse) { |
|
this.collapse.setAccordion(this) |
|
} |
|
if (type !== 'init') { |
|
this.collapse.onChange(isOpen, this) |
|
} |
|
}, |
|
getCollapseHeight(type, index = 0) { |
|
const views = uni.createSelectorQuery().in(this) |
|
views |
|
.select(`#${this.elId}`) |
|
.fields({ |
|
size: true |
|
}, data => { |
|
// TODO 百度中可能获取不到节点信息 ,需要循环获取 |
|
if (index >= 10) return |
|
if (!data) { |
|
index++ |
|
this.getCollapseHeight(false, index) |
|
return |
|
} |
|
// #ifdef APP-NVUE |
|
this.height = data.height + 1 |
|
// #endif |
|
// #ifndef APP-NVUE |
|
this.height = data.height |
|
// #endif |
|
this.isheight = true |
|
if (type) return |
|
this.onClick(this.isOpen, 'init') |
|
}) |
|
.exec() |
|
}, |
|
getNvueHwight(type) { |
|
const result = dom.getComponentRect(this.$refs['collapse--hook'], option => { |
|
if (option && option.result && option.size) { |
|
// #ifdef APP-NVUE |
|
this.height = option.size.height + 1 |
|
// #endif |
|
// #ifndef APP-NVUE |
|
this.height = option.size.height |
|
// #endif |
|
this.isheight = true |
|
if (type) return |
|
this.onClick(this.open, 'init') |
|
} |
|
}) |
|
}, |
|
/** |
|
* 获取父元素实例 |
|
*/ |
|
getCollapse(name = 'uniCollapse') { |
|
let parent = this.$parent; |
|
let parentName = parent.$options.name; |
|
while (parentName !== name) { |
|
parent = parent.$parent; |
|
if (!parent) return false; |
|
parentName = parent.$options.name; |
|
} |
|
return parent; |
|
} |
|
} |
|
} |
|
</script> |
|
|
|
<style lang="scss"> |
|
.uni-collapse-item { |
|
/* #ifndef APP-NVUE */ |
|
box-sizing: border-box; |
|
|
|
/* #endif */ |
|
&__title { |
|
/* #ifndef APP-NVUE */ |
|
display: flex; |
|
width: 100%; |
|
box-sizing: border-box; |
|
/* #endif */ |
|
flex-direction: row; |
|
align-items: center; |
|
transition: border-bottom-color .3s; |
|
|
|
// transition-property: border-bottom-color; |
|
// transition-duration: 5s; |
|
&-wrap { |
|
width: 100%; |
|
flex: 1; |
|
|
|
} |
|
|
|
&-box { |
|
padding: 0 15px; |
|
/* #ifndef APP-NVUE */ |
|
display: flex; |
|
width: 100%; |
|
box-sizing: border-box; |
|
/* #endif */ |
|
flex-direction: row; |
|
justify-content: space-between; |
|
align-items: center; |
|
height: 48px; |
|
line-height: 48px; |
|
background-color: #fff; |
|
color: #303133; |
|
font-size: 13px; |
|
font-weight: 500; |
|
/* #ifdef H5 */ |
|
cursor: pointer; |
|
outline: none; |
|
|
|
/* #endif */ |
|
&.is-disabled { |
|
.uni-collapse-item__title-text { |
|
color: #999; |
|
} |
|
} |
|
|
|
} |
|
|
|
&.uni-collapse-item-border { |
|
border-bottom: 1px solid #ebeef5; |
|
} |
|
|
|
&.is-open { |
|
border-bottom-color: transparent; |
|
} |
|
|
|
&-img { |
|
height: 22px; |
|
width: 22px; |
|
margin-right: 10px; |
|
} |
|
|
|
&-text { |
|
flex: 1; |
|
font-size: 14px; |
|
/* #ifndef APP-NVUE */ |
|
white-space: nowrap; |
|
color: inherit; |
|
/* #endif */ |
|
/* #ifdef APP-NVUE */ |
|
lines: 1; |
|
/* #endif */ |
|
overflow: hidden; |
|
text-overflow: ellipsis; |
|
} |
|
|
|
&-arrow { |
|
/* #ifndef APP-NVUE */ |
|
display: flex; |
|
box-sizing: border-box; |
|
/* #endif */ |
|
align-items: center; |
|
justify-content: center; |
|
width: 20px; |
|
height: 20px; |
|
margin-right: 10px; |
|
transform: rotate(0deg); |
|
|
|
&-active { |
|
transform: rotate(-180deg); |
|
} |
|
} |
|
|
|
|
|
} |
|
|
|
&__wrap { |
|
/* #ifndef APP-NVUE */ |
|
will-change: height; |
|
box-sizing: border-box; |
|
/* #endif */ |
|
background-color: #fff; |
|
overflow: hidden; |
|
position: relative; |
|
height: 0; |
|
|
|
&.is--transition { |
|
// transition: all 0.3s; |
|
transition-property: height, border-bottom-width; |
|
transition-duration: 0.3s; |
|
/* #ifndef APP-NVUE */ |
|
will-change: height; |
|
/* #endif */ |
|
} |
|
|
|
|
|
|
|
&-content { |
|
position: absolute; |
|
font-size: 13px; |
|
color: #303133; |
|
// transition: height 0.3s; |
|
border-bottom-color: transparent; |
|
border-bottom-style: solid; |
|
border-bottom-width: 0; |
|
|
|
&.uni-collapse-item--border { |
|
border-bottom-width: 1px; |
|
border-bottom-color: red; |
|
border-bottom-color: #ebeef5; |
|
} |
|
|
|
&.open { |
|
position: relative; |
|
} |
|
} |
|
} |
|
|
|
&--animation { |
|
transition-property: transform; |
|
transition-duration: 0.3s; |
|
transition-timing-function: ease; |
|
} |
|
|
|
} |
|
</style>
|
|
|