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