利用vue封装TabBer导航栏

利用vue封装TabBer导航栏

1、利用vue-cli2构建项目

需要在构建项目的时候安装vue-router

2、搭建项目文件路径

在这里插入图片描述

asset里存放图片和css,同时创建一个img文件夹存放图片,再建立一个tabbar子文件夹存放tabbar需要的图片。分别是导航栏未被选中和被选中的图片。

components里就存放公共的组件,比如轮播、导航栏等。

router里就存放router路由组件了。

views就具体存放页面的组件,比如主页(home)、分类(category)、购物车(shopcart)、我的(profile)。

3、封装TabBarItem

TabBarItem就是TabBar导航栏的单个组件,比如:

在这里插入图片描述

所以我们先从最小的封装起。

创建一个组件,名叫TabBarItem.vue。这个组件里面只有一张图片和一排文字(实际上会有两张图片,活跃的时候显示深色图标,不活跃的时候显示浅色图标):

<template><!-- TabBarItem模板 -->
  <div class="tab-bar-item">

    <!-- 图片 -->
    <div class="item-icon">
      <!-- 不活跃 -->
      <slot v-if="!isActive" name="item-icon">导航栏原始图片</slot>
      <!-- 活跃 -->
      <slot v-else name="item-icon-active">导航栏活跃图片</slot>
    </div>

    <!-- 文字(动态绑定class) -->
    <div :class="{'item-text-active':isActive}">
      <slot name="item-text">导航栏文字</slot>
    </div>

  </div>
</template>

所以我就利用isActive来判断该页面是否活跃。同时定义好Item的样式:

<style scoped>

  /* item样式 */
  .tab-bar-item {
    /* 依次从左往右顺序排列 */
    flex: 1;
    /* 文字居中 */
    text-align: center;
    /* 高度 */
    height: 49px;
    /* 文字大小 */
    font-size: 14px;
  }

  /* item图片样式 */
  .item-icon img{
    width: 24px;
    height: 24px;
  }

  /* item文字样式 */
  .item-text-active {
    color: #13227a;
  }

</style>

注意这里我们选择使用slot插槽来占位图片和文字,方便外部直接用图片和文字来装填,不然就需要创建4个Item。

Tips: slot插槽仅用来占位用,只需要name属性,class不会作用在他身上。所以直接利用div来绑定class,然后将slot插槽包围起来就好了。

4、封装TabBar

TabBarItem封装好了就需要将TabBarItem封装到TabBar上了。在一个组件里使用另一个组件就需要先用import导入然后再注册:

<script>
  // 导入TabBarItem
  import TabBarItem from "./TabBarItem";

  export default {
    name: "TabBar",
    components:{
      TabBarItem
    }
  }
</script>

然后在template中使用4个TabBarItem就好了:

<template>
  <div class="tab-bar">

    <!--首页-->
    <tab-bar-item>
      <img src="../../assets/img/tabbar/home.svg" alt="首页" slot="item-icon">
      <img src="../../assets/img/tabbar/home_active.svg" alt="首页" slot="item-icon-active">
      <div slot="item-text">首页</div>
    </tab-bar-item>

    <!--分类-->
    <tab-bar-item>
      <img src="../../assets/img/tabbar/category.svg" alt="分类" slot="item-icon">
      <img src="../../assets/img/tabbar/category_active.svg" alt="分类" slot="item-icon-active">
      <div slot="item-text">分类</div>
    </tab-bar-item>

    <!--购物车-->
    <tab-bar-item>
      <img src="../../assets/img/tabbar/shopcart.svg" alt="购物车" slot="item-icon">
      <img src="../../assets/img/tabbar/shopcart_active.svg" alt="购物车" slot="item-icon-active">
      <div slot="item-text">购物车</div>
    </tab-bar-item>

    <!--我的-->
    <tab-bar-item>
      <img src="../../assets/img/tabbar/profile.svg" alt="我的" slot="item-icon">
      <img src="../../assets/img/tabbar/profile_active.svg" alt="我的" slot="item-icon-active">
      <div slot="item-text">我的</div>
    </tab-bar-item>

  </div>
