前端框架Vue自学之Vue router小案例TabBar(七)

内容:TabBar设计与实现

正文:

TabBar

零、前言(源码

  可以结合源码来看,最后自己实现。源码在我的GitHub上:TabBar源码(Vue-router小案例)。

一、tabbar的基本结构的搭建

  1、需求

  tabbar就是类似下图的东西。可以让我们传入一些组件,图片,文字等。当我们点击“首页”,显示首页的相关东西;当我们点击‘分类’,显示分类的相关东西等。其实,这就是相当于把项目的结构搭建好了,之后我们做的项目中,就是往每个不同的选项构建对应的组件。

  

    2、实现思路(后续,就按照这个思路去一步步实现)

  首先,如果在下方有一个单独的TabBar组件,你如何封装?自定义TabBar组件,在App中使用;让TabBar处于底部,并且设置相关的样式。 

  接着,TabBar中显示的内容由外界决定:定义插槽;flex布局平分TabBar。

  接着,自定义TabBarItem,可以传入图片和文字:定义TabBarItem,并且定义两个插槽:图片和文字;给两个插槽外层包装div,用于设置样式;填充插槽,实现底部TabBar的效果。

  接着, 传入高亮图片。定义另外一个插槽,插入active-icon的数据。定义一个变量isActive,通过v-show来决定是否显示对应的icon。

  接着,TabBarItem绑定路由数据。安装路由(npm install vue-router --save);完成router/index,js的内容,以及创建对应的组件;main.js中注册router;App中加入<router-view>组件。

  接着,点击item跳转到对应路由,并且动态决定isActive。监听item的点击,通过this.$router.replace()替换路由路径;通过this.$route.path.indexOf(this.link)!== -1来判断是否是active。

  接着,动态计算active样式。封装新的计算属性:this.isActive?{'color':'red'}:{}。

  3、VScode下,搭建tabbar的基本结构

   首先,用Vue CLI2创建项目(Vue CLI3也可以)。目录终端输入vue init webpack tabbar。选项中注意使用runtimeonly(之前博客有分析过),安装路由(没安装也没关系,后面我们手动安装)。

  我们先把默认安装的一些东西删除,如自带的HelloWorld.vue,App.vue的对应HelloWorld的引入,样式等。(此时,npm run dev ,页面应该是一片空白的)

  注意,我们要用封装的思想,近可能多使用插槽,多复用一些公共的组件的思想。

  在src/assets创建img和css文件夹,在css文件夹下创建base.css(初始样式),并在App.vue中的style便签内用@import这个文件。

  

  

   接着我们添加tabbarItem,并且让tab-bar水平分布,给背景色,边缘设置阴影,并且让其处于页面底部。tab-bar-item居中均等分,高度一般为49px(移动开发的经验值)。

  (App.vue)

  (App.vue)

  (结果预览)

二、TabBar和TabBarItem组件封装

  之前我们写的TabBarItem非常不好,如果我们别的项目也要用时,要复制的代码太多了(HTML代码还有其样式代码等),我们要将其封装成独立的组件。这样就方便复用了。

  1、基本实现

  首先在components文件夹创建tabbar文件夹,里面放置关于tabbar功能的组件。在该文件夹下,创建TabBar.vue组件,然后将原来在App.vue写关于tabbar功能的部分对应写到TabBar.vue。如<template>的内容和<style>的内容。

  并且在App.vue导入、注册和使用TabBar组件。

   

   页面显示的结果和之前一样。但是我们把TabBar封装成组件了。

  接着,我们把tabbaritem相关图片放置在之前创建的img文件夹中(放在创建一个tabbar文件夹中)。(如果想在VScode里面预览SVG图片,可以安装SVG Viewer插件)

  

  可以发现我们的图标每种分为两类,一类是未激活,一类是激活状态。

  

   然后,在TabBarItem里面使用img便签,引入对应图片。并且在style中设置大小。注意此时的img和我们的div内容如“首页”等都是行内标签,可以再用div把内容包含。

  

  

  (显示效果)

  2、用组件化的思路重构之前的代码

  上面写的代码,虽然最终可以实现我们想要的效果,但是我们可以发现,代码逻辑已经是嵌套在一起了,我们希望,tabbar应该只关心自己大的组件的逻辑(tabbar的布局和tabbar的样式),至于小的元素怎么布局不应该涉及,不然最后封装的组件乱七八糟,令人烦恼。

  所以,tabbar封装完之后,放入插槽slot即可。

   

   然后在App.vue使用的tabbar组件中把内容填进去(即插入了插槽),注意最后我们不会如下图这么用,因为App.vue多了插槽内容的HTML代码和样式代码,很乱。所以我们再创建一个组件。

  

  (页面效果没问题)

  所以我们再创建一个组件TabBarItem.vue组件(components/tabbar内),然后把属于TabBarItem的template和style放到对应部分去,之后在到App.vue中导入、注册、使用TabBarItem.vue组件。TabBarItem.vue组件的使用是放在之前使用的TabBar组件中的,就是把TabBarItem.vue组件插入TabBar组件的插槽。

 

   

    (页面显示4个item,因为插入4个组件)

  现在先暂时不管填充的内容,因为后面我们会动态填充。到此,我们必须理解的是:定义封装了独立逻辑(独立的template和独立的style)的大组件TabBar和其中小组件TabBarItem,并且可以通过slot插槽把小组件插入到大组件中。这样做的好处是使用组件,不用再考虑样式的问题,因为内部写好了。

  现在又出现了新的问题,刚刚TabBarItem里面填充的内容不能写死,不然在我们最后的页面显示的item都是一样的了。所以,我们继续在TabBarItem组件中使用slot插槽(有name属性,分别放图标和文字)。

  

  然后在App.vue使用这个组件的插槽。

   (页面展示)

  此时,由于写成小组件+插槽的形式,假如说我们需要5个tabbaritem,直接复用组件,往组件插槽填内容,即可。非常方便!(即使用<TabBarItem>组件,里面填内容)

  (组件随意复用)

三、给TabBarItem传入active图片

  上一章中,我们只使用了未激活的图片,我们想当item处于活跃状态的时候显示另一张图片(对应的活跃的图片)。

  所以在TabBarItem里面还需要一个插槽,用于放置图片(未激活与激活)。注意,是一开始把两张未激活与激活的图片传入到组件,然后通过状态决定显示哪一张,而不是根据状态插一张,另一个状态插一张。

  首先在TabBarItem组件中,假如一个slot。

  

   然后,在App.vue中插入激活图片(一共传两个图片)。

   但此时,没有根据状态确定显示激活图片还是未激活图片,此时同时显示两张图,这是不对的。

  

   我们很容易想到使用v-if和v-else,加上一个激活变量isActive,来做。此外,如果我们想激活时,对应的item-text文字部分也变红(变个样式),也要设定一个有激活变量控制的样式。注意,插槽内容渲染时,会替换插槽slot的代码,如果我们想在插槽设定样式(包括刚刚说的v-if,v-else等属性),必须用div包裹其中,把本想写在插槽的样式写在这个div中

   

   此时,可以通过isActive为true还是false(状态),来控制显示的图标和文字是否处于激活状态。

  (isActive: true)

  (isActive: false)

四、TabBarItem和路由结合效果

  我们希望点击具体的item,页面主题得显示对应item的“主页内容”,即我们先点击“首页”,在主页内容中显示“首页”的东西(其实也是一个组件,即关于首页的组件)。现在我们就想让小组件TabBarItem与大组件页面主体一一对应(映射关系)。这就使用到我们的vue-router了(终于回归了主题,组件化思想的开发)。

  首先,我们先安装路由(如果之前没有在项目安装的话)。l路径终端输入npm install vue-router --save (运行时依赖)。在src下创建router文件夹,并在router文件夹下建立index.js。在index.js导入vue,VueRouter;安装VueRouter插件,创建路由对象,配置路由映射关系,导出路由,导入路由(main.js中),在vue实例挂载路由(在我前一个博客里有具体说明)。

  (index.js)

  (main.js)

  由于我们有四个TabBarItem,所以要配置四个路由映射。当然也要创建四个大的组件啦(都是视图/大页面方面的组件)。通常,先在src文件夹下创建views文件夹(通常放置视图、大的页面的组件),然后在views文件夹内在创建四个我们关于TabBarItem对应的大组件的文件夹:home文件夹,category文件夹,cart文件夹,profile文件夹。每个文件夹就是放置关于这个视图的组件文件。我们简单在里面创建对应大组件(先简单显示一些文字内容即可)。

  补充:通常src/components放置的是公共组件。

  

    然后,来到index.js配置我们的映射关系。要注意使用懒加载哦。

  (注意是component不是components,这个小失误害我调试半天)

     接着,我们需要监听某个TabBarItem的点击,从而对应渲染出某个视图组件。

  我们完全可以在子组件TabBarItem.vue进行监听(而不是具体使用组件的那里监听,不然就得监听4次了),方法中使用绑定的path属性修改当前路径,即使用props往组件绑定属性(path属性)。然后在使用组件的时候(App.vue),传入路径path。路由模式也可以使用为history。

    (注意写上<router-view>不然不会显示组件)

  (点击购物车,路由跳转到购物车组件,主页显示购物车组件(里面只是简单的内容:购物车车),点击其他item也是有路由跳转到对应组件)

五、TabBarItem的颜色动态控制

  第三章,我们只讲到了状态isActive控制图片和文字是否处于激活状态的图片和文字。但我们通常是点击(激活)某个具体的item,让其处于激活,其他的item处于未激活。

  所以,状态isActive变量不能写死,需要动态传递。使用计算属性。通过结合$route(活跃路由对象,只有一个)及判断item路径和活跃路径对比来实现状态控制。注意取反哦。

  (TabBarItem.vue)

  (点击首页,首页被激活;点其他的也一样)

   现在还有一个问题(需求)。我们之前写的代码,点击的TabBarItem的文字部分的样式是直接写死的,即都是只能在活跃的时候显示红色,这个封装也是不够合理的。合理的组件封装应该不需要使用者修改组件源码的。

  所以我们希望别人在使用TabBarItem组件(App.vue中),就能自由选择想选的颜色。类似于下图用法,这样别人就不需要知道我们在TabBarItem组件设计时的源码是怎么写的了。

  

   首先,我们在props中写activeColor对象,里面有类型type和默认的颜色。

   

   然后用计算属性activeStyle,绑定动态的style。

   

    最后,在使用TabBarItem组件时,可以选择使用一些想选的颜色。也可以选择不选,则为默认颜色。

   (字体显示默认颜色)

  (字体,显示设定的蓝色)

六、进一步组件化

  我们可以看到,之前我们写了一大推代码在App.vue里面,其实还是可以进一步简化的。  

   首先,发现tab-bar组件内很多代码,我们可以把其封装成一个组件,最后在App.vue里面使用这个组件即可。这就是组件化开发,形成了组件树,根组件为App.vue,App.vue所引用的的组件是其子组件,子组件可能还引用了别的组件等。

  大致步骤:先在components/tabbar下创建MainTabBar.vue组件。然后把刚刚在App.vue里面写关于Tabbar的template和组件全部放在这个MainTabBar.vue组件内封装,注意修改文件的路径(或者使用本博客最后一点知识:给路径起别名的方式)。

  

   然后在App.vue中使用这个封装的MainTabBar.vue组件。这样App.vue的代码结构就很清晰好看了。

   最终的页面效果也是不变的。

  补充:给路径起别名。(webpack配置中的resolve对象的alias属性)

  之前发现,我们在复制一些代码到别的目录下时,一些资源文件的路径需要重新配置,非常的不方便。

  由于我们是用脚手架vue CLI来构建项目的,在build文件夹webpack.base.conf.js(公共基础配置)中,已经是有一些解决方案(resolve),如:

  

   其中,extensions的意思是,我们在引用一些文件、资源时,可以省略的扩展名。例如我们引用Home.vue这个组件,可以直接写成引用Home即可。

  alias是别名的意思。这里是给src起别名(src是源文件目录),起为@,意思是说在使用路径时,可以通过@代替src。也就是说当我们想使用某个文件资源时,以src(@)为路径去引用。这样的好处就是可以把某个组件使用到的路径直接复制使用到别的组件中,确保引入文件的路径是正确的。

  类似道理,我们把一些常用资源的文件路径给起别名,然后每次用的时候就方便很多了。常用的起别名有:

  (注意)

   当然还有其他路径,后面我们用到在添加。也就是说方便我们写项目代码的,就可以添加。

  但注意,import所导入的路径可以使用这种起别名的路径。而HTML标签内,如src属性,则需要在别名前加~(波浪号),不然找不到路径。

原文地址:https://www.cnblogs.com/xinkuiwu/p/12105791.html