flex 底部固定_开发vue底部导航栏组件

本文介绍了如何使用CSS3的flex布局在Vue中开发一个底部导航栏组件,通过设置display:flex和flex:1实现自适应固定在底部的效果。同时解决了路由嵌套问题,并给出了html布局、样式配置、router.js配置以及组件引用和最终效果展示。
摘要由CSDN通过智能技术生成

这个想法源于最近自己在开发一个移动端博客的一个底部导航栏,原型设计如下:

b6b24bdbb56df1df91b9482caaef7f4c.png

我们来分析一下这个导航栏,其实很简单啦,就是自适应固定在底部 我们可以使用CSS3属性display:flex设置父级盒子为伸缩盒子模型,子元素设置flex:1自适应大小。
html布局如下

<template>
	<div class="footer">
		<div v-for='(item,index) of items' :key="index" :class='[item.cls,{on:index === idx}]' @click="change(item,index)">
			<img :src="index===idx?item.srcSelect:item.src" v-if="showIconOrSrc">
			<i :class="index===idx?item.iconSelect:item.icon" v-if="!showIconOrSrc"></i>
			<span :class="['colorChange',{on:index===idx}]" >{{item.name}}</span>
		</div>
	</div>

</template>


样式如下:

<style  scoped>
.footer{
	display: flex;
	position: fixed;
	left: 0;
	bottom: 0;
	box-sizing: border-box;
	background: rgb(248, 248, 248);
	width: 100%;
}
div{
	flex: 1;
	padding: 5px;
}
div img{
	width: 30px;
	height: 30px;
}
div span{
	display: block;
	color:black;
	color: rgb(168, 168, 168);
}
.on{
	color: rgb(25, 137, 250);
}
</style>


此间碰到一个路由嵌套问题

040d334d4b37f35dc69ee6d7f0ba82c1.png

router.js配置

fad4b4e9a14332833928aaa40618fadf.png

这个组件可以设置是iconfont图标样式,也可以使用图片 js逻辑如下:

<script type="text/javascript">
// eslint-disable-next-line	
/* eslint-disable */
	export default{
		props:{
			idx: {
				type: Number,
				default: 0,
			},
			showIconOrSrc:{
				// true表示显示图片途径 src
				// false 表示icon图标类名
				type: Boolean,
				default: true,
			},
			items: {
				type: Array,
				default: function(){
					return ([{
						cls:"home",
						name:"首页",
						push:"/home",
						icon: 'iconfont icon-shouye',
						iconSelect: 'iconfont icon-shouye',
						src:"http://118.190.209.124/img/home_normal.png",
						srcSelect:"http://118.190.209.124/img/home_selected.png"
					},
					{
						cls:"shares",
						name:"归档",
						push:"/shares",
						icon: "iconfont icon-guidang",
						iconSelect: 'iconfont icon-guidang',
						src:"http://118.190.209.124/img/guidang_normal.png",
						srcSelect:"http://118.190.209.124/img/guidang_selected.png"
					},
					{
						cla:"community",
						name:"博主",
						push:"/community",
						icon: "iconfont icon-bozhuguanli",
						iconSelect: 'iconfont icon-bozhuguanli',
						src:"http://118.190.209.124/img/user_normal.png",
						srcSelect:"http://118.190.209.124/img/user_selected.png"
					},
					{
						cla:"mine",
						name:"链接",
						push:"/mine",
						icon: "iconfont icon-lianjie2",
						iconSelect: 'iconfont icon-lianjie2',
						src:"http://118.190.209.124/img/lianjie_normal.png",
						srcSelect:"http://118.190.209.124/img/lianjie_selected.png"
					}]);
				}
			}
		},
		data(){
			return {
			}
		},
		methods: {
			change(item,index) {
				this.$router.push(item.push);
				this.$emit("change",index)
			}
		}
	} 
 
</script>


接下来就是引用:

<template>
	<div class="box">
		<router-view></router-view>
		<v-navbar :items="items" :showIconOrSrc="showIconOrSrc" :idx="idx" @change="change"></v-navbar>
	</div>
</template>

