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