详情页实现思路
点击商品进去详情页,根据点击请求更加详细的信息,要传过来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