Vue封装Tabbar组件路由跳转
外下羊. 人气:2Vue封装Tabbar组件
话不多说直接上代码
在App.vue 封装 路由跳转 利用router-view的特性
<template> <div id="app"> <router-view /> //引入子组件 把items 这个数组传进去 <Tabr :items="items" /> </div> </template>
<script> import Tabr from "./components/Tabr"; export default { components: { Tabr, }, data() { return { items: [ { title: "首页", path: "/", img: require("./assets/img/shouye.png"), imgs: require("./assets/img/shouye_1.png"), }, { title: "分类", path: "/About", img: require("./assets/img/fenlei.png"), imgs: require("./assets/img/fenlei_1.png"), }, { title: "购物车", path: "/Cart", img: require("./assets/img/gouwuchezhengpin.png"), imgs: require("./assets/img/gouwuchezhengpin_1.png"), }, { title: "我的", path: "/Mime", img: require("./assets/img/wode.png"), imgs: require("./assets/img/wode_1.png"), }, ], }; }, }; </script>
子组件Tabbar
<template> <div class="Yanxuan_tab"> <div v-for="(item,index) in items" :key="index" @click="Onclick(index)"> <div> <img :src="index===Tabindex?item.imgs:item.img" alt /> //动态绑定 </div> <div :class="index===Tabindex?'title':'Yanxuan_title'"> // {{item.title}}</div> </div> </div> </template>
<script> export default { props: { items: { type: Array, required: true, validator: function (value) { return value.length <= 6; //市面常见的Tabbar的栏 不能超过6个 }, } }, data() { return { item:this.items, Tabindex:0 } }, methods:{ Onclick(index){ //这里是根据下标切换 图片样式跟字体颜色 动态绑定 this.Tabindex = index var temp = this.item[index] this.$router.push(temp.path) } } }; </script>
<style scoped> .Yanxuan_tab { width: 100%; height: 64px; border: 1px solid gainsboro; position: fixed; bottom: 0px; left: 0px; display: inline-flex; justify-content: space-around; align-items: center; text-align: center; } .Yanxuan_title{ font-size: 14px; } .title{ font-size: 14px; color:red } </style>
然后就是配置的路由
import Vue from 'vue' import VueRouter from 'vue-router' import Home from '../views/Home.vue' Vue.use(VueRouter) const routes = [ { path: '/', name: 'Home', component: Home, meta:{ isShowTabbar:true } }, { path: '/about', name: 'About', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'), meta:{ isShowTabbar:true } } , { path: '/Cart', name: 'Cart', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/Cart.vue'), meta:{ isShowTabbar:false } }, { path: '/Mime', name: 'Mime', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/Mime.vue'), meta:{ isShowTabbar:true } }, ] const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }) export default router
最后的效果完成图
代码就直接可以用了
从零开始封装一个Tabbar
首先底部菜单栏最外层是一个div,
在div中整体上存在四个或五个小div,每个div中包含icon和text,如下图
对于每一个icon对象,它包含图标以及文字,但十实际中我们肯定不会将img和text写死,以及处于active状态时text的颜色也不会写死,以方便调用者传入想要的参数,这样才算一个彻底的封装。
代码如下
<template> <div class="tab-bar-item" @click="itemClick"> <div v-if="!isActive"> <slot name="item-icon"></slot> </div> <div v-else> <slot name="item-icon-active"></slot> </div> <div :style="activeStyle"> <slot name="item-text"></slot> </div> </div> </template> <!-- 上方代码设置三个插槽,为什么不是两个呢,因为还要包含当item处于活跃状态时要显示的image,所以是三个,使用v-if控制当非活跃时显示默认icon插槽,活跃时显示亮色icon插槽。因为插槽是要被传入其中的内容覆盖的,所以传入的内容可能会将我们slot中的一些属性覆盖掉,所以常常我们需要将slot包裹在div中,这样就可以避免这个问题。 icon下方文同理也放在div中,style绑定一个计算属性,看下方代码可以这个计算属性当item处于活跃时会返回颜色属性,当然这个属性也是可以在调用tab-bar时传入的,默认为红色。 -->
<script> export default { name:'TabBarItem', props:{ path: String, // 当前item对应的路由,由调用者指定 activeColor:{ // 当前item的文字在活跃时的颜色,默认红色,可由使用者指定 type:String, default:"red" } }, data() { return { // isActive:false, } }, computed:{ // 判断当前item是否处于活跃状态 isActive(){ return this.$route.path.indexOf(this.path)!==-1; }, // 计算属性,如果处于活跃状态则设置style,否则去除style activeStyle(){ return this.isActive? {color:this.activeColor}:{}; } }, methods:{ itemClick(){ if(this.$route.path!==this.path){ this.$router.push(this.path); // this.isActive = true; } } } } </script>
<style scoped> <!--一些默认样式--> .tab-bar-item { flex: 1; text-align: center; height: 49px; font-size: 10px; } .tab-bar-item img { margin-top: 4px; width: 22px; height: 22px; vertical-align: middle; margin-bottom: 2px; } </style>
封装完每一个tabbaritem后
接下来是整体的tabbar,试想,我们肯定还是放入一个插槽代码如下:
<template> <div id="tab-bar"> <slot></slot> </div> </template>
<script> export default { name: "TabBar" }; </script>
<style scoped> #tab-bar { display: flex; background-color: #f6f6f6; position: fixed; left: 0; right: 0; bottom: 0; box-shadow: 0px -2px 1px rgba(100, 100, 100, 0.1); } </style>
tabbar预留的插槽则用于放入每一个item,我们在这里也是不能写死的,因为控件开发者并不知需要放入多少个item。
使用者在使用我们封装的控件时
则可以如下代码,放入内容:
<template> <tab-bar> <tab-bar-item path="/home" activeColor="deepPink"> <img slot="item-icon" src="~assets/img/tabbar/home.svg" alt=""> <img slot="item-icon-active" src="~assets/img/tabbar/home_active.svg" alt=""> <div slot="item-text">首页</div> </tab-bar-item> <tab-bar-item path="/category" activeColor="deepPink"> <img slot="item-icon" src="~assets/img/tabbar/category.svg" alt=""> <img slot="item-icon-active" src="~assets/img/tabbar/category_active.svg" alt=""> <div slot="item-text">分类</div> </tab-bar-item> <tab-bar-item path="/cart" activeColor="deepPink"> <img slot="item-icon" src="~assets/img/tabbar/cart.svg" alt=""> <img slot="item-icon-active" src="~assets/img/tabbar/cart_active.svg" alt=""> <div slot="item-text">购物车</div> </tab-bar-item> <tab-bar-item path="/profile" activeColor="deepPink"> <img slot="item-icon" src="~assets/img/tabbar/profile.svg" alt=""> <img slot="item-icon-active" src="~assets/img/tabbar/profile_active.svg" alt=""> <div slot="item-text">我的</div> </tab-bar-item> </tab-bar> </template>
<script> import TabBar from "components/tabbar/TabBar"; import TabBarItem from "components/tabbar/TabBarItem"; export default { name:'MainTabBar', components:{ TabBar, TabBarItem } } </script>
<style scoped> </style>
到此结束。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
加载全部内容