Vue封装一个Tabbar组件 带组件路由跳转方式

 更新时间:2022年04月28日 09:21:47   作者:外下羊.  
这篇文章主要介绍了Vue封装一个Tabbar组件 带组件路由跳转方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Vue封装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>

到此结束。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • vue-devtools的安装和使用步骤详解

    vue-devtools的安装和使用步骤详解

    在本篇文章中小编给大家整理的是一篇关于vue-devtools安装使用的相关知识点内容,有需要的朋友们可以学习下。
    2019-10-10
  • vue基本使用--refs获取组件或元素的实例

    vue基本使用--refs获取组件或元素的实例

    今天小编就为大家分享一篇vue基本使用--refs获取组件或元素的实例,具有很好的参考价值,希望对大家有所帮助。一起个跟随小编过来看看吧
    2019-11-11
  • vue中created、watch和computed的执行顺序详解

    vue中created、watch和computed的执行顺序详解

    由于vue的双向数据绑定,自动更新数据的机制,在数据变化后,对此数据依赖 的所有数据,watch事件都会被更新、触发,下面这篇文章主要给大家介绍了关于vue中created、watch和computed的执行顺序,需要的朋友可以参考下
    2022-11-11
  • vue.js 实现评价五角星组件的实例代码

    vue.js 实现评价五角星组件的实例代码

    这篇文章主要介绍了vue.js 实现评价五角星组件的实例代码,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-08-08
  • 使用vue自定义指令开发表单验证插件validate.js

    使用vue自定义指令开发表单验证插件validate.js

    今天就来介绍一下如何利用vue的自定义指令directive来开发一个表单验证插件的过程,需要的朋友可以参考下
    2019-05-05
  • vue3 vite配置跨域及不生效问题解决

    vue3 vite配置跨域及不生效问题解决

    这篇文章主要介绍了vue3 vite配置跨域以及不生效问题,本文给大家分享完美解决方案,需要的朋友可以参考下
    2023-07-07
  • vue实现登录功能

    vue实现登录功能

    这篇文章主要介绍了vue实现登录功能的步骤,帮助大家更好的理解和使用vue框架,感兴趣的朋友可以了解下
    2020-12-12
  • vue中table表头单元格合并(附单行、多级表头代码)

    vue中table表头单元格合并(附单行、多级表头代码)

    本文主要介绍了vue中table表头单元格合并(附单行、多级表头代码),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • vue中使用iconfont图标的过程

    vue中使用iconfont图标的过程

    这篇文章主要介绍了vue中使用iconfont图标的过程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • Vue 换肤的示例实践

    Vue 换肤的示例实践

    本篇文章主要介绍了Vue 换肤的示例实践,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01

最新评论