</template>

注意slot分别将对应的图片和文字插入到插槽里。

<style scoped>

  .tab-bar{
    /* 依次从左往右顺序排列 */
    display: flex;
    /* 背景颜色 */
    background-color: #f6f6f6;
    /* 位置固定 */
    position: fixed;
    /* 位置固定到屏幕最下方 */
    left: 0;
    right: 0;
    bottom: 0;
  }

</style>

这是TabBar的样式。

5、将TabBar引入App.vue中

将组件引入另一个组件同样是需要先用import导入再在components里注册

<script>

// 导入TabBar
import TabBar from "./components/tabber/TabBar";

export default {
  name: 'App',
  components:{
    TabBar
  }
}
</script>

然后就可以在template中使用了:

<template>
  <div id="app">

    <!-- 底下导航栏 -->
    <tab-bar></tab-bar>

  </div>
</template>

到这里,我们大致的TabBar就封装完成。但是我们还需要给它封装跳转的相关逻辑,并且结合vue-router来实现动态路由切换的目的。

6、懒加载4个TabBarItem对应的页面并且配置在routes里

// 导入Vue和VueRouter
import Vue from "vue";
import VueRouter from "vue-router";

// 懒加载组件
const Home = () => import('../views/home/Home');
const Category = () => import('../views/category/Category');
const Shopcart = () => import('../views/shopcart/Shopcart');
const Profile = () => import('../views/profile/Profile');

// 全局使用VueRouter
Vue.use(VueRouter);

// 实例化router
const router=new VueRouter({
  routes:[
    // 主页
    {
      path: '/',
      redirect: '/home'
    },
    // Home页
    {
      path: '/home',
      component: Home
    },
    // Category页
    {
      path: '/category',
      component: Category
    },
    // Shopcart页
    {
      path: '/shopcart',
      component: Shopcart
    },
    // Profile页
    {
      path: '/profile',
      component: Profile
    }
  ],
  mode: 'history'
});

// 导出router
export default router;

这样就可以在页面里利用router或者router-link来进行跳转了。同时在main.js里引入和注册router:

import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  render: h => h(App)
})

7、在TabBarItem里利用$router来跳转页面

因为我们没有使用router-link来跳转页面,所以我们就需要用this.$router.push()或者this.$router.replace()来使用代码进行直接跳转。并且我们需要明白一个逻辑就是为了提高代码的复用性,我们肯定是只需要一个TabBarItem,然后在TabBarItem里放置插槽,然后在外部动态的向插槽里放置图片和文字,所以我们就需要在TabBarItem里动态获取需要跳转的路径然后再在TabBarItem里进行跳转。所以我们就需要在父组件,也就是TabBar里给每个TabBarItem绑定path,然后点击该TabBarItem后获得该path然后再进行跳转。所以我们就需要在TabBar里给每个Item加上path:

<template>
  <div class="tab-bar">

    <!--首页-->
    <tab-bar-item path="/home">
      <img src="../../assets/img/tabbar/home.svg" alt="首页" slot="item-icon">
      <img src="../../assets/img/tabbar/home_active.svg" alt="首页" slot="item-icon-active">
      <div slot="item-text">首页</div>
    </tab-bar-item>

    <!--分类-->
    <tab-bar-item path="/category">
      <img src="../../assets/img/tabbar/category.svg" alt="分类" slot="item-icon">
      <img src="../../assets/img/tabbar/category_active.svg" alt="分类" slot="item-icon-active">
      <div slot="item-text">分类</div>
    </tab-bar-item>

    <!--购物车-->
    <tab-bar-item path="/shopcart">
      <img src="../../assets/img/tabbar/shopcart.svg" alt="购物车" slot="item-icon">
      <img src="../../assets/img/tabbar/shopcart_active.svg" alt="购物车" slot="item-icon-active">
      <div slot="item-text">购物车</div>
    </tab-bar-item>

    <!--我的-->
    <tab-bar-item path="/profile">
      <img src="../../assets/img/tabbar/profile.svg" alt="我的" slot="item-icon">
      <img src="../../assets/img/tabbar/profile_active.svg" alt="我的" slot="item-icon-active">
      <div slot="item-text">我的</div>
    </tab-bar-item>

  </div>
