尚品汇(七)

一、分页静态组件(Pagination)

掌握自定义分页系统

1.分页器所需数据
(1)当前是第几页pageNo
(2)每页展示的数据条数pageSize
(3)一共有多少页total
(4)分页器连续页码个数pageCount
2.自定义分页器
先用模拟数据调试
(1)Pagination组件接收父组件的数据,computed计算出分页所需数据
(2)计算连续页面的起始数字和结束数字,连续的页码数必须有5个
3.页码的起始数字与结束数字在计算时可能出现的情况
特殊情况:总页数不足,即总页数小于连续的页码个数时,start=1,end=totalPage
正常情况下,计算出显示的连续数字。
但是,如果当前页是第一页(因为当前页码太小,计算出的start小于1),计算可能得到负数,此时要纠正负数。则将start=1,end=pageCount(连续页码数)
end大于totalPage,则将end=totalPage,start=totoalPage-pageCount+1
4.分页器动态展示
(1)数字1的展示,当start大于1的时候显示
(2)…的展示,当start>2的时候展示
(3)中间数字,遍历pageCount(连续页码数,数字,1-这个数字),使用v-if选择显示,只有当遍历的数字大于start时才会显示该数字
(4)…当end<totalPage-1时显示
(5)结尾数字的展示,当end<totalPage时展示
5.分页器添加类名,添加当前页的样式
6.滚动行为

二、产品详情页

详情数据获取

(1)当点击商品图片,使用声明式导航,携带商品id跳转至商品详情页

					<div class="p-img">
                    <!--商品的图片:需要路由跳转的时候,携带商品的ID-->
                    <router-link :to=" `/detail/${good.id}`  ">
                    <img  :src="good.defaultImg" /></router-link>
                 	 </div>

(2)在商品详情页面时,滚轮在顶部。


//第二步:暴露VueRouter类的实例
//对外暴露一个路由器,实质是VueRouter类的实例,一个路由器可以管理多个路由
const router = new VueRouter({
    //配置路由
    routes,
    //设置滚动条的位置
    scrollBehavior() {
        //滚动行为这个函数,需要有返回值,返回值为一个对象。
        //经常可以设置滚动条x|y位置 [x|y数值的设置一般最小是零]
        return { y: 0 };
    }
});

(3)api请求接口
(4)添加detail仓库(action mutation state)
(5)在index中引入、注册detail仓库
(6) 点击图片后,在Detail组件挂载完毕后,dispatch,获取产品详情信息
(7)仓库中进行操作,将信息存至detail中

1.产品详情展示动态
Deatail详情页:Detail中的结构,两个子组件

从vuex中获取数据,在仓库中的detail,返回数据时可以如下 防止浏览器报假错
 categoryView(state) {
          //研究这个问题:
          //起始状态:state.detailInfo起始状态空对象,空对象.categoryView->undefined
          //当服务器数据回来之后state.detailInfo,并非空对象,获取的即为服务器返回的数据{7个K}
          //当前属性值:服务器的数据有值,用服务器的。服务器数据没有回来至少有一个空对象兜底【不能undefined兜底】
          return state.detailInfo.categoryView || {}
     },

展示产品的名称、详情、价格

2.放大镜Zoom与兄弟组件ImageList(放大镜下边的滑块图片)

(1)兄弟组件通信,点击滑块中的图片,通过兄弟组件切换图片

ImageList

 <div
        class="swiper-slide"
        v-for="(slide, index) in skuInfo.skuImageList"
        :key="index"
      >
        <img
          :src="slide.imgUrl"
          :class="{ active: currentIndex == index }"
          @click="handler(index)"
        />
      </div>


 //小图的点击事件
    handler(index) {
      //修改响应式数据存储当前用户点击的索引值
      this.currentIndex = index;
      //全局事件总线,通知兄弟当前图片的索引值
      this.$bus.$emit("sendIndex", index);
    },

Zoom

 mounted() {
    //接受兄弟组件传递过来的索引值
    this.$bus.$on('sendIndex', (index) => {
      this.index = index;
    })
  }

放大镜功能的具体实现

   handler(e) {
      // 放大镜 鼠标始终在放大镜中心
// $ref获取的是dom对象
      //获取蒙板
      let mask = this.$refs.mask;
      let big = this.$refs.big;
      //计算蒙板的left|top数值 鼠标的水平位置 距离父盒子左边的值-自身蒙版宽度的一般
      let l = e.offsetX - mask.offsetWidth / 2;
      let t = e.offsetY - mask.offsetHeight / 2;
      //约束蒙板的上下左右范围 防止超出父盒子 盒子宽度为两个蒙版的宽度 高度也是
      if (l < 0) l = 0;
      if (l > mask.offsetWidth) l = mask.offsetWidth;
      if (t < 0) t = 0;
      if (t > mask.offsetHeight) t = mask.offsetHeight;
      mask.style.left = l + "px";
      mask.style.top = t + "px";
      // 设置放大后的图片的位置
      big.style.left = -2 * l + "px";
      big.style.top = -2 * t + "px";
    },

3.展示商品售卖属性
(1)展示商品售卖属性值

//商品销售属性列表的数据
     spuSaleAttrList() {
          return state.detailInfo.spuSaleAttrList || []
     }

