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