Vue-CLI + Vue3 + Vue-Router4 实现tabbar小案例

news2024/11/29 16:33:23

Vue-CLI + Vue3 + Vue-Router4 实现tabbar小案例

tabbar导航栏案例:该案例实现了基础的组件封装,编程式路由,以及插槽的使用,对于我们日常组件化开发有着很大的启示作用,主要效果是点击下方的导航栏链接,上方内容区显示对应的组件内容,就如果我们常用的手机App一样。

效果图:

项目结构图:

svg图片资源下载:点击下载图片资源

1、 使用Vue-CLI新建tabbar工程,删除不必要的vue组件,并且取消代码检查:lintOnSave:false
2、 在assets文件夹下建立css和img文件夹,存放静态资源,将图片复制到img文件夹中的tabbar子文件夹中

3、 在css文件夹中建立base.css文件:

body{
    padding: 0;
    margin: 0;
}
/*然后在App.vue组件的style中引入css/base文件:@import "assets/css/base.css",此处不建议在main.js中引入*/

4、 修改App.vue的内容:

<template>
  <div id="app">
    <div id="tab-bar">
      <div class="tab-bar-item">首页</div>
      <div class="tab-bar-item">分类</div>
      <div class="tab-bar-item">购物车</div>
      <div class="tab-bar-item">我的</div>
    </div>
  </div>
</template>

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

<style>
@import "assets/css/base.css";
#tab-bar{
  display: flex; /* 弹性盒子布局 */
  background-color: #f1f1f1;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: 50px;
  box-shadow: 0 -2px 2px rgba(100,100,100,0.2);
}
.tab-bar-item{
  flex: 1; /* 对多项内容等分排列 */
  text-align: center;
  height: 49px;
  font-size: 14px;
}
</style>

5、 将导航栏封装成TabBar和TarBarItem两个组件,步骤如下:

//1. 把id为tab-bar的层及相应的css代码等封装在一起,作为一个组件
//2. 在components文件夹中建立一个名为tabbar的子文件夹,单独存放tabbar组件相关的组件,不要把所有的组件都直接放在components文件夹下,便于管理。[项目越大,组件越多]
//3. 在tabbar文件夹中建立名为TabBar.vue文件,把App.vue文件中的内容复制到TabBar.vue中
//4. 在TabBar.vue中,有四项内容,由于每一项在后期显示时有图片和文字,所以把TabBar.vue中的每一项封装成一个组件:TabBarItem.vue,考虑到TabBar.vue中使用的TabBarItem子组件数量是不固定的,所以要用到插槽。
//代码如下:

TabBar.vue内容:

<template>
  <div id="tab-bar">
    <!-- 使用插槽,让App.vue根据需要,插入内容 -->
    <slot></slot>
  </div>
</template>

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

<style scoped>
#tab-bar{
  display: flex; /* 弹性盒子布局 */
  background-color: #f1f1f1;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: 50px;
  box-shadow: 0 -2px 2px rgba(100,100,100,0.2);
}
</style>

TabBarItem.vue内容:

<template>
  <div class="tab-bar-item">
    <img src="../../assets/img/tabbar/home.svg" alt="" />
    <div>首页</div>
  </div>
</template>

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

<style scoped>
.tab-bar-item {
  flex: 1; /* 对多项内容等分排列 */
  text-align: center;
  height: 49px;
  font-size: 14px;
}

.tab-bar-item img{
  width: 24px;
  height: 24px;
  margin-top: 3px;
  margin-bottom: 2px;
  vertical-align: middle;
}
</style>

App.vue内容:

<template>
  <div id="app">
    <tab-bar>
      <!-- 根据需要在插槽位置插入4个子组件TabBarItem[数量可变] -->
      <tab-bar-item></tab-bar-item>
      <tab-bar-item></tab-bar-item>
      <tab-bar-item></tab-bar-item>
      <tab-bar-item></tab-bar-item>
    </tab-bar>
  </div>
</template>

<script>
  //导入TabBar组件
  import TabBar from "./components/tabbar/TabBar";
  //导入TabBarItem组件
  import TabBarItem from "./components/tabbar/TabBarItem";
  export default {
    name:'App',
    components:{
      TabBarItem,
      TabBar
    }
  }