选中属性的高亮显示

(2)商品售卖属性值排他操作

点谁谁亮,不点不亮

 <!--每一个销售属性的属性值的地方-->
                <dd
                  changepirce="0"
                  :class="{ active: saleAttrValue.isChecked == 1 }"
                  v-for="(
                    saleAttrValue
                  ) in saleAttr.spuSaleAttrValueList"
                  :key="saleAttrValue.id"
                  @click="
                    changeChecked(saleAttrValue, saleAttr.spuSaleAttrValueList)
                  "
                >
//第一个参数是当前点击的对象
//将所有的对象取消高亮操作,给当前点击的对象设置高亮,此时实现了排他操作
  changeChecked(saleAttrValue, arr) {
      console.log(this.skuInfo);
      //响应式数据:对象、数组
      //数组的响应式数据:变更、替换【基本类型数据、引用类型对象响应式的】
      //数组里面是基本类型数据:替换、变更    如果对象,不管你怎么玩都是相应的!!!!
      //排他操作
      //底下的代码:修改数组里面的对象【相应的式的】,数据变化视图跟这变化!!!
      arr.forEach((item) => {
        item.isChecked = "0";
      });
      saleAttrValue.isChecked = "1";
    },

4.购买产品个数
(1)通过加减按钮修改产品个数

 <!-- 购物商品个数的操作地方 -->
              <div class="controls">
                <input
                  autocomplete="off"
                  class="itxt"
                  v-model="skuNum"
                  @change="handler"
                />
                <a href="javascript:" class="plus" @click="skuNum++">+</a>
                <a
                  href="javascript:"
                  class="mins"
                  @click="skuNum > 1 ? skuNum-- : 1"
                  >-</a
                >
              </div>

(2)通过用户输入改变产品个数

input框的change事件

 //数量的表单元素的change回调
    handler(e) {
      //通过event事件对象获取用户输入内容[用户输入的内容一定是字符串类型的数据] 
      //包含非数字的字符串*1一定等于NaN
      let value = e.target.value * 1;
      //用户输入进来非法情况判断 判断特殊情况 是否为非数值 是否小于1
      if (isNaN(value) || value < 1) {
        this.skuNum = 1;
      } else {
        //正常情况 取整
        this.skuNum = parseInt(value);
      }
    },

5.加入购物车

加入购物车的回调函数
1.发请求,将商品加入到数据库(通知服务器)
2.服务器存储成功(服务器没有返回数据,只有code=200代表此次操作成功)—进行路由跳转传递参数
3.失败,提示用户
4.将产品信息进行会话存储,以字符串的形式进行存储(本地存储不能存储对象)
5.路由跳转,展示商品信息,加入成功提示

 <div class="add">
                <!--点击加入购物车按钮:不能用声明式导航,第一个:要发请求(有业务),将购买的产品信息通知服务器存储-->
                <a @click="addOrUpdateCart">加入购物车</a>
  </div>


//加入购物车或者更新购物车中的产品个数
    async addOrUpdateCart() {
      //派发action:携带的载荷,分别商品的id、商品个数
      //实质就是调用了小仓库里面相应的这个函数->addOrUpdateCart,声明部分加上asyc,这个函数执行的结构一定是Promise
      //返回结果是一个Promise对象【三种状态:pending、成功、失败】,返回状态到底是什么,取决于这个函数addOrUpdateCart返回结果
      
        //判断加入购物车是成功还是失败
        //try是成功
      try {
        // 调用仓库中的函数
        //await是成功
        await this.$store.dispatch("addOrUpdateCart", {
        //产品id产品数量
          skuId: this.$route.params.skuId,
          skuNum: this.skuNum,
        });
        //路由跳转:携带参数,携带参数一般都是基本类型数据【字符串、数字等等】,引用类型数据白扯【传递过来路由获取不到】!!!
        //浏览器存储功能,在路由跳转在之前,存储到浏览器中
        //会话存储 会话结束就消失
        sessionStorage.setItem('SKUINFO',JSON.stringify(this.skuInfo));
        //路由跳转 携带加入购物车的产品信息跳转至另一个组件
        this.$router.push({
          path: "/addcartsuccess",
          query: { skuNum: this.skuNum},
        });
      } catch (error) {
        //失败干什么
        alert("加入购物车失败");
      }
    },

store中的detail.js

   //加入购物车|将来修改商品个数的地方,右侧是载荷对象【两个K,两个V】
   //加上async 返回的一定是Promise 要么成功 要么失败
     async addOrUpdateCart({ state, commit, dispatch }, { skuId, skuNum }) {
          //向服务器发送请求,在服务器存储数据,result为服务器的返回结果
          //请求api接口 获取返回结果
          let result = await reqAddOrUpdateCart(skuId, skuNum);
 		//如果加入购物车成功,返回promise即为成功
          if (result.code == 200) {
          //非空字符串代表成功
               return "ok";
          } else {
               //如果加入购物车失败,返回失败的Promise
               return Promise.reject();
          }
     }

三、路由传递参数结合会话存储

1.将商品信息存入本地会话存储,商品数量通过路由跳转,使用query参数进行传递

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值