</template>

注意tab-bar-item标签上的path。因为这是父组件的path,所以我们就可以在子组件利用props来获取:

<script>
  export default {
    name: "TabBarItem",
    props: {
      // 从父组件获得path
      path: {
        type: String,
        required: true
      },
    },
    methods: {
      itemClick() {
         this.$router.replace(this.path);
      },
    },
  }
</script>

直接利用props获得path,然后再通过this.$router.replace()将从props里获得的path绑定然后直接跳转。这样就达到了跳转的目的。但是有一个问题:假如说我处在当前页面再进行跳转的话就会跳转到/home/home这个路径下,显然,这是不正确的。所以我们要进行判断,如果现在跳转的页面仍然是当前页面,那么就不跳转:

	itemClick() {
        // 将要跳转页面的path
        let nextPath=this.path;
        // 当前页面的path
        let currentPath=this.$route.path;
        // 避免重复点击当前页报错
        if (nextPath!==currentPath){
          this.$router.replace(nextPath);
        }
      },

利用this.path获得在TabBar里点击TabBarItem的路径path,然后再利用this.$route.path获得当前活跃的路径(也就是当前页面所处的路径)进行比较,如果相同,说明用户仍然想跳转到该页面,此时不执行跳转,否则将执行跳转。

此时,我们就解决了页面跳转问题并且解决了重复点击Item会报错的问题。

8、动态获取页面的活跃情况并且切换样式

在实际开发中,用户一般点击到哪个Item,那个Item就会高亮,和其他的Item有着不同的样式,所以我们需要完成动态切换Item样式的需求。首先,我们需要创建一个computed计算属性来保存item的是否活跃:

    computed: {
      // 判断当前页面是否处于活跃,true:活跃;false:不活跃
      isActive() {
        /*
        * 判断逻辑是:取当前活跃页面的路径字符对从父组件
        * 获得的path进行比较,如果前者包含后者,说明当前
        * 页处于活跃。(包含indexOf的返回值就是0,return
        * true,不包含返回-1,return false)
        * */
        return this.$route.path.indexOf(this.path)===0;
      }
    },

逻辑就是利用从父组件props里获取的path来对this.$route.path(当前页面的路径)进行匹配,如果从父组件传来的路径(this.path)存在当前页面路径(this.$route.path)就返回0,否则返回-1或者字符串存在的下标。所以,就会return,如果等于0说明相匹配,就表明当前路径确实是活跃的,否则不活跃。所以在template里:

<template><!-- TabBarItem模板 -->
  <div class="tab-bar-item" @click="itemClick">

    <!-- 图片 -->
    <div class="item-icon">
      <!-- 不活跃 -->
      <slot v-if="!isActive" name="item-icon">导航栏原始图片</slot>
      <!-- 活跃 -->
      <slot v-else name="item-icon-active">导航栏活跃图片</slot>
    </div>

    <!-- 文字(动态绑定class) -->
    <div :class="{'item-text-active':isActive}">
      <slot name="item-text">导航栏文字</slot>
    </div>

  </div>
</template>

利用isActive来判断当前页面是否处于活跃,如果处于活跃,显示导航栏活跃图片(深色),同时绑定上深色字体的样式。

9、在需要的地方加上router-view供内容显示

最后在App.vue里加上router-view以显示内容:

<template>
  <div id="app">

    <!-- 显示内容 -->
    <router-view></router-view>

    <!-- 底下导航栏 -->
    <tab-bar></tab-bar>

  </div>
</template>
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值