如果想看该实战系列的其他内容,请移步至 Vue.js 实战系列之实现视频类WebApp的项目开发。
项目仓库地址,欢迎 Star
实现效果
模块开发
-
路由配置
当我们在创建一个复杂应用的时候,最开始应该做的不是具体业务功能,而是先捋顺整个应用的结构和思路,从路由入手就是一个很好的选择。
根据项目需求得知,该 WebApp 底部有5个 TabBar 组成,所以我们需要构建5个页面,分别是首页、朋友、发布、消息、我的。而且底部 TabBar 在每个页面都有,所以我的做法是创建一个根页面,在这个页面通过子路由的方式加载各个主页。
修改 router/index.js 文件进行路由配置:
import Vue from 'vue'; import VueRouter from 'vue-router'; import Home from '../views/Home.vue'; Vue.use(VueRouter); const routes = [ { path: '/', redirect: 'index', }, { path: '/', name: 'Home', component: Home, children: [ { path: '/index', name: 'index', component: () => import(/* webpackChunkName: "index" */ '../views/index/index.vue'), }, { path: '/friends', name: 'friends', component: () => import(/* webpackChunkName: "friends" */ '../views/friends/index.vue'), }, { path: '/news', name: 'news', component: () => import(/* webpackChunkName: "news" */ '../views/news/index.vue'), }, { path: '/mine', name: 'mine', component: () => import(/* webpackChunkName: "mine" */ '../views/mine/index.vue'), }, ], }, { path: '/release', name: 'release', component: () => import(/* webpackChunkName: "release" */ '../views/release/index.vue'), }, ]; const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes, }); export default router;
路由配置解释:
- 查看上面的路由配置可知:发布页面的路由并没有添加到主页的子路由中,这是因为发布页面不需要展示底部 TabBar 组件。
- 路由采用懒加载的方式引入
- 引入路由时有:
/* webpackChunkName: "index" */
,这个的作用就是修改打包之后的js文件名。 - 为什么使用嵌套路由?
很多时候我们的页面结构决定了我们可能需要嵌套路由,比如我们的当前项目,在进入主页之后有多个功能页面,然后当选择其中一个功能页面之后进入对应的页面,这个时候我们就可以用到嵌套路由。
官方文档中给我们提供了一个children
属性,这个属性是一个数组类型,里面实际放着一组路由;这个时候父子关系结构就出来了,所以children
属性里面的是路由相对来说是children
属性外部路由的子路由。 - 注意:以上路由配置的页面需提前创建好,否则会有报错。
-
底部导航栏TabBar实现
新建 Tabbar.vue 组件文件:
common/components/tab/Tabbar.vue
<template> <div class="tab-bar"> <div class="item" @click="changTab(0)"> <router-link to="/index" tag="span" :class="tabIndex === 0 ? 'active' : ''">首页</router-link> </div> <div class="item" @click="changTab(1)"> <router-link to="/friends" tag="span" :class="tabIndex === 1 ? 'active' : ''">朋友</router-link> </div> <div @click="changTab(0)"> <router-link to="/release" tag="span"> <img class="dy-btn" src="@/assets/images/dy-btn.png" alt="" /> </router-link> </div> <div class="item" @click="changTab(3)"> <router-link to="/news" tag="span" :class="tabIndex === 3 ? 'active' : ''">消息</router-link> </div> <div class="item" @click="changTab(4)"> <router-link to="/mine" tag="span" :class="tabIndex === 4 ? 'active' : ''">我的</router-link> </div> </div> </template> <script> export default { name: 'Tabbar', data() { return { tabIndex: 0, }; }, methods: { changTab(i) { this.tabIndex = i; }, }, }; </script> <style lang="less" scoped> .tab-bar { background: #000000; height: 50px; width: 100%; line-height: 50px; position: fixed; bottom: 0; left: 0; display: flex; justify-content: space-around; color: #cccccc; font-size: 16px; .item { flex: 1; text-align: center; font-weight: 500; } .active { color: #ffff; font-weight: 600; } .dy-btn { width: 50px; height: 30px; margin: 10px; } } </style>
-
封装TabBar组件
我们将上面的 Tabbar 组件进行拆分,使他变成一个复用性更高的组件。
先对 Tabbar 进行拆分,拆分成 TabBar 和 TabItem 两部分:
-
TabItem:作为 TabBar 的单个 tab,可以实现较高的复用性。
组件封装主要利用了 vue 的两个属性:
props
: 接收父组件给子组件的传值;
computed
:计算属性(当其依赖的属性的值发生变化时,计算属性会重新计算,反之,则使用缓存中的属性值)<template> <div class="item" @click="itemClick"> <router-link :to="navPath" tag="span" :class="isActive ? 'active' : ''" > {{ tabTitle }} <slot></slot> </router-link> </div> </template> <script> export default { props: { tabTitle: { type: String, default: '', }, navPath: { type: String, default: '/index', }, }, computed: { isActive() { return this.$route.path === this.navPath; }, }, methods: { itemClick() { console.log(this.$route.path); }, }, }; </script> <style lang="less" scoped> .item { flex: 1; text-align: center; font-weight: 500; } .active { color: #ffff; font-weight: 600; } </style>
-
TabBar :作为 TabItem 的父组件,对其进行使用。
<template> <div class="tab-bar"> <TabItem tab-title="首页" nav-path="/index"></TabItem> <TabItem tab-title="朋友" nav-path="/friends"></TabItem> <TabItem nav-path="/release"> <img class="dy-btn" src="@/assets/images/dy-btn.png" alt="" /> </TabItem> <TabItem tab-title="消息" nav-path="/news"></TabItem> <TabItem tab-title="我的" nav-path="/mine"></TabItem> </div> </template> <script> import TabItem from './TabItem.vue'; export default { name: 'Tabbar', components: { TabItem, }, }; </script> <style lang="less" scoped> .tab-bar { background: #000000; height: 50px; width: 100%; line-height: 50px; position: fixed; bottom: 0; left: 0; display: flex; justify-content: space-around; color: #cccccc; font-size: 16px; .dy-btn { width: 50px; height: 30px; margin: 10px; } } </style>
-
问题记录
注意:由于我们使用了 Eslint 进行规范检查,所以在项目开发过程中一定要注意代码规范,下面我注意总结了在开发过程中会碰到的几个代码规范问题。
-
Eslint 检测报错
error Expected linebreaks to be 'LF' but found 'CRLF' linebreak-style
原因:
项目代码做了eslint
的规范检查,规定了换行需要以Lunix系统的换行方式,Linux下只有换行LF,而在 window 下换行默认是 CRLF。解决方案:
在.eslintrc
文件rules
里面 配置"linebreak-style": ["error", "windows"]
或者linebreak-style': ["off", "windows"]
, 允许windows开发环境,记得重启项目。 -
Eslint 提示
Newline required at end of file but not found
原因:
根据报错的字面意思就是文件的末尾需要有空的一行。解决方案:
在最后加上一行空白就可以了。 -
Eslint 提示
Trailing spaces not allowed no-trailing-spaces
原因:
空格多了,需删除多余空格。解决方案:
删除多余的空格就可以了。
总结
-
本章节主要对底部状态栏TabBar进行组件开发,以及设置对应的路由配置。
-
对比模块开发中的第二、三部分 对TabBar实现 和 封装组件化处理,可以清晰的看出,使用组件化进行项目开发,可以简化代码以及提高代码的复用性,所以我们在项目开发中,应该尽可能的使用组件化进行开发。
-
总是提示错误,我们为什么还需要用 Eslint?
在开始写这部分代码之前,一直没有注意到使用 Eslint 来进行代码规范,在后面的代码开发过程中,开始逐渐意识到代码规范的重要性,养成一个良好的代码规范可以让我们的代码减少不必要的错误。
在团队协作时,良好的代码规范显得格外重要,因为这是保障一个团队代码风格相同、避免低级bug的途径之一。
使用 EsLint 工具和代码风格检测工具,可以辅助编码规范执行,有效控制代码质量。
关于 Eslint 具体的使用方法,请大家自行查阅。
上一章节: 2. 搭建项目基本骨架
下一章节: 4. 顶部导航条实现
项目整体介绍:Vue.js 项目实战之实现视频播放类WebApp的项目开发(仿抖音app)
项目仓库地址,欢迎 Star。
有任何问题欢迎评论区留言讨论。