| <template> | 
|     <view class="u-collapse-item"> | 
|         <u-cell | 
|             :title="title" | 
|             :value="value" | 
|             :label="label" | 
|             :icon="icon" | 
|             :isLink="isLink" | 
|             :clickable="clickable" | 
|             :border="parentData.border && showBorder" | 
|             @click="clickHandler" | 
|             :arrowDirection="expanded ? 'up' : 'down'" | 
|             :disabled="disabled" | 
|         > | 
|             <!-- #ifndef MP-WEIXIN --> | 
|             <!-- 微信小程序不支持,因为微信中不支持 <slot name="title" slot="title" />的写法 --> | 
|             <template slot="title"> | 
|                 <slot name="title"></slot> | 
|             </template> | 
|             <template slot="icon"> | 
|                 <slot name="icon"></slot> | 
|             </template> | 
|             <template slot="value"> | 
|                 <slot name="value"></slot> | 
|             </template> | 
|             <template slot="right-icon"> | 
|                 <slot name="right-icon"></slot> | 
|             </template> | 
|             <!-- #endif --> | 
|         </u-cell> | 
|         <view | 
|             class="u-collapse-item__content" | 
|             :animation="animationData" | 
|             ref="animation" | 
|         > | 
|             <view | 
|                 class="u-collapse-item__content__text content-class" | 
|                 :id="elId" | 
|                 :ref="elId" | 
|             ><slot /></view> | 
|         </view> | 
|         <u-line v-if="parentData.border"></u-line> | 
|     </view> | 
| </template> | 
|   | 
| <script> | 
|     import props from './props.js'; | 
|     // #ifdef APP-NVUE | 
|     const animation = uni.requireNativePlugin('animation') | 
|     const dom = uni.requireNativePlugin('dom') | 
|     // #endif | 
|     /** | 
|      * collapseItem 折叠面板Item | 
|      * @description 通过折叠面板收纳内容区域(搭配u-collapse使用) | 
|      * @tutorial https://www.uviewui.com/components/collapse.html | 
|      * @property {String}            title         标题 | 
|      * @property {String}            value         标题右侧内容 | 
|      * @property {String}            label         标题下方的描述信息 | 
|      * @property {Boolean}            disbled     是否禁用折叠面板 ( 默认 false ) | 
|      * @property {Boolean}            isLink         是否展示右侧箭头并开启点击反馈 ( 默认 true ) | 
|      * @property {Boolean}            clickable    是否开启点击反馈 ( 默认 true ) | 
|      * @property {Boolean}            border        是否显示内边框 ( 默认 true ) | 
|      * @property {String}            align        标题的对齐方式 ( 默认 'left' ) | 
|      * @property {String | Number}    name        唯一标识符 | 
|      * @property {String}            icon        标题左侧图片,可为绝对路径的图片或内置图标 | 
|      * @event {Function}            change             某个item被打开或者收起时触发 | 
|      * @example <u-collapse-item :title="item.head" v-for="(item, index) in itemList" :key="index">{{item.body}}</u-collapse-item> | 
|      */ | 
|     export default { | 
|         name: "u-collapse-item", | 
|         mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
|         data() { | 
|             return { | 
|                 elId: uni.$u.guid(), | 
|                 // uni.createAnimation的导出数据 | 
|                 animationData: {}, | 
|                 // 是否展开状态 | 
|                 expanded: false, | 
|                 // 根据expanded确定是否显示border,为了控制展开时,cell的下划线更好的显示效果,进行一定时间的延时 | 
|                 showBorder: false, | 
|                 // 是否动画中,如果是则不允许继续触发点击 | 
|                 animating: false, | 
|                 // 父组件u-collapse的参数 | 
|                 parentData: { | 
|                     accordion: false, | 
|                     border: false | 
|                 } | 
|             }; | 
|         }, | 
|         watch: { | 
|             expanded(n) { | 
|                 clearTimeout(this.timer) | 
|                 this.timer = null | 
|                 // 这里根据expanded的值来进行一定的延时,是为了cell的下划线更好的显示效果 | 
|                 this.timer = setTimeout(() => { | 
|                     this.showBorder = n | 
|                 }, n ? 10 : 290) | 
|             } | 
|         }, | 
|         mounted() { | 
|             this.init() | 
|         }, | 
|         methods: { | 
|             // 异步获取内容,或者动态修改了内容时,需要重新初始化 | 
|             init() { | 
|                 // 初始化数据 | 
|                 this.updateParentData() | 
|                 if (!this.parent) { | 
|                     return uni.$u.error('u-collapse-item必须要搭配u-collapse组件使用') | 
|                 } | 
|                 const { | 
|                     value, | 
|                     accordion, | 
|                     children = [] | 
|                 } = this.parent | 
|   | 
|                 if (accordion) { | 
|                     if (uni.$u.test.array(value)) { | 
|                         return uni.$u.error('手风琴模式下,u-collapse组件的value参数不能为数组') | 
|                     } | 
|                     this.expanded = this.name == value | 
|                 } else { | 
|                     if (!uni.$u.test.array(value) && value !== null) { | 
|                         return uni.$u.error('非手风琴模式下,u-collapse组件的value参数必须为数组') | 
|                     } | 
|                     this.expanded = (value || []).some(item => item == this.name) | 
|                 } | 
|                 // 设置组件的展开或收起状态 | 
|                 this.$nextTick(function() { | 
|                     this.setContentAnimate() | 
|                 }) | 
|             }, | 
|             updateParentData() { | 
|                 // 此方法在mixin中 | 
|                 this.getParentData('u-collapse') | 
|             }, | 
|             async setContentAnimate() { | 
|                 // 每次面板打开或者收起时,都查询元素尺寸 | 
|                 // 好处是,父组件从服务端获取内容后,变更折叠面板后可以获得最新的高度 | 
|                 const rect = await this.queryRect() | 
|                 const height = this.expanded ? rect.height : 0 | 
|                 this.animating = true | 
|                 // #ifdef APP-NVUE | 
|                 const ref = this.$refs['animation'].ref | 
|                 animation.transition(ref, { | 
|                     styles: { | 
|                         height: height + 'px' | 
|                     }, | 
|                     duration: this.duration, | 
|                     // 必须设置为true,否则会到面板收起或展开时,页面其他元素不会随之调整它们的布局 | 
|                     needLayout: true, | 
|                     timingFunction: 'ease-in-out', | 
|                 }, () => { | 
|                     this.animating = false | 
|                 }) | 
|                 // #endif | 
|   | 
|                 // #ifndef APP-NVUE | 
|                 const animation = uni.createAnimation({ | 
|                     timingFunction: 'ease-in-out', | 
|                 }); | 
|                 animation | 
|                     .height(height) | 
|                     .step({ | 
|                         duration: this.duration, | 
|                     }) | 
|                     .step() | 
|                 // 导出动画数据给面板的animationData值 | 
|                 this.animationData = animation.export() | 
|                 // 标识动画结束 | 
|                 uni.$u.sleep(this.duration).then(() => { | 
|                     this.animating = false | 
|                 }) | 
|                 // #endif | 
|             }, | 
|             // 点击collapsehead头部 | 
|             clickHandler() { | 
|                 if (this.disabled && this.animating) return | 
|                 // 设置本组件为相反的状态 | 
|                 this.parent && this.parent.onChange(this) | 
|             }, | 
|             // 查询内容高度 | 
|             queryRect() { | 
|                 // #ifndef APP-NVUE | 
|                 // $uGetRect为uView自带的节点查询简化方法,详见文档介绍:https://www.uviewui.com/js/getRect.html | 
|                 // 组件内部一般用this.$uGetRect,对外的为uni.$u.getRect,二者功能一致,名称不同 | 
|                 return new Promise(resolve => { | 
|                     this.$uGetRect(`#${this.elId}`).then(size => { | 
|                         resolve(size) | 
|                     }) | 
|                 }) | 
|                 // #endif | 
|   | 
|                 // #ifdef APP-NVUE | 
|                 // nvue下,使用dom模块查询元素高度 | 
|                 // 返回一个promise,让调用此方法的主体能使用then回调 | 
|                 return new Promise(resolve => { | 
|                     dom.getComponentRect(this.$refs[this.elId], res => { | 
|                         resolve(res.size) | 
|                     }) | 
|                 }) | 
|                 // #endif | 
|             } | 
|         }, | 
|     }; | 
| </script> | 
|   | 
| <style lang="scss" scoped> | 
|     @import "../../libs/css/components.scss"; | 
|   | 
|     .u-collapse-item { | 
|   | 
|         &__content { | 
|             overflow: hidden; | 
|             height: 0; | 
|   | 
|             &__text { | 
|                 padding: 12px 15px; | 
|                 color: $u-content-color; | 
|                 font-size: 14px; | 
|                 line-height: 18px; | 
|             } | 
|         } | 
|     } | 
| </style> |