三、开始完成首页的功能
3.1. 封装顶部NavBar组件
- 创建
NavBar组件 - 设置左中右三个插槽
- 配置基本样式属性
- 在首页home中导入
NavBar组件并注册 - 在home页顶部使用
<nav-bar>,并设置内容显示在中间插槽区域
3.2. 封装轮播图组件
- 创建
HomeSwiper、Swiper和SwiperItem组件 - 将
Swiper和SwiperItem组件都导入HomeSwiper组件中,并注册 - 将
HomeSwiper组件导入首页 Home 并注册,使用HomeSwiper组件
3.3 axios请求封装
- 安装axios和vue-axios,
npm install --save axios
- 创建并设置请求
request.js - 导入 axios ,配置请求
request - 创建
axios实例=>添加请求拦截器=>添加响应拦截器=>发送真实的网络请求
3.4 封装首页 home.js 的请求
- 导入
request.js请求配置文件 - 配置首页的
getHomeMultidata请求函数 - 首页加载
getHomeMultidata请求函数,来获得所有想要的数据
3.5 首页调用getHomeMultidata方法请求数据
- 导入
home.js请求文件 - 在
methods中创建getHomeMultidata方法,并在 生命周期函数created中调用 - 在
data中初始化banners数组 - 在
getHomeMultidata方法中拿到实际的banner图片的数据,并赋给data中的banners
3.6 完成轮播图功能(采用Swiper5轮播组件,对3.2进行重构)
- 创建 HomeSwiper 组件,并在首页轮播区导入、注册和使用
- 首页父组件将获取到的 banners 传给子组件 HomeSwiper
- 引入 Swiper4/5 轮播组件
安装 vue-awesome-swiper 轮播UI组件
npm install vue-awesome-swiper --save在 HomeSwiper 组件中局部注册,并引入组件
import { Swiper, SwiperSlide } from 'vue-awesome-swiper'
import 'swiper/css/swiper.css'
export default {
components: {
Swiper,
SwiperSlide
}
}
- 通过
v-for指令进行循环遍历SwiperSlide来显示banners中的数组值 - 每个遍历的
item中都可以拿到link和image,并创建<a>和<img>标签来显示内容 - 在
swiper标签中放入分页器
<div class="swiper-pagination" slot="pagination"></div>
- 在
data中设置轮播参数,分页器的参数
swiperOptions: {
loop: true,
effect: "coverflow", // 3d流
autoplay: {
delay: "2000",
disableOnInteraction: false
},
slidesPerView: 1,
grabCursor: true,
pagination: {
el: ".swiper-pagination",
clickable: true,
type: "bullets",
bulletClass: "swiper-pagination-bullet",
bulletActiveClass: "swiper-pagination-bullet-active"
}
}
- 完成轮播图的样式和分页器的样式
注意:想要查看当前Swiper实例对象必须要在updated(){}函数中去打印;如果是在mounted(){}会报错,找不到。
3.8 完成推荐 RecommendView 组件的内容
- 创建、导入、注册、使用该组件
- 在父组件中获取
recommends的数组数据并传给recommendview子组件 - 子组件将拿到的数据渲染到页面,并调试样式
3.9 完成每周流行PopularThisWeek组件的内容
- 创建、导入、注册、使用该组件
- 完成组件的内容和样式
3.10 完成TabControl组件的功能
- 创建、导入、注册、使用该组件
TabControl - 创建
props接收父组件传过来的titles参数,并用v-for遍历循环显示所有title - 通过绑定动态属性
:class:{active: index === currentIndex}来判断高亮显示 - 绑定点击事件
@click=“itemClick(index)”来判断点击的是哪个title标题,并将标题索引的值传给currentIndex
3.11 完成商品列表内容
创建
GoodsList和GoodsItem组件将
GoodsList组件导入 Home 中并注册和使用,将GoodsItem组件导入GoodsList中注册、使用-
在
home.js中封装用来请求商品数据的请求getHomeGoods-
type参数表示请求的是:流行、新款还是精选的商品数据 -
page参数表示请求的数据页数
-
初始化商品数据对象,在
data中创建goods对象,由pop、new和sele对象数据组成-
在
methods中创建请goods的方法getHomeGoods()- 定义
pages常亮,表示拿到的data中goods对象的对应type的那条数据 -
page是当前已加载的页面数量,并对其自动加1 - 在请求数据时获取的就是对应
type当前已加载页面的总数据
- 定义
-
将商品数据
goods数据传给子组件GoodsList,并完成子组件中 商品数据的 渲染- 定义
props中的goods数据 - 用
v-for遍历goods中的数据在GoodsItem组件上 - 完成
GoodsList组件中的样式
- 定义
-
将每个
item对象数据通过:goods-item属性传递给子组件GoodsItem- 完成
GoodsItem组件中的数据结构和样式的渲染 - 将图片数据通过计算属性中的
showImage()返回
- 完成
3.12 通过TabControl组件上的点击来实现商品列表的内容切换
- 在首页的
TabControl组件上绑定@tabclick点击事件 - 在
TabControl组件内的itemClick方法中使用$emit方法将获取的currentIndex的值传给@tabclick点击事件 - 在首页创建
tabClick()方法来监听点击的currentIndex索引的对应的title名,也就是currentType的值 -
tabClick()使用switch条件判断 - 创建 计算属性
showGoods()的值为, 对应点击this.currentType的goods的商品数据 -
showGoods()的值会通过绑定的:goods属性传递给子组件GoodsList - 由于进入首页时
TabControl是点击选中的第一tab位置,- 方法一:在
created函数中增加一次点击事件,即调用一次tabClick(0) - 因此在
tabClick()方法中需要通过if判断this.$refs.tabControl !== undefined - 方法二:在
mounted中进行点击就不需要if判断
- 方法一:在
3.13 使用 better-scroll 插件完成局部滚动
- 创建并引入
scroll组件
npm install better-scroll --save - 初始化代码,创建
BScroll对象,使用probeType参数来监听滚动 - 监听滚动事件并获取滚动的位置
position - 使用
pullUpLoad参数做上拉加载的功能- 判断
this.pullUpLoad是否为true,如果为true就使用on方法监听pullingUp事件 - 在首页该事件下调用加载更多方法
loadMore(),去掉getHomeGoods请求方法获取数据
- 判断
- 当上拉加载数据加载完毕后,需要调用
finishPullUp告诉better-scroll数据已加载
3.14 封装backtop组件,回到顶部
- 创建并引入
backTop组件 - 完成回到顶部的图片结构和样式
- 在首页通过
@click.native监听点击事件backClick()方法-
native修饰符:监听组件根元素的原生事件
-
- 在
scroll组件中封装scrollTo()方法,通过backClick方法去调用scrollTo方法回到顶部 - 在首页
backTop组件中 使用指令v-show来控制按钮的显示和隐藏- 定义
isShowBackTop初始化值为false - 并在
scroll组件上绑定contentScroll方法来实现:当滚动到某一位置时按钮显示,也就是-position.y > 1000时isShowBackTop为true
- 定义
3.15 解决部分图片未加载出来导致的滚动首页区域卡顿的问题

