| <template> | 
|     <view> | 
|         <view :class="{ | 
|         leftBottom: leftBottom, | 
|         rightBottom: rightBottom, | 
|         leftTop: leftTop, | 
|         rightTop: rightTop | 
|       }" v-if="leftBottom||rightBottom||leftTop||rightTop" class="fab-box fab"> | 
|             <view :class="{ | 
|           left: horizontal === 'left' && direction === 'horizontal', | 
|           top: vertical === 'top' && direction === 'vertical', | 
|           bottom: vertical === 'bottom' && direction === 'vertical', | 
|           right: horizontal === 'right' && direction === 'horizontal' | 
|         }" :style="{ 'background-color': styles.buttonColor }" class="fab-circle" @click="_onClick"> | 
|                 <view class="fab-circle-box" :class="{ active: isShow }"> | 
|                     <view class="fab-circle-v"></view> | 
|                     <view class="fab-circle-h"></view> | 
|                 </view> | 
|             </view> | 
|             <view :class="{ | 
|           left: horizontal === 'left', | 
|           right: horizontal === 'right', | 
|           flexDirection: direction === 'vertical', | 
|           flexDirectionStart: flexDirectionStart, | 
|           flexDirectionEnd: flexDirectionEnd | 
|         }" :style="{ width: boxWidth, height: boxHeight, background: styles.backgroundColor }" class="fab-content"> | 
|                 <view v-if="flexDirectionStart || horizontalLeft" class="fab-item first" /> | 
|                 <view v-for="(item, index) in content" :key="index" :class="{ active: isShow }" :style="{ | 
|             color: item.active ? styles.selectedColor : styles.color | 
|           }" class="fab-item" @click="_onItemClick(index, item)"> | 
|                     <image :src="item.active ? item.selectedIconPath : item.iconPath" class="content-image" mode="widthFix" /> | 
|                     <text class="text">{{ item.text }}</text> | 
|                 </view> | 
|                 <view v-if="flexDirectionEnd || horizontalRight" class="fab-item first" /> | 
|             </view> | 
|         </view> | 
|     </view> | 
| </template> | 
|   | 
| <script> | 
|     export default { | 
|         name: 'UniFab', | 
|         props: { | 
|             pattern: { | 
|                 type: Object, | 
|                 default () { | 
|                     return {} | 
|                 } | 
|             }, | 
|             horizontal: { | 
|                 type: String, | 
|                 default: 'left' | 
|             }, | 
|             vertical: { | 
|                 type: String, | 
|                 default: 'bottom' | 
|             }, | 
|             direction: { | 
|                 type: String, | 
|                 default: 'horizontal' | 
|             }, | 
|             content: { | 
|                 type: Array, | 
|                 default () { | 
|                     return [] | 
|                 } | 
|             }, | 
|             show: { | 
|                 type: Boolean, | 
|                 default: false | 
|             } | 
|         }, | 
|         data() { | 
|             return { | 
|                 fabShow: false, | 
|                 flug: true, | 
|                 isShow: false, | 
|                 styles: { | 
|                     color: '#3c3e49', | 
|                     selectedColor: '#007AFF', | 
|                     backgroundColor: '#fff', | 
|                     buttonColor: '#3c3e49' | 
|                 } | 
|             } | 
|         }, | 
|         computed: { | 
|             contentWidth(e) { | 
|                 return uni.upx2px((this.content.length + 1) * 110 + 20) + 'px' | 
|             }, | 
|             contentWidthMin() { | 
|                 return uni.upx2px(110) + 'px' | 
|             }, | 
|             // 动态计算宽度 | 
|             boxWidth() { | 
|                 return this.getPosition(3, 'horizontal') | 
|             }, | 
|             // 动态计算高度 | 
|             boxHeight() { | 
|                 return this.getPosition(3, 'vertical') | 
|             }, | 
|             // 计算左下位置 | 
|             leftBottom() { | 
|                 return this.getPosition(0, 'left', 'bottom') | 
|             }, | 
|             // 计算右下位置 | 
|             rightBottom() { | 
|                 return this.getPosition(0, 'right', 'bottom') | 
|             }, | 
|             // 计算左上位置 | 
|             leftTop() { | 
|                 return this.getPosition(0, 'left', 'top') | 
|             }, | 
|             rightTop() { | 
|                 return this.getPosition(0, 'right', 'top') | 
|             }, | 
|             flexDirectionStart() { | 
|                 return this.getPosition(1, 'vertical', 'top') | 
|             }, | 
|             flexDirectionEnd() { | 
|                 return this.getPosition(1, 'vertical', 'bottom') | 
|             }, | 
|             horizontalLeft() { | 
|                 return this.getPosition(2, 'horizontal', 'left') | 
|             }, | 
|             horizontalRight() { | 
|                 return this.getPosition(2, 'horizontal', 'right') | 
|             } | 
|         }, | 
|         watch: { | 
|             pattern(newValue, oldValue) { | 
|                 //console.log(JSON.stringify(newValue)) | 
|                 this.styles = Object.assign({}, this.styles, newValue) | 
|             } | 
|         }, | 
|         created() { | 
|             this.isShow = this.show | 
|             if (this.top === 0) { | 
|                 this.fabShow = true | 
|             } | 
|             // 初始化样式 | 
|             this.styles = Object.assign({}, this.styles, this.pattern) | 
|         }, | 
|         methods: { | 
|             _onClick() { | 
|                 this.isShow = !this.isShow | 
|             }, | 
|             open() { | 
|                 this.isShow = true | 
|             }, | 
|             close() { | 
|                 this.isShow = false | 
|             }, | 
|             /** | 
|              * 按钮点击事件 | 
|              */ | 
|             _onItemClick(index, item) { | 
|                 this.$emit('trigger', { | 
|                     index, | 
|                     item | 
|                 }) | 
|             }, | 
|             /** | 
|              * 获取 位置信息 | 
|              */ | 
|             getPosition(types, paramA, paramB) { | 
|                 if (types === 0) { | 
|                     return this.horizontal === paramA && this.vertical === paramB | 
|                 } else if (types === 1) { | 
|                     return this.direction === paramA && this.vertical === paramB | 
|                 } else if (types === 2) { | 
|                     return this.direction === paramA && this.horizontal === paramB | 
|                 } else { | 
|                     return this.isShow && this.direction === paramA ? this.contentWidth : this.contentWidthMin | 
|                 } | 
|             } | 
|         } | 
|     } | 
| </script> | 
|   | 
| <style lang="scss" scoped> | 
|   | 
|     .uni-icon { | 
|         font-family: uniicons; | 
|         font-size: 30px; | 
|         font-weight: normal; | 
|         font-style: normal; | 
|         line-height: 1; | 
|         display: inline-block; | 
|         text-decoration: none; | 
|         -webkit-font-smoothing: antialiased; | 
|     } | 
|   | 
|     .fab-box { | 
|         position: fixed; | 
|         display: flex; | 
|         justify-content: center; | 
|         align-items: center; | 
|         z-index: 2; | 
|     } | 
|   | 
|     .fab-box.top { | 
|         width: 60rpx; | 
|         height: 60rpx; | 
|         right: 30rpx; | 
|         bottom: 60rpx; | 
|         border: 1px #5989b9 solid; | 
|         background: #6699cc; | 
|         border-radius: 10rpx; | 
|         color: #fff; | 
|         transition: all 0.3; | 
|         opacity: 0; | 
|     } | 
|   | 
|     .fab-box.active { | 
|         opacity: 1; | 
|     } | 
|   | 
|     .fab-box.fab { | 
|         z-index: 10; | 
|     } | 
|   | 
|     .fab-box.fab.leftBottom { | 
|         left: 30rpx; | 
|         bottom: 60rpx; | 
|     } | 
|   | 
|     .fab-box.fab.leftTop { | 
|         left: 30rpx; | 
|         top: 80rpx; | 
|         /* #ifdef H5 */ | 
|         top: calc(80rpx + var(--window-top)); | 
|         /* #endif */ | 
|     } | 
|   | 
|     .fab-box.fab.rightBottom { | 
|         right: 30rpx; | 
|         bottom: 60rpx; | 
|     } | 
|   | 
|     .fab-box.fab.rightTop { | 
|         right: 30rpx; | 
|         top: 80rpx; | 
|         /* #ifdef H5 */ | 
|         top: calc(80rpx + var(--window-top)); | 
|         /* #endif */ | 
|     } | 
|   | 
|     .fab-circle { | 
|         display: flex; | 
|         justify-content: center; | 
|         align-items: center; | 
|         position: absolute; | 
|         width: 110rpx; | 
|         height: 110rpx; | 
|         background: #3c3e49; | 
|         /* background: #5989b9; */ | 
|         border-radius: 50%; | 
|         box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.2); | 
|         z-index: 11; | 
|     } | 
|   | 
|     .fab-circle-box { | 
|         position: absolute; | 
|         left: 0; | 
|         top: 0; | 
|         right: 0; | 
|         bottom: 0; | 
|         transition: all 0.3s; | 
|     } | 
|   | 
|     .fab-circle-v { | 
|         position: absolute; | 
|         width: 8rpx; | 
|         height: 60rpx; | 
|         left: 50%; | 
|         top: 50%; | 
|         margin: -30rpx 0 0 -4rpx; | 
|         background-color: white; | 
|     } | 
|   | 
|     .fab-circle-h { | 
|         position: absolute; | 
|         width: 60rpx; | 
|         height: 8rpx; | 
|         left: 50%; | 
|         top: 50%; | 
|         margin: -4rpx 0 0 -30rpx; | 
|         background-color: white; | 
|     } | 
|   | 
|     .fab-circle.left { | 
|         left: 0; | 
|     } | 
|   | 
|     .fab-circle.right { | 
|         right: 0; | 
|     } | 
|   | 
|     .fab-circle.top { | 
|         top: 0; | 
|     } | 
|   | 
|     .fab-circle.bottom { | 
|         bottom: 0; | 
|     } | 
|   | 
|     .fab-circle .uni-icon-plusempty { | 
|         color: #ffffff; | 
|         font-size: 80rpx; | 
|         transition: all 0.3s; | 
|         font-weight: bold; | 
|     } | 
|   | 
|     .fab-circle-box.active { | 
|         transform: rotate(135deg); | 
|         font-size: 80rpx; | 
|     } | 
|   | 
|     .fab-content { | 
|         background: #6699cc; | 
|         box-sizing: border-box; | 
|         display: flex; | 
|         border-radius: 100rpx; | 
|         overflow: hidden; | 
|         box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1); | 
|         transition: all 0.2s; | 
|         width: 110rpx; | 
|     } | 
|   | 
|     .fab-content.left { | 
|         justify-content: flex-start; | 
|     } | 
|   | 
|     .fab-content.right { | 
|         justify-content: flex-end; | 
|     } | 
|   | 
|     .fab-content.flexDirection { | 
|         flex-direction: column; | 
|         justify-content: flex-end; | 
|     } | 
|   | 
|     .fab-content.flexDirectionStart { | 
|         flex-direction: column; | 
|         justify-content: flex-start; | 
|     } | 
|   | 
|     .fab-content.flexDirectionEnd { | 
|         flex-direction: column; | 
|         justify-content: flex-end; | 
|     } | 
|   | 
|     .fab-content .fab-item { | 
|         display: flex; | 
|         flex-direction: column; | 
|         justify-content: center; | 
|         align-items: center; | 
|         width: 110rpx; | 
|         height: 110rpx; | 
|         font-size: 24rpx; | 
|         color: #fff; | 
|         opacity: 0; | 
|         transition: opacity 0.2s; | 
|     } | 
|   | 
|     .fab-content .fab-item.active { | 
|         opacity: 1; | 
|     } | 
|   | 
|     .fab-content .fab-item .content-image { | 
|         width: 50rpx; | 
|         height: 50rpx; | 
|         margin-bottom: 5rpx; | 
|     } | 
|   | 
|     .fab-content .fab-item.first { | 
|         width: 110rpx; | 
|     } | 
| </style> |