Vue商城——首页功能
Vue商城项目的前提工作
用脚手架3创建项目
- vue create 项目名称
在GitHub上建一个仓库
将项目与github联系起来
- git init
- git add .
- git commit -m ‘项目名称’
- git remote add origin github地址
- git push -u origin master
更新文件到github
git add 文件名称或者 git add .
git commit -m “这是注释内容”
这一步从本地仓库或本地分支获取并集成(整合),输入指令:git pull origin master
如果过程中出现‘please enter a commit message…’,首先按下esc退出键然后输入 :wq即可
输入指令:git push -u origin master
划分目录结构
- src
- assets 放一些资源
- css
- img
- components 放一些公共的组件
- common 当前项目里面可以使用的组件 在下一个项目里面也可以使用的组件
- content 与业务相关的组件 只针对于当前项目来说是公共的
- views 对应视图的一些逻辑
- router 路由相关的东西
- store 公共状态的管理 vuex
- network 网络相关的
- common 公共的js文件
- const.js 公共常量
- utils.js 工具函数
- mixin.js 一些混入
- assets 放一些资源
引入css文件
一般开发的是一个前端项目的话,会对项目里面很多css进行初始化
- normalize.css 对浏览器上的很多标签进行统一 在github上搜索 文件链接
- base.css 这是属于自己的css
配置别名
在vue.config.js中配置别名
首页功能的实现
项目模块划分
在components/common封装tabbar
在components/content封装mainTabbar
npm install vue-router --save
- 在router的index.js中配置路由映射关系
对组件进行懒加载 - 在main.js中挂载
请求首页的多个数据
npm install axios --save
安装框架- 在network文件夹下新建request.js
import axios from 'axios'
导入
注意:这里写的是export而不是export default,为什么?
因为export default只能暴露一个对象,而export 可以暴露多个对象,以后需要用到多个的话就可以- 在network文件夹下新建home.js获取首页所需数据的api
- 在Home组件中面向home.js进行开发,首页创建好之后就发送网络请求在create中
- 在data中保存数据
网络模块的封装
network->request.js
第一层是工具函数层,封装一个通用的axios,创建一个实例,包括请求的基本路径,请求拦截器,响应拦截器。
export function request(config) {// 创建axios实例const instance = axios.create({// 默认是get请求// 支持跨域 jsonp 在url后面写上callback// 这个接口不支持postbaseURL: "http://123.207.32.32:8000",timeout: 5000,})// 请求的拦截器instance.interceptors.request.use(config => {// 比如config中的一些信息不符合服务器的请求// 比如每次发送网络请求时,都希望界面中显示一个请求的图标// 某些网络请求(比如登录),需要携带一些信息return config}, err => {console.log(err);})// 响应的拦截器instance.interceptors.response.use(res => {return res}, err => {console.log(err);})//发送真正的网络请求return instance(config)
}
首页面向request发送网络请求
network->home.js
第二层封装,接口层,对首页所有数据的请求都在home.js中,统一管理。
export function getHomeMultidata(){return request({url:'/home/multidata'})
}
第三层,调用层,Home.vue中,首页创建完就进行网络请求
getHomeMultidata(){getHomeMultidata().then(res=>{//console.log(res);// result在组件中,会一直存在,保存在data中//this.result=res;this.banners=res.data.data.banner.list;// 轮播图this.recommends=res.data.data.recommend.list; // 推荐信息})},
导航栏的封装和使用
- 在common中封装NavBar,使用具名插槽
- 在Home中引入封装好的组件
NavBar的封装
<template><div class="nav-bar"><div class="left"><slot name="left"></slot></div><div class="center"><slot name="center"></slot></div><div class="right"><slot name="right"></slot></div></div>
</template>
在Home.vue中的使用
固定在顶部,不跟随滚动条滚动
<nav-bar class="home-nav"><div slot="center">购物街</div>
</nav-bar>
轮播图的封装和使用
- 在componets/common下新建swiper文件下,封装Swiper和SwiperItem
- 在home/childComps下封装HomeSwiper组件,
- 在Home中引入封装好的组件
- 展示轮播图数据banners
推荐信息的展示
- 在home/childComps下封装HomeRecommendView组件
- 在Home中引入封装好的组件
- 展示推荐信息的数据recommend
<div class="recommend"><div v-for="(item,index) in recommends" :key="index" class="recommend-item"><a :href="item.link"><img :src="item.image" alt=""><div>{{item.title}}</div></a></div></div>
FeatureView的封装
- 独立组件封装。在home/childComps下封装FeatureView组件
- 放的是一张图片 div>a>img
TabControl选项卡的封装
- 在componets/content下封装TabControl,只是文字不一样的时候,就没必要弄插槽了
- props->titles div->根据titles v-for遍历 div->span{{title}}
- flex布局,均等分
- 选中谁,谁就变红色
在data中弄一个变量currentIndex来记录当前谁被选中;
动态绑定class属性,:class="{active:index == currentIndex}"
,默认第一个选中变红色; - 点击谁的时候,谁就变,监听item的点击,绑定点击事件
@click="itemClick(index)"
itemClick(index){this.currentIndex=index;}
- 吸顶效果,监听滚动,当滚动到一定位置的时候,将position设置成fixed,向下滚动的时候把fixed属性删除,就可以随着一起滚动了。
position:sticky;
必须设置top值,这个属性的作用是 在没有达到top值之前,position是sticky,达到之后改成fixed,但是很多浏览器不兼容这个属性。
商品列表数据的请求和展示
- 请求商品数据,既要展示流行数据,又要展示新款数据,还要展示精选数据,根据不同的点击,展示不同的数据
- 用变量保存数据,一次性把三个数据请求一下,在data中定义
要先考虑设计什么数据结构,然后再去使用
有自己对应的页码和数据,page用来记录当前加载到第几页了,list用来保存数据
goods:{'pop':{page:0,list:[]},'new':{page:0,list:[]},'sell':{page:0,list:[]},},
- 在network的
home.js
中获取商品所需数据的api,getHomeGoods
export function getHomeGoods(type,page) {return request({url: '/home/data',params:{type,page}})
}
- 在Home的
create
中请求商品数据
默认情况下先加载第一页的数据,在以后的上拉加载更多的操作下再去请求更多的数据。
getHomeGoods(type){const page=this.goods[type].page + 1;getHomeGoods(type,page).then(res=>{//对象中的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中this.goods[type].list.push(...res.data.data.list);this.goods[type].page += 1;})
},
- 在components/content下新建goods文件夹,在里面封装GoodsList.vue和GoodsListItem.vue,从某一个类型中取出商品的list传给GoodsList,然后遍历出小的item传给GoodsListItem,让GoodsListItem展示商品
- 在GoodsList.vue中,定义props:goods,商品一行显示两个,用flex布局,给子item设置固定的宽度
.goods{display: flex;flex-wrap: wrap;justify-content: space-around;
}
- 在GoodsListItem.vue中,定义props:goodsItem,父组件向子组件传数据,用
props
TabControl点击切换商品
- 首先内部监听点击,将事件传到Home中去,之前点击的时候只是内部样式的改变,现在需要传递事件,子组件发生点击事件,将事件传给父组件,用自定义事件
$emit
,
methods: {itemClick(index){this.currentIndex=index;this.$emit('tabClick',index)}}
在父组件Home中监听事件,@tabClick="tabClick"
,根据监听决定goodslist显示商品的类型。
- 定义一个当前显示的商品类型,默认是pop,
currentType:'pop'
,根据点击切换显示类型
<goods-list :goods="goods[currentType].list"/>tabClick(index){switch (index) {case 0:this.currentType='pop'break;case 1:this.currentType='new'break;case 2:this.currentType='sell'break;}
}
:goods="goods[currentType].list"
这一串太长了,弄一个计算属性computed,来展示商品
<goods-list :goods="showGoods"/>computed: {showGoods(){return this.goods[this.currentType].list}},
吸顶效果
- 必须知道滚动到多少时,开始有吸顶效果,获取到
tabcontrol
的offsetTop
,在data
中保存tabOffsetTop:0
,为了能够拿到,绑定一个属性ref="tabControl"
,拿到组件,组件没有offsetTop属性,而是要拿到组件对应的元素,所有的组件都有一个属性$el
,用来获取组件中的元素,mounted
中DOM加载完毕,但是图片不一定加载完了,所以要等图片加载完了之后计算出一个最终的offsetTop
, - 监听轮播图是否加载完成,只需要发出一次事件,弄一个变量记录状态,和之前的防抖的区别
在HomeSwiper.vue中
<img :src="item.image" @load="imageLoad">data(){return{isLoad:false; // 只需要发出一次事件}},imageLoad(){if(!this.isLoad){this.$emit('swiperImageLoad');this.isLoad=true;}}
在Home.vue中
<home-swiper :banners="banners" @swiperImageLoad="swiperImageLoad"/>swiperImageLoad(){this.tabOffsetTop=this.$refs.tabControl.$el.offsetTop;},
- 监听滚动,动态改变tabControl的样式,弄一个变量,
isTabFixed:false
,默认情况下不吸顶,当滚动到一定位置的时候,改变状态,动态绑定class
<tab-control :titles="['流行','新款','精选']" @tabClick="tabClick"ref="tabControl" :class="{fixed:isTabFixed}"/>contentScroll(position){//1.判断回到顶部是否显示this.isShowBackTop = (-position.y) > 1000//2.判断tabControl是否吸顶this.isTabFixed = (-position.y) > this.tabOffsetTop},.fixed{position: fixed;left: 0;right: 0;top: 44px;
}
问题:这种方法下面的商品内容会一下子往上移,虽然tabControl设置了fixed,但是也随着better-scroll一起滚出去了,因为tabControl会脱标。better-scroll滚动是根据translate属性移动的,设置了fixed还是能跟着一起滚动。
可以把tabControl再复制一份,来实现停留效果。
但是选项卡会被标题导航给盖住。
标题购物车可以不定位,这样就不会脱标,使用定位是在用浏览器原生滚动的时候。复制的tabControl放到navbar的下面,此时在轮播图的后面,再设置相对定位给一个层级关系,相对定位是因为还在原来的位置。默认它是不显示的,v-show="isTabFixed"
,当滚动到一定位置的时候再显示,当滚动没有达到一定位置时,隐藏。
swiperImageLoad(){this.tabOffsetTop=this.$refs.tabControl2.$el.offsetTop;},
问题:现在两个tabControl并没有保持一致。
tabClick(index){switch (index) {case 0:this.currentType='pop'break;case 1:this.currentType='new'break;case 2:this.currentType='sell'break;}this.$refs.tabControl1.currentIndex=index;this.$refs.tabControl2.currentIndex=index;},
我们并不能保证用户点击的是哪一个,所以两个都要赋值。
当把项目部署到服务器之后,用手机端去请求网页的时候,样式各方面没什么问题,但是滚动的时候,没有一个滚动的时候的滑动效果,滑动的时候也很卡顿,此时用的是原生的滚动,什么是原生的滚动呢?当里面的内容超过了当前的窗口的时候,自动就可以滚动了。但是用在移动端,会非常卡顿。以前用
iScroll
来适配移动端的滚动,但是这个框架现在作者不更新了。better-scroll在iscroll基础上,还加入了一些c3的属性。可以实现移动端的顺滑滚动,还在顶部和底部都增加了弹簧效果。
原生的滚动
.content{height:150px;overflow-y:scroll;
}
Better-Scroll的安装和使用
npm install better-scroll --save
在外层弄一个wrapper,wrapper需要固定的高度,在 wrapper里面放内容content,只能是一个标签组成的content,它是父元素的第一个子元素,滚动的部分是content元素。
使用
import BScroll from 'better-scroll'
new BScroll(el,options)
el挂载一个要滚动的元素
new BScroll(document.querySelector('.wrapper'))
也可以直接传一个类,根据类型查找标签
new BScroll('.wrapper',{})
实时监听当前滚动到什么位置了
(默认情况下,BScroll不能实时监听滚动的位置)
需要设置一个属性probeType
probeType值为0,1 不侦测实时的位置
2 在手指滚动的过程中侦测,手指离开后的惯性滚动过程中不侦测
3 只要是在滚动,都侦测上拉加载更多 设置
pullUpLoad
为true,要调用finishPullUp
方法才能实现下一次的上拉加载更多
要监听什么时候滚动到最底部了滚动区域包裹的元素需要监听点击 ,设置
click
属性是true,better-scroll会阻止浏览器的原生 click 事件(现在好像可以了)
BScroll的基本使用
on方法
scroll事件 滚动的实时坐标
bscroll.on("scroll",(position)=>{console.log(position);
})
pullingUp 上拉加载更多
bscroll.on("pullingUp",()=>{// 发送网络请求,请求更多页数据// 等数据请求完,并且将新的数据展示出来后bscroll.finishPullUp(); // 因为只能上拉加载一次,执行完这个函数之后,才能进行下一次上拉加载更多
})
封装better-scroll与使用
- 在components/common下创建一个scroll文件夹,在里面封装Scroll
- 需要一个插槽
- 引入better-scroll,
- DOM被挂载时,初始化BScroll,
querySelector
不能明确的指定拿到的是哪个元素,绑定ref
属性。
例如在Home.vue中也有class=“wrapper”,在App.vue中也有class=“wrapper”,不知道到底取的是哪个,querySelector获取的可能是第一个。
ref如果绑定在组件中,
this.$refs.refname
获取到的是一个组件对象 。一般绑定在子组件。
ref如果绑定在普通的元素中,获取到的是一个元素
- home的高度太高了,相当于所有内容的高度,给一个100的视口高度,在Home中给滚动的区域content一个固定的高度
#home{height: 100vh;position: relative;
}
.content{overflow: hidden;position: absolute;top:44px;bottom: 49px;left:0;right:0;
}
可滚动区域的问题
在决定有多少区域可以滚动时,根据scrollerHeight属性决定的,scrollerHeight属性是根据放在better-scroll的content中的子组件的高度,
但是在首页中,刚开始在计算scrollerHeight属性时,是没有将图片计算在内的,后来图片加载进来之后有了新的高度,但是scrollHeight属性并没有更新。
监听每一张图片是否加载完成,只要有一个图片加载完成了,执行一次refresh()。
如何监听图片是否加载完成?
原生js img.οnlοad=function() {}
vue @load=‘方法’
事件总线:和vuex很像,不是管理状态的,而是管理事件的。因为涉及到非父子组件通信。
在GoodsListItem中监听图片是否加载完成,
<img :src="showImage" alt="" @load="imageLoad"">
imageLoad(){this.$bus.$emit('itemImageLoad')},
在main.js中
Vue.prototype.$bus=new Vue()
在Scroll中
refresh(){this.scroll && this.scroll.refresh && this.scroll.refresh()},
在Home.vue的mounted中接收事件总线,refresh会执行很多次
this.$bus.$on('itemImageLoad',()=>{this.$refs.scroll.refresh()})
刷新频繁防抖处理
debounce
如果直接执行refresh,会执行很多次,可以将refresh函数传到debounce函数中,生成一个新的函数,之后在调用非常频繁的时候,就用新生成的函数,而新生成的函数,并不会非常频繁的调用,如果下一次执行来的非常快,那么会将上一次取消掉。
在common/utils.js中封装防抖函数,
export function debounce(func, delay){let timer = null// ...可以传几个参数return function (...args) {if (timer) clearTimeout(timer)timer = setTimeout(() => {func.apply(this, args)}, delay);}
}
回到顶部
按钮的封装和使用
- 在components/content下创建一个backTop文件夹,在里面封装BackTop
- 在BackTop里面放一个图片,定位在右下角
- 在Home中引入,不需要放在滚动区域scroll中
- 在BackTop中监听回到顶部不太好,回到顶部需要拿到滚动区域scroll对象,所以监听回到顶部的点击事件放到Home中比较好
- 监听组件的点击事件,要调用
.native
修饰符(监听一个组件的原生事件时);也可以在BackTop.vue内部监听点击,用$emit传给父组件Home.vue。像button,div是可以直接监听点击的。组件不能直接监听点击。
<back-top @click.native="backTopClick"></back-top>
- 在Scroll中封装
scrollTo()
方法
scrollTo(x,y,time=300){this.scroll && this.scroll.scrollTo(x,y,time)},
- 给
<scroll>
绑定ref,拿到滚动的对象
backTopClick(){this.$refs.scroll.scrollTo(0,0,500)},
按钮的显示和隐藏
滚动到一定区域的时候才显示,回到的时候隐藏
- 在Scroll中监听滚动的位置,在props中定义probeType
props:{probeType:{type:Number,default:0,},
- 在Home中要监听scroll的实时滚动,不加冒号会把probe-type当成字符串
<scroll class="content"ref="scroll":probe-type="3">
- 在Scroll中要根据在不同地方的应用的时候,有没有传入probeType的值,决定别人要不要实时监听,在父组件中监听子组件传过来的自定义事件
@scroll="contentScroll"
if(this.probeType===2 || this.probeType === 3){this.scroll.on('scroll',(position)=>{this.$emit('scroll',position)})}
<scroll class="content"ref="scroll":probe-type="3"@scroll="contentScroll">
5.在Home中根据滚动的位置决定是否显示还是隐藏,用v-show
,默认一进去的时候是不显示的,isShowBackTop:false,
<back-top @click.native="backTopClick" v-show="isShowBackTop"></back-top>contentScroll(position){//1.判断回到顶部是否显示this.isShowBackTop = (-position.y) > 1000},
完成上拉加载更多
- 监听什么时候滚动到底部。在Scroll中,定义
pullUpLoad
属性,
props:{pullUpLoad:{type:Boolean,default:false}},
在Home.vue中
<scroll class="content"ref="scroll":probe-type="3"@scroll="contentScroll":pull-up-load="true">
在Scroll中,向父组件传递事件,pullingUp
在一次上拉加载的动作后,这个时机一般用来去后端请求数据。
if(this.pullUpLoad){this.scroll.on('pullingUp',()=>{this.$emit('pullingUp')})}
- 在Home的
<scroll>
中定义属性@pullingUp="loadMore"
,加载更多的时候是针对商品类型来加载的,选中谁就给谁上拉加载更多
<scroll class="content"ref="scroll":probe-type="3"@scroll="contentScroll":pull-up-load="true"@pullingUp="loadMore">loadMore(){//只能上拉加载一次this.getHomeGoods(this.currentType)},
但是此时只能上拉加载一次,在数据加载完成之后,调用finishPullUp
可以实现多次
getHomeGoods(type){const page=this.goods[type].page + 1;getHomeGoods(type,page).then(res=>{this.goods[type].list.push(...res.data.data.list)this.goods[type].page += 1//可以多次上拉加载this.$refs.scroll.finishPullUp()})},
Home离开时记录状态和位置
当滚动一半的时候,切换去了其他页面,再回到首页的时候,并没有保持在原来的位置,而是回到了顶部。
让Home不要随意销毁掉
使用keep-alive
<keep-alive><router-view/>
</keep-alive>
让Home保持原来的位置
离开时,保存一个位置信息saveY
进来时,将位置设置为原来保存的位置信息saveY即可
进来的时候可能刷新一下,不然可能会回到顶部
在Scroll.vue中
getCurrentY(){return this.scroll ? this.scroll.y : 0}
在Home.vue中
// 进来的时候设置位置
activated() {this.$refs.scroll.scrollTo(0,this.saveY,0)this.$refs.scroll.refresh();// 不然可能出现一些问题},// 离开的时候记录位置
deactivated() {this.saveY=this.$refs.scroll.getCurrentY()},
点击首页中的商品跳转到商品详情页
点击商品进去详情页,根据点击请求更加详细的信息,要传过来goodsItem的iid,根据id去服务器请求更加详细的信息;配置路由映射关系,点击进行跳转,带参数传递跳转。
在GoodsListItem中
itemClick(){this.$router.push('/detail/'+this.goodsItem.iid)/* this.$router.push({path:'/detail',query:{iid:this.goodsItem.iid}}) */}
但是获取到的iid在更换点击商品时没有改变,并没有发生新的请求,因为发生了路由跳转,router-view由keep-alive包着,不会每次销毁并重新创建,所以不会给iid给新的值,详情页不要使用keep-alive,使用exclude属性
<keep-alive exclude="Detail"><router-view></router-view>
</keep-alive>
Vue商城——首页功能相关推荐
- 【第九篇】商城系统-商城首页功能
一.商品上架功能 ElasticSearch实现商城系统中全文检索的流程. 1.商品ES模型 商品的映射关系 PUT product {"mappings": {"pro ...
- 基于vue2.0打造移动商城页面实践 vue实现商城购物车功能 基于Vue、Vuex、Vue-router实现的购物商城(原生切换动画)效果...
基于vue2.0打造移动商城页面实践 地址:https://www.jianshu.com/p/2129bc4d40e9 vue实现商城购物车功能 地址:http://www.jb51.net/art ...
- 淘淘商城第51讲——从商城首页跳转到搜索页面
通过上文的学习,我们已经学会了如何把商品数据导入到索引库中,本文我将会教大家如何从淘淘商城首页跳转到搜索页面. 我们要访问淘淘商城首页就得先启动Redis服务,大家根据自己使用的情况来启动,使用的是单 ...
- 大型多商户商城系统-功能表
下载 http://souhuai.oss-cn-hangzhou.aliyuncs.com/php/php_mall_232M.zip Mall商城篇 前台 页面 说明 商城首页 包括PC,H5( ...
- 简易的网上购物商城首页设计流程
这里写目录标题 前言 1 整体构造思想 2 设计前的摸索 3 网页顶端和导航栏的设计 4 nav导航栏的固定效果 5 轮播图部分 6 明星机型设计 7 精选配件设计 8 搜索欧珀区域 9 服务和售后区 ...
- 【40-系统性能压力测试基本概念-相关性能指标HPSTPSQPSRT-安装Jmeter教程-JMeter测试流程-线程组-取样器-监视器-测试商城首页-JMeter Address 占用的问题】
一.知识回顾 [0.三高商城系统的专题专栏都帮你整理好了,请点击这里!] [1-系统架构演进过程] [2-微服务系统架构需求] [3-高性能.高并发.高可用的三高商城系统项目介绍] [4-Linux云 ...
- 加速度jsudo:立创电子元器件商城网站功能测评
对于从事元器件的销售来说,最终的职业规划,都是希望能有个自己的公司.但是对于没有资金,人脉不广,又没有产品的人来说,要是搁在10年前,这实在是太难了.但是,这是21世纪,一切皆有可能.如果你会一点网络 ...
- 加速度jsudo:电子元器件商城网站功能测评——华强电子
华强电子成立于2003年,计划创业板上市,主要是为为客户提供现货采购.海外代购.BOM配单及PCB制板服务. 对于从事元器件的销售来说,最终的职业规划,都是希望能有个自己的公司.但是对于没有资金,人脉 ...
- 前端vue实现分页功能
前端Vue实现分页功能 我们都知道在spring boot项目中安装pagehelper可以实现分页功能,但是在vue中也能在前端实现分页. 1. 首先,在data中定义以下变量: data() {r ...
最新文章
- PHP函数库之BC高精确度函数库
- 2018/Province_Java_C/2/猴子分香蕉
- es 同义词 热更新 1.1版本
- Unity Android解决信息流广告关闭报错
- 操作系统复习题+最终版
- QT5开发及实例学习之十七Qt5双缓冲机制
- 09-Elasticsearch重要的系统配置
- 最新 UI 色彩渐变素材模板|设计师好帮手
- 建立高可用性的数据库群集
- Unicode编码详解
- 可变临时邮箱,亲测可用,附使用教程
- 苹果应用商店审核_苹果应用商店AppStore审核规则指南
- ubuntu防火墙安装arm架构说明
- 一元高次方程c语言实现,c语言实现一元二次方程求解
- C语言怎样提取一个数的十位个位百位千位
- java月份下拉菜单_实现一个日期下拉菜单
- JS逆向hook通用脚本合集
- python安装hyperlpr
- 理想评价鸿蒙系统,鸿蒙系统来了!前期如何发育?后期的潜力有多大?苹果真豁口了!...
- elk之拼音插件可选参数
热门文章
- w10桌面计算机图标箭头去除,Win10怎么去除桌面快捷方式图标左下角的小箭头
- Word无法打开该文件,因为文件格式与扩展名不匹配
- python辅助u盘数据恢复
- 读书笔记:杨家成的英语学习之路(附带作者人生感悟)
- PerformanceManagementSystem
- 25.JavaScript的Symbol类型、隐藏属性、全局注册表
- Intel(Altera)FPGA的SOF转JIC文件和下载详细教程
- 积水成渊之python——os.path.join()
- prometheus+alertmanager 企业微信告警
- C/C++ 下标运算符subscript、后缀表达式、正负下标