事件总线.png
-
使用事件总线技术:
- 在子组件中
GoodsItem通过this.$bus.$emit("事件名")发射事件给事件总线 - 再在首页中通过
this.$bus.$on("事件名", 回调函数)来监听事件总线
- 在子组件中
在
GoodsItem组件中使用@load="imageLoad"监听图片加载完成事件itemImageLoad通过
this.$bus.$emit("itemImageLoad")将其发送给事件总线在首页
mounted()中监听事件总线中itemImageLoad事件的变化,
this.$bus.$on("itemImageLoad", () => {})
注意:是在 mounted() 中调用而不是在 created() 中调用
- 此时需要在
main.js中创建一个原型属性Vue.prototype.$bus = new Vue(),给$bus赋值一个vue实例,他是可以作为事件总线的。那么就可用这个vue实例发射事件和监听事件 - 再在首页的
this.$bus.$on()中掉refresh()方法来重新拿到滚动区域的高度
3.16 防抖操作,解决refresh非常频繁调用的问题
- 创建防抖函数 debounce(){}
debounce(func, delay) {
let timer = null;
return function(...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
- 防抖函数起作用的过程:
- 如果我们直接执行
refresh,那么refresh函数会被执行30次 - 可以将
refresh函数传入debounce函数中,生成新的函数 - 之后在调用非常频繁的时候,就使用新生成的函数
- 而新生成的函数,并不会频繁调用,如果下一次执行来的非常快,那么会将上一次取消掉
- 如果我们直接执行
-
防抖的目的:为了让我们执行非常频繁的函数等一会,等一会是否还要执行该函数,如果要执行就合并到一起,一起等;等到
delay时间内没有下一次函数要执行,再真正执行某一个函数。这样可以该函数的执行频率很低。
3.17 TabControl 组件的吸顶效果
- 必须知道向上滚动多少,才会有吸顶效果
- 先获取到
TabControl的offsetTop-
this.$refs.centerTabcontrol.offsetTop该方式获取不到offsetTop,因为组件是没有offsetTop - 需要去获取组件里面的元素的
offsetTop值 - 所有的组件都有一个
$el属性,用来获取组件中的元素 - 但是在
mounted()函数中去获取offsetTop时首页的图片还未加载完,此时的值是不准确的
-
- 在首页轮播监控图片是否加载完
- 在组件
HomeSwiper中添加图片监控@Load=“imageLoad” - 在
methods中添加该imageLoad方法 - 将监听方法
swiperImageload发送给首页this.$emit(“swiperImageload”) - 为了防止有多张图片发送多次,使用
isload来做判断:通过if当已经发送过一次后,设置isload为true,就会停止发送swiperImageload
- 在组件
- 监听滚动,动态的改变
tabControl组件的样式- 如果通过
position: fixed来改变tabControl组件的样式来达到吸顶效果会有问题 - 问题1:下面的商品列表内容会突然上移;
- 问题2:
tabControl组件会随着滚动组件一起滚出屏幕
- 如果通过
- 通过在
navbar组件下面再复制一份tabControl组件,控制滚动时tabControl的显示隐藏- 设置一个
class:“top-tabcontrol”用来控制顶部的tabControl组件显示的样式 - 设置
isTabFixed: false用来判断当他为true时,顶部的tabControl组件显示 - 通过监听滚动位置函数
contentScroll(position)中判断滚动的位置是否大于tabOffsetTop,当滚动的位置大于tabOffsetTop时,顶部的tabControl显示
this.isTabFixed = -position.y > this.tabOffsetTop;- 为了保证吸顶后顶部的
tabControl的功能正常,需要在tabClick()中同样监控顶部的tabControl的点击,将index的值赋给currentIndex
- 设置一个
3.18 离开首页后再回来保持原来的位置
- 用户离开首页再回来,会重新回到首页顶部,这是应为离开首页后,首页被销毁执行了
destroyed()生命周期函数导致 - 此时需要在 App.vue 中
<router-view />前面包一个<keep-alive> - 当我们离开首页时,保存一个
saveY - 进来时,将位置设置为原来保存的位置
saveY信息即可 - 使用
deactivated(){}函数来记录离开首页时的位置this.saveY - 使用
activated(){}函数当回到首页时瞬间滚动到记录的this.saveY,并刷新让下次从新记录位置