</script>

<style>
@import "assets/css/base.css";
</style>

6、 测试运行…界面会出现四个子组件,但内容都一样,而我们要实现的是显示不同内容的4个组件,所以就可以在TabBarItem中也使用插槽(上方显示图片,下方显示文字):

<template>
  <div class="tab-bar-item">
    <!--  如果使用多个插槽,要使用具名插槽  -->
    <slot name="item-icon"></slot>
    <slot name="item-text"></slot>
  </div>
</template>

7、 修改App.vue,将TabBarItem中的插槽填满,把其中对于img的样式放到App.vue中:

<template>
  <div id="app">
    <tab-bar>
      <!-- 根据需要在插槽位置插入4个子组件TabBarItem[数量可变] -->
      <tab-bar-item>
        <template #item-icon>
          <img src="./assets/img/tabbar/home.svg" alt="">
        </template>
        <template #item-text>
          <div>首页</div>
        </template>
      </tab-bar-item>
      <tab-bar-item>
        <template #item-icon>
          <img src="./assets/img/tabbar/category.svg" alt="">
        </template>
        <template #item-text>
          <div>分类</div>
        </template>
      </tab-bar-item>
      <tab-bar-item>
        <template #item-icon>
          <img src="./assets/img/tabbar/shopcart.svg" alt="">
        </template>
        <template #item-text>
          <div>购物车</div>
        </template>
      </tab-bar-item>
      <tab-bar-item>
        <template #item-icon>
          <img src="./assets/img/tabbar/profile.svg" alt="">
        </template>
        <template #item-text>
          <div>我的</div>
        </template>
      </tab-bar-item>
    </tab-bar>
  </div>
</template>
<style>
@import "assets/css/base.css";
.tab-bar-item img {
  width: 24px;
  height: 24px;
  margin-top: 3px;
  margin-bottom: 2px;
  vertical-align: middle;
}
</style>

接下来实现点击TabBarItem时,显示红色图片且红色文字。先给TabBarItem组件增加一个插槽,专门显示活跃图片,原来那个显示图片的插槽显示非活跃的;当组件被点击时,判断它是否为活跃状态,是就显示红色图片,否则显示黑色图片,文字也是如此…

8、 在TabBar组件的template中增加一个插槽,用来显示活跃图片:

<template>
  <div class="tab-bar-item">
    <!--  如果使用多个插槽,要使用具名插槽  -->
    <slot name="item-icon"></slot>
    <slot name="item-icon-active"></slot>
    <slot name="item-text"></slot>
  </div>
</template>

9、 对App.vue进行修改,给每个tab-bar-item中插入一张活跃图片,然后运行测试,发现有两个svg图片,也就是说三个插槽都显示出来了:

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

10、 对TabBarItem组件进行修改,实现两个图片插槽只显示一个,使用v-if与v-else实现:

<template>
  <div class="tab-bar-item">
    <!--  如果使用多个插槽,要使用具名插槽  -->
    <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>

<script>
export default {
  name: "TabBarItem",
  data(){
    return{
      isActive:false
    }
  },
  computed:{
    activeStyle(){
      return this.isActive ? {color:'#ff5777'}:{}
    }
  }
}
</script>

<style scoped>
.tab-bar-item {
  flex: 1; /* 对多项内容等分排列 */
  text-align: center;
  height: 49px;
  font-size: 14px;
}
</style>

接下来实现路由:点击tabbar导航栏中某一项,就显示相应的组件。

在view文件夹中存放页面级别的组件,比如说路由跳转的组件,在component文件夹中存放可复用的组件。

11、 在views文件夹中创建四个子文件夹(home/category/shopcart/profile),在子文件夹中分别建立相对应的vue文件(HomeView/CategoryView/ShopCartView/ProfileView),文件中显示一些简单文字用以区分即可:

<template>
  <div>
    <h2>这是首页组件</h2>
  </div>
</template>

12、 在index.js配置文件中添加路由配置信息:

