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