Fab 悬浮按钮

声明,参考:https://ext.dcloud.net.cn/plugin?id=144

  • 在 template 中使用

<template>
	<view>
		<uni-fab
			:pattern="pattern"
			:content="content"
			:horizontal="horizontal"
			:vertical="vertical"
			:direction="direction"
			@trigger="trigger"
		></uni-fab>
	</view>
</template>

  • 在 javascript 中使用
<script>
	import uniFab from '@/components/uni-fab/uni-fab.vue';
	
	export default {
		data() {
			return {
				horizontal: 'left',
				vertical: 'top',
				direction: 'horizontal',
				pattern: {
					color: '#7A7E83',
					backgroundColor: '#fff',
					selectedColor: '#FF0000',
					buttonColor:"#007AFF",
				},
				content: [
					{
						iconPath: '/static/img/tabbar/guanzhu.png',
						selectedIconPath: '/static/img/tabbar/guanzhuactive.png',
						text: '组件',
						active: false
					},
					{
						iconPath: '/static/img/tabbar/home.png',
						selectedIconPath: '/static/img/tabbar/homeactive.png',
						text: 'API',
						active: false
					},
					{
						iconPath: '/static/img/tabbar/me.png',
						selectedIconPath: '/static/img/tabbar/meactive.png',
						text: '模版',
						active: false
					}
				]
			}
		},
	
		methods: {
			
			 trigger(e) {
				let other = this.content.map((d, i) => {
				   d.active = i== e.index
				})
				
				uni.showToast({
					title:'选择了'+this.content[e.index].text
				})
			}
		},
		
		components: {
			uniFab
		}
	}
</script>


  • 最后附上uni-fab.vue

<template>
	<view>
		<view
			class="fab-box fab" 
			:class="{
				leftBottom: leftBottom,
				rightBottom: rightBottom,
				leftTop: leftTop,
				rightTop: rightTop
			}"
		>
			<view
				class="fab-circle"
				: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 }"
				@click="open"
			>
				<text class="icon icon-jia" :class="{ active: showContent }"></text>
			</view>
			<view
				class="fab-content"
				:class="{
					left: horizontal === 'left',
					right: horizontal === 'right',
					flexDirection: direction === 'vertical',
					flexDirectionStart: flexDirectionStart,
					flexDirectionEnd: flexDirectionEnd
				}"
				:style="{ width: boxWidth, height: boxHeight, background: styles.backgroundColor }"
			>
				<view v-if="flexDirectionStart || horizontalLeft" class="fab-item first"></view>
				<view
					class="fab-item"
					v-for="(item, index) in content"
					:key="index"
					:class="{ active: showContent }"
					:style="{
						color: item.active ? styles.selectedColor : styles.color
					}"
					@click="taps(index, item)"
				>
					<image
						class="content-image"
						:src="item.active ? item.selectedIconPath : item.iconPath"
						mode=""
					></image>
					<text class="text">{{ item.text }}</text>
				</view>
				<view v-if="flexDirectionEnd || horizontalRight" class="fab-item first"></view>
			</view>
		</view>
	</view>
</template>

<script>
export default {
	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 [];
			}
		}
	},
	data() {
		return {
			fabShow: false,
			flug: true,
			showContent: false,
			styles: {
				color: '#3c3e49',
				selectedColor: '#007AFF',
				backgroundColor: '#fff',
				buttonColor: '#3c3e49'
			}
		};
	},
	created() {
		if (this.top === 0) {
			this.fabShow = true;
		}
		// 初始化样式
		this.styles = Object.assign({}, this.styles, this.pattern);
	},
	methods: {
		open() {
			this.showContent = !this.showContent;
		},
		/**
		 * 按钮点击事件
		 */
		taps(index, item) {
			this.$emit('trigger', {
				index,
				item
			});
			
			this.showContent = false;
		},
		/**
		 * 获取 位置信息
		 */
		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.showContent && this.direction === paramA
					? this.contentWidth
					: this.contentWidthMin;
			}
		}
	},
	watch: {
		pattern(newValue, oldValue) {
			console.log(JSON.stringify(newValue));
			this.styles = Object.assign({}, this.styles, newValue);
		}
	},
	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');
		}
	}
};
</script>

<style scoped>
.fab-box {
	position: fixed;
	display: flex;
	justify-content: center;
	align-items: center;
	z-index: 2;
}

.fab-box.top {
	width: 60upx;
	height: 60upx;
	right: 30upx;
	bottom: 60upx;
	border: 1px #5989b9 solid;
	background: #6699cc;
	border-radius: 10upx;
	color: #fff;
	transition: all 0.3;
	opacity: 0;
}

.fab-box.active {
	opacity: 1;
}

.fab-box.fab {
	z-index: 10;
}

.fab-box.fab.leftBottom {
	left: 30upx;
	bottom: 60upx;
}

.fab-box.fab.leftTop {
	left: 30upx;
	top: 80upx;
	/* #ifdef H5 */
	top: calc(80upx + var(--window-top));
	/* #endif */
}

.fab-box.fab.rightBottom {
	right: 30upx;
	bottom: 60upx;
}

.fab-box.fab.rightTop {
	right: 30upx;
	top: 80upx;
	/* #ifdef H5 */
	top: calc(80upx + var(--window-top));
	/* #endif */
}

.fab-circle {
	display: flex;
	justify-content: center;
	align-items: center;
	position: absolute;
	width: 110upx;
	height: 110upx;
	background: #3c3e49;
	/* background: #5989b9; */
	border-radius: 50%;
	box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.2);
	z-index: 11;
}

.fab-circle.left {
	left: 0;
}

.fab-circle.right {
	right: 0;
}

.fab-circle.top {
	top: 0;
}

.fab-circle.bottom {
	bottom: 0;
}

.fab-circle .icon-jia {
	color: #ffffff;
	font-size: 50upx;
	transition: all 0.3s;
}

.fab-circle .icon-jia.active {
	transform: rotate(135deg);
}

.fab-content {
	background: #6699cc;
	box-sizing: border-box;
	display: flex;
	border-radius: 100upx;
	overflow: hidden;
	box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1);
	transition: all 0.2s;
	width: 110upx;
}

.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: 110upx;
	height: 110upx;
	font-size: 24upx;
	color: #fff;
	opacity: 0;
	transition: opacity 0.2s;
}

.fab-content .fab-item.active {
	opacity: 1;
}

.fab-content .fab-item .content-image {
	width: 50upx;
	height: 50upx;
	margin-bottom: 5upx;
}

.fab-content .fab-item.first {
	width: 110upx;
}

@font-face {
	font-family: 'iconfont';
	src: url('https://at.alicdn.com/t/font_1028200_xhbo4rn58rp.ttf?t=1548214263520')
		format('truetype');
}

.icon {
	font-family: 'iconfont' !important;
	font-size: 16px;
	font-style: normal;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

.icon-jia:before {
	content: '\e630';
}

.icon-arrow-up:before {
	content: '\e603';
}
</style>


posted @ 2019-09-04 15:20  浪里小白龙呼呼呼  阅读(2030)  评论(0编辑  收藏  举报