{
  path: '/',
  redirect: '/home'
},
{
  path: '/home',
  name: 'home',
  component: () => import('../views/tabbar/home/HomeView')
},
{
  path: '/category',
  name: 'category',
  component: () => import('../views/tabbar/category/CategoryView')
},
{
  path: '/shopcart',
  name: 'shopcart',
  component: () => import('../views/tabbar/shopcart/ShopCartView')
},
{
  path: '/profile',
  name: 'profile',
  component: () => import('../views/tabbar/profile/ProfileView')
},

13、 在TabBarItem中添加点击事件与路由结合起来,用来显示正确的组件:

<script>
export default {
  name: "TabBarItem",
  props:{
    path:String,
    activeColor:String
  },
  data(){
    return{
      isActive:false
    }
  },
  computed:{
    activeStyle(){
      return this.isActive ? {color:this.activeColor}:{}
    }
  },
  methods:{
    itemClick(){
      this.$router.replace(this.path)
    }
  }
}
</script>

14、 对App.vue进行修改,在tab-bar-item上增加path参数(分别为:/home,/category,/shopcart,/profile),和activeColor参数(值为活跃时的颜色),然后在根模板下添加router-view输出组件,运行测试,此时就可以切换组件视图了:

<tab-bar-item path="/home" active-color="#ff5577">

15、 在TabBarItem中修正显示的颜色,当前点击项显示红色,其它项为默认颜色(黑色),在computed中增加isActive属性(实现活跃验证),将data()中的isActive删掉,然后运行测试:

isActive(){
  // === -1:表示当前路由中的路径不包含父组件传递过来的路径
  return this.$route.path.indexOf(this.path) !== -1
}

16、 继续提取出一个组件(MainTabBar.vue),放在components文件夹下的tabbar文件夹中,把App.vue文件内容复制到MainTabBar中,以便提取修改:

MainTabBar:

<template>
  <div id="app">
    <tab-bar>
      <!-- 根据需要在插槽位置插入4个子组件TabBarItem[数量可变] -->
      <tab-bar-item path="/home" active-color="#ff5577">
        <template #item-icon>
          <img src="../../assets/img/tabbar/home.svg" alt="">
        </template>
        <template #item-icon-active>
          <img src="../../assets/img/tabbar/home_active.svg" alt="">
        </template>
        <template #item-text>
          <div>首页</div>
        </template>
      </tab-bar-item>
      <tab-bar-item path="/category" active-color="#ff5577">
        <template #item-icon>
          <img src="../../assets/img/tabbar/category.svg" alt="">
        </template>
        <template #item-icon-active>
          <img src="../../assets/img/tabbar/category_active.svg" alt="">
        </template>
        <template #item-text>
          <div>分类</div>
        </template>
      </tab-bar-item>
      <tab-bar-item path="/shopcart" active-color="#ff5577">
        <template #item-icon>
          <img src="../../assets/img/tabbar/shopcart.svg" alt="">
        </template>
        <template #item-icon-active>
          <img src="../../assets/img/tabbar/shopcart_active.svg" alt="">
        </template>
        <template #item-text>
          <div>购物车</div>
        </template>
      </tab-bar-item>
      <tab-bar-item path="/profile" active-color="#ff5577">
        <template #item-icon>
          <img src="../../assets/img/tabbar/profile.svg" alt="">
        </template>
        <template #item-icon-active>
          <img src="../../assets/img/tabbar/profile_active.svg" alt="">
        </template>
        <template #item-text>
          <div>我的</div>
        </template>
      </tab-bar-item>
    </tab-bar>
  </div>
</template>

<script>
//导入TabBar组件
import TabBar from "./TabBar";
//导入TabBarItem组件
import TabBarItem from "./TabBarItem";
export default {
  name:'MainTabBar',
  components:{
    TabBarItem,
    TabBar
  }
}
</script>

<style>
.tab-bar-item img {
  width: 24px;
  height: 24px;
  margin-top: 3px;
  margin-bottom: 2px;
  vertical-align: middle;
}
</style>

App.vue:

<template>
  <div id="app">
    <router-view/>
    <main-tab-bar></main-tab-bar>
  </div>
</template>

<script>
//导入MainTabBar组件
import MainTabBar from "@/components/tabbar/MainTabBar";
export default {
  name:'App',
  components:{
    MainTabBar
  }
}
</script>

