详情页实现思路
点击商品进去详情页,根据点击请求更加详细的信息,要传过来goodsItem的iid,根据id去服务器请求更加详细的信息;配置路由映射关系,点击进行跳转,带参数传递跳转
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>
首页的位置保持不变
指定版本安装better-scroll npm install better-scroll@1.13.2 --save
用keep-alive标签把router-view标签包住,点击其他导航栏,再点击首页,自动回到顶部,不是因为创建了新的Home.vue,获取离开时滚动的位置,再次进入的时候设置保存的位置。【频繁切换还是会自动回到顶部???】
导航栏的封装
1.在childComps中创建组件DetailNavBar.vue,在组件中引入公共组件TabBar,替换TabBar组件中的插槽,在详情页Detail中引入封装好的导航栏DetailNavBar,
2.引入一个返回图标,绑定点击事件,点击之后会返回到之前进入的状态
3.将导航栏中的标题定义成数组titles然后遍历,进行flex布局
4.标题点击谁,谁就变成红色
** 定义一个当前索引currentIndex,动态绑定class,动态绑定点击事件 【此处是否可以直接引入tabControl组件??】
加入滚动的效果Scroll
1.指定版本安装better-scroll npm install better-scroll@1.13.2 --save
2.详情页的底部导航栏NavBar不用展示,可以给详情页相对布局并设置层级关系,给一个白色的背景色,详情页就可以脱离原来的标准流,把底部导航栏隐藏了
3.顶部的导航栏在DetailNavBar组件中设置相对定位层级关系和背景颜色
4.仍然选择better-scroll,引用之前封装好的Scroll,把要滚动的东西用scroll包裹住,替换Scroll里面的插槽
5.scroll需要有固定的高度,让父元素有100%的视口高度
一、滚动的问题
推荐数据使用goodslistitem展示时,用了load监听,图片加载完了会通知首页,但是我们不需要通知首页。我们需要区分。发出事件的时候做一下路由判断。
imageLoad(){
if(this.$router.path.indexOf('/home')){
this.$bus.$emit('homeItemImageLoad')
} else if(this.$router.path.indexOf('/detail')){
this.$bus.$emit('detailItemImageLoad')
}
},
再在详情页监听图片是否加载完成,但是最后离开的时候还是要取消
详情数据请求
1.保存从首页商品展示传入的iid
2.根据iid请求详情数据
** 在network的detail.js中封装getDetail,发出网络请求
一、轮播图的封装
- 在childComps中创建组件DetailSwiper.vue,在组件中引入公共组件Swiper,SwiperItem,在详情页Detail中引入封装好的DetailSwiper
- 根据请求到的数据topImages轮播展示商品,定义了一个变量,把topImages进行保存,图片太大了,给swiper设置固定的高度
二、商品基本信息的封装
- 抽离组件需要的数据,再把抽离的数据传给组件,把杂乱的数据整合成一个对象,导出class类对象Goods保存的一些商品信息
- 在childComps中创建组件DetailBaseInfo.vue,封装一些商品基本信息,在详情页Detail中引入封装好的DetailBaseInfo
- 要先判断是否有商品信息,有再渲染,怎么判断呢?
v-if="Object.keys(goods).length !== 0"
看goods是不是一个空的对象
三、商家基本信息的封装
- 导出class类对象Shop保存的一些商品信息
- 在childComps中创建组件DetailShopInfo.vue,封装一些商家信息,在详情页Detail中引入封装好的DetailShopInfo
- 在显示总销量时,有个过滤器
filters: {
sellCountFilter: function (value) {
if (value < 10000) return value;
return (value/10000).toFixed(1) + '万'
}
}
四、商品详情的封装
- 在childComps中创建组件DetailGoodsInfo.vue,封装一些商品详细信息,在详情页Detail中引入封装好的DetailGoodsInfo
- 在滚动的过程中,可能出现不能滚动的现象,是因为better-scroll在计算滚动区域时,图片还没加载出来,所以需要先监听图片是否加载完成
- 首页要获取图片的个数,然后定义一个计数变量,当两者相等时,就可以发出图片加载完成的事件,
- 在详情页面中,对滚动区域进行刷新
// 监听detailInfo这个对象的变化
watch:{
detailInfo(){
//获取图片的个数
this.imageLength=this.detailInfo.detailImage[0].list.length
}
},
methods: {
imageLoad(){
// 先判断一下,只发出一次事件,不然有几张图片就发出几次事件
// 所有的图片都加载完成之后,进行一次回调
if(++this.counter===this.imageLength){
this.$emit('imageLoad')
}
}
},
五、商品参数的封装
- 导出class类对象GoodsParam保存的一些商品参数信息
- 在childComps中创建组件DetailParamInfo.vue,封装一些商品参数信息,在详情页Detail中引入封装好的DetailParamInfo
- 参数用table布局
六、商品评论信息的封装
- 评论信息的获取
** 在接口的result->rate里面
** cRate 当前商品一共有多少评论 点击更多按钮跳转到另一个页面 展示更多评论信息
** list[0] 取出一条评论信息在详情页进行展示
** 定义commentInfo对象 保存取出来的评论信息 有可能没有评论信息 先判断 - 评论信息的展示
** 在childComps中创建组件DetailCommentInfo.vue,封装一些评论信息,在详情页Detail中引入封装好的DetailCommentInfo
** 过滤器将时间格式化 formatDate 从utils中引入
filters: {
showDate: function (value) {
// 将时间戳转成Date对象
let date = new Date(value*1000);
// 将date进行格式化
return formatDate(date, 'yyyy/MM/dd')
}
}
七、商品推荐信息的封装
- 推荐数据的获取
** 在detail.js中弄一个接口,不用传参数
export function getRecommend() {
return request({
url: '/recommend',
})
}
** 在详情页中将接口函数导入,定义一个recommends数组,在created中请求推荐数据
- 推荐数据的展示
** 不需要创建一个新的子组件,可以直接用之前的GoodsList组件,
** 在详情页中导入GoodsList组件并注册使用
** 弄个计算属性computed,取展示的图片数据
首页和详情页监听全局事件的mixin的使用
** mixin 混入
底部工具栏
一、底部工具栏的封装
二、将商品添加到购物车
** 1.给“加入购物车”添加点击事件,发送一个事件,因为是在子组件中监听,
** 2.在详情页中监听点击,先获取商品的信息,这些信息要展示在购物车页面中;
** 3.将商品添加进购物车,在详情页将商品添加到某个位置,在购物车界面将信息进行展示,用到vuex
addToCart(){
// 1.获取购物车需要展示的信息
const product={}
product.image=this.topImages[0]
product.title=this.goods.title
product.desc=this.goods.desc
product.cartPrice=this.goods.cartPrice
product.iid=this.iid
// 2.将商品添加到购物车
this.$store.dispatch('addCart',product)
}
三、将商品添加到store中
** 0.安装vuex npm install vuex --save
** 1.在文件夹store中新建一个文件,导入vue,vuex,安装插件,创建store对象,挂载到Vue实例上,在main.js中导入store
** 2.定义一个数组变量cartList在其中存放商品,修改任何state中的状态都要通过mutations,mutations中每一个方法完成的事件尽可能单一
[ADD_COUNTER](state, payload) {
payload.count++;
},
[ADD_TO_CART](state, payload) {
state.cartList.push(payload);
}
** 3.逻辑判断在actions中
addCart(context, payload) {
// 1.查找之前的数组中是否有该商品
let oldProduct = context.state.cartList.find(
item => item.iid === payload.iid
);
// 2.判断oldProduct
if (oldProduct) {
context.commit(ADD_COUNTER, oldProduct);
} else {
payload.count = 1;
context.commit(ADD_TO_CART, payload);
}
}
四、添加购物车弹窗
** 1.在components的common文件夹中新建一个toast文件夹,因为还可以在其他项目中使用,创建一个Toast组件,
** 2.让弹窗垂直水平居中布局,
** 3.控制弹窗的显示和隐藏,v-show定义一个变量isShow,默认不显示,属性值设置为false,还定义个弹窗显示内容的变量message,点击“加入购物车”后显示,过一会儿就隐藏,使用定时器
** 4.在Detail组件中导入,注册并使用
** 5.点击“加入购物车”后显示,过一会儿就隐藏,使用定时器
if (oldProduct) {
context.commit(ADD_COUNTER, oldProduct);
resolve('当前的商品数量+1')
} else {
payload.count = 1;
context.commit(ADD_TO_CART, payload);
resolve('添加购物车成功')
}
this.$store.dispatch('addCart',product).then(res=>{
this.isShow=true;
this.message=res
setTimeout(() => {
this.isShow=false;
this.message=''
}, 1500);
另一种封装:
** 0.把这个组件封装在一个插件里面,先创建这个组件,最开始的时候就把这个组件添加进body里面,然后安装这个插件,安装这个插件就预备好了
** 1.在main.js文件里面导入toast,安装插件,执行install函数,
** 2.在toast文件夹里面新建index文件,在index中导入Toast组件,在install函数里面把需要的东西预备好
obj.install=function(Vue){
// 1.创建组件构造器
const toastContrustor = Vue.extend(Toast)
// 2.new的方式,根据组件构造器,可以创建一个组件对象
const toast = new toastContrustor()
// 3.将组件对象,手动挂载到某一个元素上
toast.$mount(document.createElement('div'))
// 4.toast.$el对应的就是div
document.body.appendChild(toast.$el)
Vue.prototype.$toast = toast
}
** 3.在Toast组件中写一个show方法
show(message,duration=2000){
// duration=duration || 3000
this.isShow=true;
this.message=message
setTimeout(() => {
this.isShow=false;
this.message=''
}, duration);
}
** 4.在Detail组件中调用show方法
this.$store.dispatch('addCart',product).then(res=>{
this.$toast.show(res,2000)
})
转载:https://blog.csdn.net/qq_41217480/article/details/105632335