-
引入cssjavascript
- normalize.css
- base.css,在里面引用normalize.css
- 在app.vue引用base.css
-
建立页面home,category,cart,profilecss
-
router配置html
-
tabbaritemvue
难点在于判断item是否被点击java
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数据ios
//请求数据并保存 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数据axios
<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数据api
class:index==currentindex网络
Click:currentindex==indexapp
<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的滚动逻辑冲突了