-
引入css
- normalize.css
- base.css,在里面引用normalize.css
- 在app.vue引用base.css
-
创建页面home,category,cart,profile
-
router配置
-
tabbaritem
难点在于判断item是否被点击
isActive(){ return this.$route.path.indexOf('this.link')!=-1 }
点击后文字更改样式 activeStyle(){ return this.isActive?{'color':'#333'}:{} }
Request.js
import axios from 'axios'
export function request(config) {
// 1.创建axios的实例
const instance = axios.create({
baseURL: 'http://152.136.185.210:8000/api/h8',
timeout: 5000
})
// 2.axios的拦截器
// 2.1.请求拦截的作用
instance.interceptors.request.use(config => {
return config
}, err => {
// console.log(err);
})
// 2.2.响应拦截
instance.interceptors.response.use(res => {
return res.data
}, err => {
console.log(err);
})
// 3.发送真正的网络请求
return instance(config)
}
Home.js
import {request} from "./request";
export function getHomeMultidata() {
return request({
url: '/home/multidata'
})
}
export function getHomeGoods(type, page) {
return request({
url: '/home/data',
params: {
type,
page
}
})
}
在home.vue引用
import {getHomeMultidata} from "network/home";
swiper
需要banners和recommend数据
//请求数据并保存
created() {
getHomeMultidata().then(res => {
this.banners=res.data.banner.list
this.recommends=res.data.recommend.list
});
}
//把数据传到swiper组件
<home-swiper :banners="banners"></home-swiper>
homeswiper组件
<template>
<swiper ref="swiper"
v-if="banners.length">
<swiper-item v-for="(item,index) in banners" :key="index">
<a :href="item.link">
<img :src="item.image" alt="">
</a>
</swiper-item>
</swiper>
</template>
<script>
import {Swiper, SwiperItem} from 'common/swiper'
export default {
name: "HomeSwiper",
components: {
Swiper,
SwiperItem
}, props: {
banners: {
type: Array,
default: []
}
},
methods:{
stopTimer() {
this.$refs.swiper.stopTimer()
},
startTimer() {
if (this.$refs.swiper) {
this.$refs.swiper.startTimer()
}
}
}
}
</script>
<style scoped>
</style>
recommendView
需要recommend数据
<template>
<div class="recommend">
<div v-for="item in recommends" class="recommed-item">
<a href="item.link">
<img :src="item.image" alt="">
<div>{{item.title}}</div>
</a>
</div>
</div>
</template>
<script>
export default {
name: "RecommendView",
props: {
recommends: {
type: Array,
default: []
}
}
}
</script>
<style scoped>
.recommend {
display: flex;
justify-content: space-around;
text-align: center;
padding-bottom: 20px;
border-bottom: 10px solid #eee;
}
.recommed-item img {
margin-top: 10px;
margin-bottom: 5px;
height: 70px;
width: 70px;
flex: 1;
}
</style>
featureView
<template>
<div class="feature">
<a href="https://act.mogujie.com/zzlx67">
<img src="~assets/img/home/recommend_bg.jpg" alt="">
</a>
</div>
</template>
<script>
export default {
name: "FeatureView"
}
</script>
<style scoped>
.feature img{
width: 100%;
}
</style>
tabControl
需要titles数据
class:index==currentindex
Click:currentindex==index
<template>
<div class="tab-control">
<div v-for="(item,index) in titles" class="tab-control-item"
:class="{active:index==currentIndex}"
@click="itemClick(index)">
<span>{{item}}</span>
</div>
</div>
</template>
<script>
export default {
name: "TabControl",
props: {
titles: {
type: Array,
default: []
}
},
data() {
return {
currentIndex: 0
}
},
methods: {
itemClick(index) {
this.currentIndex = index
}
}
}
</script>
<style scoped>
.active span{
color: #ff8198;
border-bottom: 2px solid #ff8198;
}
.tab-control {
display: flex;
text-align: center;
}
.tab-control-item {
height: 40px;
line-height: 40px;
flex: 1;
}
.tab-control-item span {
font-size: 17px;
padding: 5px;
}
</style>
商品展示
需要流行,精选数据
- 请求数据
export function getHomeGoods(type, page) {
return request({
url: '/home/data',
params: {
type,
page
}
})
}
把请求方法写在methods,create调用methiods方法
import {getHomeMultidata, getHomeGoods} from "network/home";
created() {
this.getHomeMultidata()
this.getHomeGoods('pop')
this.getHomeGoods('new')
this.getHomeGoods('sell')
}, methods: {
getHomeGoods(type) {
const page = this.goods[type].page + 1
getHomeGoods(type, page).then(res => {
console.log(res)
this.goods[type].list.push(...res.data.list)
this.goods[type].page += 1
})
},
getHomeMultidata() {
getHomeMultidata().then(res => {
console.log(res)
this.banners = res.data.banner.list
this.recommends = res.data.recommend.list
})
}
}
goodsLIst
需要goods['type'].list数据
flex-wrap:wrap
<template>
<div class="goods-list">
<goods-list-item v-for="item in goodsList" :goodsItem="item"></goods-list-item>
</div>
</template>
<script>
import GoodsListItem from "./GoodsListItem";
export default {
name: "GoodsList",
components: {
GoodsListItem
}, props: {
goodsList: {
type: Array,
default: []
}
}
}
</script>
<style scoped>
.goods-list {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
padding: 2px;
}
</style>
goodsListItem
设置宽度,才能用flex-wrap
<template>
<div class="goods-item">
<img :src="goodsItem.show.img" alt="">
<div class="goods-info">
<p>{{goodsItem.title}}</p>
<span class="price">{{goodsItem.price}}</span>
<span class="collect">{{goodsItem.cfav}}</span>
</div>
</div>
</template>
<script>
export default {
name: "GoodsListItem",
props: {
goodsItem: {
type: Object,
default() {
return {}
}
}
}
}
</script>
<style scoped>
.goods-item {
padding-bottom: 40px;
position: relative;
width: 48%;
}
.goods-item img {
width: 100%;
border-radius: 5px;
}
.goods-info {
font-size: 12px;
position: absolute;
bottom: 5px;
left: 0;
right: 0;
overflow: hidden;
text-align: center;
}
.goods-info p {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-bottom: 3px;
}
.goods-info .price {
color: var(--color-high-text);
margin-right: 20px;
}
.goods-info .collect {
position: relative;
}
.goods-info .collect::before {
content: '';
position: absolute;
left: -15px;
top: -1px;
width: 14px;
height: 14px;
background: url("~assets/img/common/collect.svg") 0 0/14px 14px;
}
</style>
tabControl切换数据
点击切换流行 ,新款的数据
在scroll组件要设置clck:true,不然div等标签监听不到点击
tabcontrol发送自定义事件,并传到Home当前index,Home然后根据index来switch选择是pop还是new
<tab-control :titles="['流行','新款','精选']" @tabClick="tabClick"></tab-control>
<goods-list :goodsList="showGoods"></goods-list>
tabClick(index) {
switch (index) {
case 0:
this.currentTab = 'pop';
break
case 1:
this.currentTab = 'new';
break
case 2:
this.currentTab = 'sell';
break
}
}
computed:{
showGoods() {
return this.goods[this.currentTab].list
}
}
better-scroll
要在mount里创建对象
mounted(){
this.scroll = new BScroll(document.querySelector('.wrapper'),{
probeTybe:3,
pullUpload:true,
})
this.scroll.on('scroll',(position) => {
console.log(position)
})
this.scroll.on('pullingUp',() =>{
console.log('上拉加载更多')
setTimeOut(() =>{
scroll.finishPullUp()
},2000)
})
}
Wrapper要有固定高度,它的子标签只能有一个
注意它的父标签的高度
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.content {
height: 200px;
background-color: red;
overflow: hidden;
}
</style>
</head>
<body>
<div>
<div class="content">
<ul>
<button class="btn">按钮</button>
<li>列表数据1</li>
<li>列表数据2</li>
<li>列表数据3</li>
<li>列表数据4</li>
<li>列表数据5</li>
<li>列表数据6</li>
<li>列表数据7</li>
<li>列表数据8</li>
<li>列表数据9</li>
<li>列表数据10</li>
<li>列表数据11</li>
<li>列表数据12</li>
<li>列表数据13</li>
<li>列表数据14</li>
<li>列表数据15</li>
<li>列表数据16</li>
<li>列表数据17</li>
<li>列表数据18</li>
<li>列表数据19</li>
<li>列表数据20</li>
<li>列表数据21</li>
<li>列表数据22</li>
<li>列表数据23</li>
<li>列表数据24</li>
<li>列表数据25</li>
<li>列表数据26</li>
<li>列表数据27</li>
<li>列表数据28</li>
<li>列表数据29</li>
<li>列表数据30</li>
<li>列表数据31</li>
<li>列表数据32</li>
<li>列表数据33</li>
<li>列表数据34</li>
<li>列表数据35</li>
<li>列表数据36</li>
<li>列表数据37</li>
<li>列表数据38</li>
<li>列表数据39</li>
<li>列表数据40</li>
<li>列表数据41</li>
<li>列表数据42</li>
<li>列表数据43</li>
</ul>
</div>
</div>
<script src="./bscroll.js"></script>
<script>
// 默认情况下BScroll是不可以实时的监听滚动位置
// probe 侦测
// 0,1都是不侦测实时的位置
// 2: 在手指滚动的过程中侦测, 手指离开后的惯性滚动过程中不侦测.
// 3: 只要是滚动, 都侦测.
const bscroll = new BScroll(document.querySelector('.content'), {
probeType: 3,
click: true,
pullUpLoad: true
})
bscroll.on('scroll', (position) => {
// console.log(position);
})
bscroll.on('pullingUp', () => {
console.log('上拉加载更多');
// 发送网络请求, 请求更多页的数据
// 等数据请求完成, 并且将新的数据展示出来后
setTimeout(() => {
bscroll.finishPullUp()
}, 2000)
})
document.querySelector('.btn').addEventListener('click', function () {
console.log('------');
})
</script>
</body>
</html>
封装better-scroll
<template>
<div ref="wrapper">
<div class="content">
<slot></slot>
</div>
</div>
</template>
<script>
import bscroll from 'better-scroll'
export default {
name: "Scroll",
components:{
scroll
},
data() {
return {
scroll:null,
}
},
mounted() {
this.scroll=new bscroll(this.$refs.wrapper,{
probeType:3,
pullUpLoad:true
})
this.scroll.on('scroll',(position) => {
console.log(position);
})
}
}
</script>
<style scoped>
</style>
backTop
//注意直接监听组件的原生事件,要有native
<back-top @click.native="backTopClick"></back-top>
实时判断是否显示backtop
先把scroll组件里的position信息发到home,因为在home里可以方便的管理backtop是否显示
this.scroll.on('scroll', (position) => {
this.$emit('scroll',position)
})
<scroll class="content" ref="wrapper" :probe-type="3" @scroll="contentScroll">
注意,position是负数,要把它换成正数计算
contentScroll(position) {
console.log(position)
this.isShowBackTop = -position.y > 1000
}
<back-top @click.native="backTopClick" v-show="isShowBackTop"></back-top>
上拉加载更多
this.scroll.on('pullingUp',() => {
this.$emit('pullingUp');
})
<scroll class="content" ref="wrapper" :probe-type="3" @scroll="contentScroll"
:pull-up-load="true"
@pullingUp="loadMore">
//没事做可以封装一下这个方法
finishPullUp() {
this.scroll.finishPullUp();
}
loadMore() {
this.getHomeGoods(this.currentTab);
this.$refs.wrapper.finishPullUp();
}
可滚动区域的问题
问题原因:没请求到图片时把可滚动区域计算好了,请求完图片,可滚动区域就不够了
解决办法:监听图片加载完就重新计算可滚动区域
Vue.prototype.$bus = new Vue()
imgLoad() {
this.$bus.$emit('imgLoad')
}
this.$bus.$on('imgLoad', () => {
this.$refs.wrapper.refresh()
})
可能出现的问题:
问题1:加载完图片,scroll对象还没创建好,但是home就调用scroll的refresh方法,导致报错
解决办法1:
调用方法前判断对象是否为空
this.scroll && this.scroll.refresh()
解决办法2:
也有可能是create里面拿不到this.$refs.wrapper,那么就去mounted里调用方法
mounted() {
this.$bus.$on('imgLoad', () => {
this.$refs.wrapper.refresh()
})
}
防抖函数提升性能
debounce(func, delay) {
let timer = null;
return function (...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(...args)
}, delay);
}
}
mounted() {
const refresh = this.debounce(this.$refs.wrapper.refresh, 50)
this.$bus.$on('imgLoad', () => {
refresh()
})
}
没事做可以抽取一下debounce
export function mounted() {
const refresh = this.debounce(this.$refs.wrapper.refresh, 50)
this.$bus.$on('imgLoad', () => {
refresh()
})
}
import {debounce} from "common/util";
tabControl吸顶效果
解决思路:
拿到tabcontrol的offsettop
存在的问题:图片没加载完,拿到offsettop可能是错的
console.log(this.$refs.tabControl.$el.offsetTop);
监听图片加载完,在发出自定义事件,
data() {
return {
isImgLoad:false
}
},
//这样只发送一次事件
imgLoad() {
if (!this.isImgLoad) {
this.$emit('imgLoad');
this.isImgLoad=true
}
}
imgLoad() {
this.tabControlOffsetTop = this.$refs.tabControl.$el.offsetTop;
}
contentScroll(position) {
//判断显示返回顶部的组件
this.isShowBackTop = -position.y > 1000
//判断是否吸顶
this.isTabFixed = -position.y > this.tabControlOffsetTop
console.log(this.isTabFixed)
},
<tab-control :titles="['流行','新款','精选']" @tabClick="tabClick" ref="tabControl"
:class="{fixed : isTabFixed}"></tab-control>
//data数据
tabControlOffsetTop: 0,
isTabFixed: false,
.fixed {
position: fixed;
top: 44px;
left: 0;
right: 0;
}
存在的问题:这么做没有吸顶,因为和betterscroll的滚动逻辑冲突了
来源:oschina
链接:https://my.oschina.net/u/4243251/blog/4257845