<style>
@import "assets/css/base.css";
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/606875.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【owt】addon.MediaStream,erizo::MediaStream 还有addon.MediaXXX,erizo::MediaXXX

9. MediaStream 和erizo::MediaStream 类的继承关系 erizo::MediaStream source/agent/webrtc/rtcConn/erizo/src/erizo/MediaStream.h source/agent/webrtc/rtcConn/erizo/src/erizo/MediaDefinitions.h erizo::MediaSource source/agent/webrtc/rtcConn/erizo/src/erizo/…

皮卡丘RCE

1.RCE漏洞描述 RCE漏洞&#xff0c;可以让攻击者直接向后台服务器远程注入操作系统命令或者代码&#xff0c;从而控制后台系统。 远程系统命令执行 一般出现这种漏洞&#xff0c;是因为应用系统从设计上需要给用户提供指定的远程命令操作的接口。比如我们常见的路由器、防火墙…

XSS笔记(简单了解的)

1.什么是XSS&#xff1f; XSS (Cross Site Scripting)&#xff0c;即跨站脚本攻击&#xff0c;是一种常见于 Web 应用中的计算机安全漏洞。恶意攻击者往 Web 页面里嵌入恶意的客户端脚本&#xff0c;当用户浏览此网页时&#xff0c;脚本就会在用户的浏览器上执行&#xff0c;进…

chatgpt赋能python:Python可以有多个同名函数吗?

Python 可以有多个同名函数吗&#xff1f; Python作为一门高级编程语言&#xff0c;其灵活性和易用性备受开发人员的青睐。在Python中&#xff0c;函数是编程语言的核心&#xff0c;任何有经验的Python工程师都会知道Python的函数允许使用相同的名称来进行定义。那么问题来了&…

一文搞懂编程界中最基础最常见【必知必会】的十一个算法,再也别说你只是听说过【建议收藏+关注】

文章目录 常见算法分类算法复杂度算法描述与实现交换类排序冒泡排序快速排序 插⼊类排序直接插入排序Shell排序 选择类排序简单选择排序&#xff08;⼜称直接选择排序&#xff09;堆排序 归并排序二路归并排序多路排序 线性时间非比较类排序计数排序基数排序桶排序 常见算法分类…

1. 爬虫及爬虫的步骤

1. 爬虫及爬虫的步骤 文章目录 1. 爬虫及爬虫的步骤1. 爬虫是什么&#xff1f;2. 爬虫的作用3. 爬虫步骤3.1 获取网页3.2 解析网页3.3 存储数据 4. 总结 1. 爬虫是什么&#xff1f; 爬虫就是写一段代码让计算机模仿人类自动访问网站。 2. 爬虫的作用 爬虫可以代替人们自动地…

Golang每日一练(leetDay0085) 2的幂、数字 1 的个数

目录 231. 2的幂 Power of Two &#x1f31f; 233. 数字 1 的个数 Number of Digit One &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java…

深度学习总结——用自己的数据集微调CLIP

CLIP概述 CLIP&#xff08;Contrastive Language-Image Pretraining&#xff09;是由OpenAI开发的一种深度学习模型&#xff0c;用于将图像和自然语言文本进行联合编码。它采用了多模态学习的方法&#xff0c;使得模型能够理解图像和文本之间的语义关系。 它的核心思想是将图…

皮卡丘SQL注入汇总

1.Sql Inject(SQL注入)概述 SQL注入漏洞主要形成的原因是在数据交互中&#xff0c;前端的数据传入到后台处理时&#xff0c;没有做严格的判断&#xff0c;导致其传入的“数据”拼接到SQL语句中后&#xff0c;被当作SQL语句的一部分执行。 从而导致数据库受损&#xff08;被脱裤…

循环控制语句

文章目录 1.break——跳出循环1.1作用 2.continue——控制循环2.1作用 3.猜数字4.while语句4.1while语句的结构4.2算1-10求和&#xff1a;4.3使用while方式批量添加5个用户给这五个用户添加密码&#xff1a; 5.until语句6.拓展6.1 购物6.2shell 计算器实现加减乘除和取余6.3打印…