<script>
import NavBar from "@/navbar/navbar"
export default {
	name: 'navbar',
	data() {
		return {
			idx:0,
			showIconOrSrc: false,
			items: [{
						cls:"home",
						name:"首页",
						push:"/home",
						icon: 'iconfont icon-shouye',
						iconSelect: 'iconfont icon-shouye',
						src:"http://118.190.209.124/img/home_normal.png",
						srcSelect:"http://118.190.209.124/img/home_selected.png"
					},
					{
						cls:"shares",
						name:"归档",
						push:"/shares",
						icon: "iconfont icon-guidang",
						iconSelect: 'iconfont icon-guidang',
						src:"http://118.190.209.124/img/guidang_normal.png",
						srcSelect:"http://118.190.209.124/img/guidang_selected.png"
					},
					{
						cla:"community",
						name:"博主",
						push:"/community",
						icon: "iconfont icon-bozhuguanli",
						iconSelect: 'iconfont icon-bozhuguanli',
						src:"http://118.190.209.124/img/user_normal.png",
						srcSelect:"http://118.190.209.124/img/user_selected.png"
					},
					{
						cla:"mine",
						name:"链接",
						push:"/mine",
						icon: "iconfont icon-lianjie2",
						iconSelect: 'iconfont icon-lianjie2',
						src:"http://118.190.209.124/img/lianjie_normal.png",
						srcSelect:"http://118.190.209.124/img/lianjie_selected.png"
					}],
		
		}
	},
	components: {
		"v-navbar": NavBar,
	},
	methods: {
		change(index){
			this.idx = index
		}
	}
}
</script>

<style scoped>
.box{
	width: 100%;
	height: 100%;
}
</style>


最终效果就是入下图:

32111c97aa5cac2266fe8f66187299cc.gif


作者:Ken_Coding
链接:https://juejin.im/post/5c4f0e28f265da61616f0e51
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3中可以通过自定义组件实现底部导航栏的灵活组件。以下是一个简单的实现示例: 1. 创建一个TabBar组件,用于展示底部导航栏: ```vue <template> <div class="tab-bar"> <slot></slot> </div> </template> <script> export default { name: "TabBar", }; </script> <style scoped> .tab-bar { display: flex; justify-content: space-around; align-items: center; position: fixed; bottom: 0; left: 0; right: 0; height: 50px; background-color: #fff; box-shadow: 0 -3px 5px rgba(0, 0, 0, 0.1); } </style> ``` 2. 在TabBar组件中使用slot插槽,用于接收底部导航栏的子组件。例如: ```vue <template> <div class="tab-bar"> <slot></slot> </div> </template> <script> export default { name: "TabBar", }; </script> <style scoped> .tab-bar { display: flex; justify-content: space-around; align-items: center; position: fixed; bottom: 0; left: 0; right: 0; height: 50px; background-color: #fff; box-shadow: 0 -3px 5px rgba(0, 0, 0, 0.1); } </style> ``` 3. 创建底部导航栏组件,例如TabBarItem。在TabBarItem中可以定义图标、文字和点击事件等属性。例如: ```vue <template> <div class="tab-bar-item" :class="{ active: active }" @click="handleClick"> <i :class="icon"></i> <span>{{ title }}</span> </div> </template> <script> export default { name: "TabBarItem", props: { icon: { type: String, required: true, }, title: { type: String, required: true, }, active: { type: Boolean, required: true, }, }, methods: { handleClick() { this.$emit("click"); }, }, }; </script> <style scoped> .tab-bar-item { display: flex; flex-direction: column; align-items: center; font-size: 12px; color: #666; } .tab-bar-item i { font-size: 20px; margin-bottom: 2px; } .tab-bar-item.active { color: #007aff; } </style> ``` 4. 在父组件中使用TabBar和TabBarItem组件。例如: ```vue <template> <div> <router-view /> <TabBar> <TabBarItem v-for="(tab, index) in tabs" :key="index" :icon="tab.icon" :title="tab.title" :active="index === activeIndex" @click="activeIndex = index" /> </TabBar> </div> </template> <script> import TabBar from "@/components/TabBar.vue"; import TabBarItem from "@/components/TabBarItem.vue"; export default { name: "App", components: { TabBar, TabBarItem, }, data() { return { tabs: [ { icon: "icon-home", title: "首页", }, { icon: "icon-category", title: "分类", }, { icon: "icon-cart", title: "购物车", }, { icon: "icon-person", title: "个人中心", }, ], activeIndex: 0, }; }, }; </script> ``` 在父组件中使用TabBar和TabBarItem组件,通过循环遍历tabs数组,动态生成底部导航栏组件TabBarItem,并通过activeIndex属性控制当前激活的子组件。当子组件被点击时,通过click事件向父组件发送消息,触发activeIndex的变化,从而实现底部导航栏的切换。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值