使用 Vue 封装自定义组件[ Tabbar ]底部切换栏(不使用组件库)

204 阅读2分钟

其实封装一个自定义的底部切换栏组件很简单,因为功能十分单一。封装复用的、功能多样的组件才是一件难事!还有写文章也挺不容易的(。•ˇ‸ˇ•。)

为什么要封装:这种废话就不多说了,上一篇关于封装轮播图组件的文章已经有浅谈过。而且作为一名积极上进的前端开发,多点练习封装组件真的很有必要。

为什么不使用组件库:组件库用起来确实很方便,但是我还是想自己封装一遍,理清其中的逻辑思路。而且Tabbar这种底部切换栏,其实是很简单的效果,实现起来不难也很容易理解。

来了啵,下面进入正题!

Tabbar效果展示

点击不同的图标,切换到各自对应的页面,并显示活跃状态。

20221003_014933 00_00_01-00_00_10.gif

如何实现

HTML结构

一个ul列表,包含4个li子元素(当然也可以用普通的div盒子包裹4个div子元素)

每个li切换项,包含一张图片和文字

在data中定义一个切换项数组routerList,每一个数组项顺序对应每一个切换项

数组项是一个对象,包含{路径、选中状态的图片、未选中状态的图片、标题}

如何改变 选中和未选中 的状态

遍历生成结构时,img标签的图片路径为一个三元表达式,判断当前路由是否以自己数据项的路径开头,true则赋值选中状态是图片,否则赋值未选中状态的图片

 <!-- HTML结构 -->
  <div class="tabbar">
    <ul>
      <li
        v-for="(item, index) in routerList"
        :key="index"
        @click="changePath(item.path)"
      >
        <img
          :src="$route.path.startsWith(item.path) ? item.selected : item.active"
          alt=""
        />
        <span :class="$route.path.startsWith(item.path) ? 'active' : ''">
          {{item.title}}
        </span>
      </li>
    </ul>
  </div>

CSS布局样式

flex 弹性盒布局是最方便简单的

  • ul列表 :弹性布局, 固定宽高,垂直居中
  • li子元素 :垂直方向开启弹性布局,均分ul列表的宽度,水平居中
  • 图片:固定宽高

JS动态效果

为每个li切换项绑定click回调,参数是每个li的路径 定义回调函数,判断接收的路径是否与当前路由路径相同,不相同才切换页面

methods: {
    changePath(path) {
      // 跳转路径       先判断点击的是否同一个,相同则return
      if (path == this.$route.path) return;
      else this.$router.replace(path);
    },
  },

完整代码

<template>
  <!-- HTML结构 -->
  <div class="tabbar">
    <ul>
      <li
        v-for="(item, index) in routerList"
        :key="index"
        @click="changePath(item.path)"
      >
        <img
          :src="$route.path.startsWith(item.path) ? item.selected : item.active"
          alt=""
        />
        <span :class="$route.path.startsWith(item.path) ? 'active' : ''">
          {{ item.title }}
        </span>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "Tabbar",
  // 遍历的数据
  data() {
    return {
      routerList: [
        {
          title: "首页",
          active: "./images/home.png",            //未选中
          selected: "./images/home-select.png",   //选中
          path: "/home",
        },
        {
          title: "分类",
          active: "./images/list.png",            //当然图片都可以自定义
          selected: "./images/list-select.png",
          path: "/category",
        },
        {
          title: "购物车",                         //标题也是
          active: "./images/cart.png",
          selected: "./images/cart-select.png",
          path: "/cart",
        },
        {
          title: "我的",
          active: "./images/my.png",
          selected: "./images/my-select.png",
          path: "/my",
        },
      ],
    };
  },
  methods: {
    changePath(path) {
      // 跳转路径       先判断点击的是否同一个,相同则return
      if (path == this.$route.path) return;
      else this.$router.replace(path);
    },
  },
};
</script>

<style scoped lang="scss">
.tabbar {                         // 使用了scss 预处理器
  width: 100%;
  height: 1.4rem;
  background-color: white;

  ul {
    display: flex;
    justify-content: space-around;
    width: 100%;
    height: 100%;

    li {
      flex: 1;
      display: flex;
      flex-direction: column;
      font-size: 0.4267rem;
      align-items: center;
      justify-content: center;
      img {
        width: 0.8267rem;
        height: 0.8267rem;
      }
    }
  }
}
</style>

总结

封装一个自定义组件是不是真的挺简单的?

确实!不过这只是因为我们封装的是一个底部切换栏,功能十分单一。封装复用的、功能多样的组件才是一件难事呢!

写文章也很难!虽然看起来只是很简单的内容,但是我也花了两个多小时。不简单呐.... 所以如果你看到这里了,我真的会谢!!!

82410650529f86e7d25f70568b5a44f5.jpeg