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>

到此结束。

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

Vue封装一个Tabbar组件 带组件路由跳转方式的更多相关文章

  1. 用vue3封装一个符合思维且简单实用的弹出层

    最近新项目中需要一个弹窗组件,所以我就做了一个,下面这篇文章主要给大家介绍了关于如何利用vue3封装一个符合思维且简单实用的弹出层,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

  2. Node.js中对通用模块的封装方法

    这篇文章主要介绍了Node.js中对通用模块的封装方法,封装方法参考了Underscore.js的实现,需要的朋友可以参考下

  3. java封装及四种权限修饰符详解

    这篇文章主要介绍了java封装及四种权限修饰符详解,对属性进行封装,使用户不能直接输入数据,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值

  4. 在vue中如何封装G2图表

    这篇文章主要介绍了在vue中如何封装G2图表,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  5. JS样式获取的封装方法实例详解

    这篇文章主要介绍了JS样式获取的封装方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Ajax基础教程之封装(三)

    这篇文章给大家介绍ajax基础教程之封装的知识,本文通过实例给大家详细介绍,非常不错,感兴趣的朋友一起学习吧

  7. JavaScript函数封装的示例详解

    这篇文章主要通过动画的示例来为大家详细介绍一下JavaScript的函数封装,文中的示例代码讲解详细,感兴趣的小伙伴可以学习一下

  8. Flutter Dio二次封装的实现

    这篇文章主要介绍了Flutter Dio二次封装的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  9. React路由封装的实现浅析

    路由是React项目中相当重要的概念,对于功能较为复杂的网页来说,必然会涉及到不同功能间的页面跳转,本篇文章将对React官方维护的路由库React-Router-Dom的使用和常用组件进行讲解,同时对路由组件传递param参数的方式进行讲解,希望对各位读者有所参考

  10. vue日常开发基础Axios网络库封装

    这篇文章主要为大家介绍了vue日常开发基础Axios网络库封装示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部