chatgpt赋能python:Python反转输出正整数-让计算更简单

Python反转输出正整数-让计算更简单 Python是一种高级编程语言&#xff0c;除了可以完成各种任务&#xff0c;还可以反转输出正整数。在本篇SEO文章中&#xff0c;我将介绍如何使用Python编程语言反转输出正整数&#xff0c;并且展现了这个方法是如何简化计算。 什么是Python…

chatgpt赋能python:Python列表指定元素的取出方法

Python列表指定元素的取出方法 在Python编程中&#xff0c;经常需要取出列表中的指定元素。本文将介绍几种常用的取出列表指定元素的方法。 1. 使用索引 列表中的元素可以通过索引来进行访问和修改&#xff0c;索引从0开始。下面的示例展示了如何使用索引来取出列表中的指定…

六、docker安装ngxin部署若以前端

1.第一次安装&#xff0c;不进行挂载数据卷&#xff0c; docker run \ -p 8060:80 \ --name nginx \ --privilegedtrue \ --restartalways \ -d nginx:1.17.82. 将配置信息复制到宿主机本地 # 将容器nginx.conf文件复制到宿主机 docker cp nginx:/etc/nginx/nginx.conf /data…

总投资300亿,南山前海南山村旧改城市更新

南山村 项目位于南山区南山街道南山村旧村片区&#xff0c;东临南新路&#xff0c;南临东滨路&#xff0c;西临前海路&#xff0c;北临南园村。地处联系前海、后海两大中心区的空间发展轴带上&#xff0c;区位交通条件优越。位于9号线延长线前海路站附近&#xff0c;也因地处大…

背包问题总结篇

背包问题总结篇 关于这几种常见的背包&#xff0c;其关系如下&#xff1a; 通过这个图&#xff0c;可以很清晰分清这几种常见背包之间的关系。 在讲解背包问题的时候&#xff0c;我们都是按照如下五部来逐步分析&#xff0c;相信大家也体会到&#xff0c;把这五部都搞透了&…

【C++刷题】【动态规划篇】(一)

动态规划篇&#xff08;一&#xff09; 一、1137. 第 N 个泰波那契数&#xff08;easy&#xff09;二、三步问题&#xff08;easy&#xff09;三、使用最小花费爬楼梯&#xff08;easy&#xff09;四、解码方法&#xff08;medium&#xff09;五、不同路径&#xff08;medium&a…

如何利用地面控制点实现倾斜摄影三维模型数据的几何坐标变换和纠正?

如何利用地面控制点实现倾斜摄影三维模型数据的几何坐标变换和纠正&#xff1f; 倾斜摄影是一种在空中拍摄地表物体的技术&#xff0c;可以获得高分辨率、高精度的三维模型数据&#xff0c;广泛应用于城市规划、建筑设计、土地管理等领域。然而&#xff0c;由于航拍时无法避免姿…

ClassLoader源码

介绍 ClassLoader 顾名思义就是类加载器 ClassLoader 是一个抽象类 没有父类 作用 1.负责将 Class 加载到 JVM 中 2.审查每个类由谁加载&#xff08;父优先的等级加载机制&#xff09; 3.将 Class 字节码重新解析成 JVM 统一要求的对象格式 常量&变量 //注册本地方法…

chatgpt赋能python:Python实现动态排名:在SEO游戏中的使用

Python实现动态排名&#xff1a;在SEO游戏中的使用 搜索引擎优化&#xff08;SEO&#xff09;是一项必不可少的活动&#xff0c;可以提高网站在搜索结果中的排名和流量。其中之一是动态排名&#xff0c;它可以根据网站相应信息的变化而自动更新排名&#xff0c;使网站始终保持…

chatgpt赋能python:Python技巧:如何用Python去除文本中的头和尾

Python技巧&#xff1a;如何用Python去除文本中的头和尾 在任何文本处理任务中&#xff0c;去除文本数据的头和尾是非常常见的需求。这在搜索引擎优化&#xff08;SEO&#xff09;中尤其重要&#xff0c;因为头和尾中可能包含重复的内容&#xff0c;这会降低网页的排名。在这篇…