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>
							 |