三、开始完成首页的功能
3.1. 封装顶部NavBar组件
- 创建
NavBar
组件 - 设置左中右三个插槽
- 配置基本样式属性
- 在首页home中导入
NavBar
组件并注册 - 在home页顶部使用
,并设置内容显示在中间插槽区域
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
,并创建和
标签来显示内容
- 在
swiper
标签中放入分页器
- 在
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 解决部分图片未加载出来导致的滚动首页区域卡顿的问题
-
使用事件总线技术:
- 在子组件中
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 中
前面包一个 - 当我们离开首页时,保存一个
saveY
- 进来时,将位置设置为原来保存的位置
saveY
信息即可 - 使用
deactivated(){}
函数来记录离开首页时的位置this.saveY
- 使用
activated(){}
函数当回到首页时瞬间滚动到记录的this.saveY
,并刷新让下次从新记录位置