当前位置:   article > 正文

尚品汇前端项目总结3(P60-P90)_request 获取store

request 获取store

目录

detail模块开发

路由的滚动行为

产品售卖属性值排他思想

放大镜

购买产品个数的操作(正则表达式)

 加入购物车

shopCart组件开发 

游客身份uuid

购物车动态展示数据

修改购物车中商品数量 

删除全部选中的商品以及全选

注册与登录界面

注册业务

 验证码

注册

登录业务

token

登录后header状态的改变

退出登录


 

detail模块开发

路由的滚动行为

使用前端路由,当页面切换新路由时,想要页面滚到顶部,或者保持原先的滚动位置,可以自定义路由切换时页面的滚动行为

  1. let router = new VueRouter({
  2. routes
  3. scrollBehavior(to,before,savedPosition) {
  4. //return 期望滚动到哪个位置
  5. //滚动到顶部
  6. return { y: 0 }
  7. }
  8. })

to和from表示路由对象savedPosition当且仅当popstate(通过浏览器的前进后退按钮触发)导航时才可用

return的信息格式为{x:number,y:number}

产品售卖属性值排他思想

点击的标签加上样式: 要获得被点击的属性值以及属性值列表,当发生点击事件的时候,先将属性列表中所有的属性都清除样式,然后再给被点击的属性加上样式

  1. changeClass(spuSaleAttrValueList,spuSaleAttrValue){
  2. for(let i=0;i<spuSaleAttrValueList.length;i++){
  3. spuSaleAttrValueList[i].isChecked=0;
  4. }
  5. spuSaleAttrValue.isChecked=1;
  6. }

放大镜

放大镜结构如下,下面为轮播图,与之前的轮播图不同的就是再swiper里面设置了一次展示几张【slidesPerView:3】

  1. <div class="spec-preview">
  2. <!-- 背景图片 -->
  3. <img :src=" imgObj.imgUrl" />
  4. <!-- 触发事件的地方 -->
  5. <div class="event" @mousemove="small" ref="box"></div>
  6. <!-- 放大的部分 -->
  7. <div class="big" ref="big">
  8. <img :src=" imgObj.imgUrl" ref="img" />
  9. </div>
  10. <!-- 覆盖层 -->
  11. <div class="mask" ref="mask"></div>
  12. </div>

event.offsetX,event.offsetY:鼠标相对于父盒子的位置

offsetWidth,offsetHeight

style.top,style.left:元素相对于父盒子的定位

逻辑部分:首先要判断mask的位置是否超出边界,如果超出就做相应处理,img的移动部分主要是利用公式

img移动距离/mask移动距离=-img可移动最大距离/mask可移动最大距离

因为img和mask移动方向相反,所以有一个负号 

  1. small(event){
  2. let mask=this.$refs.mask;
  3. let box=this.$refs.box;
  4. let big=this.$refs.big;
  5. let img=this.$refs.img;
  6. let left=event.offsetX-mask.offsetWidth/2;
  7. let top=event.offsetY-mask.offsetHeight/2;
  8. if(event.offsetX-mask.offsetWidth/2<0){
  9. left=0
  10. }
  11. if(event.offsetX-mask.offsetWidth/2>box.offsetWidth-mask.offsetWidth){
  12. left=box.offsetWidth-mask.offsetWidth
  13. }
  14. if(event.offsetY-mask.offsetHeight/2<0){
  15. top=0
  16. }
  17. if(event.offsetY-mask.offsetHeight/2>=box.offsetHeight-mask.offsetHeight){
  18. top=box.offsetHeight-mask.offsetHeight
  19. }
  20. mask.style.top=top+'px';
  21. mask.style.left=left+'px';
  22. //最大偏移量的比
  23. img.style.left=-((img.offsetWidth-big.offsetWidth)/(box.offsetWidth-mask.offsetWidth))*left+'px'
  24. img.style.top=-((img.offsetHeight-big.offsetHeight)/(box.offsetHeight-mask.offsetHeight))*top+'px'
  25. }

购买产品个数的操作(正则表达式)

加减按钮要注意不能为负数,给输入框绑定change事件 

正则表达式: 

  1. changeSkuNum(){
  2. //正则,可以输入0-9中任何数,并且每个数出现的次数可以是0次或无数次
  3. let rg=/^[0-9]*$/;
  4. this.skuNum=Math.ceil(this.skuNum);
  5. if(!rg.test(this.skuNum)){
  6. this.skuNum=1;
  7. }else{
  8. //隐式转换成数字
  9. this.skuNum=this.skuNum*1;
  10. }
  11. }

不用正则:

  1. changeSkuNum(){
  2. //隐式转换成number,如果是数字以外的类型转换成number就会是NaN
  3. let value=this.skuNum*1
  4. //排除负数的情况
  5. if(isNaN(this.skuNum)||value<1){
  6. this.skuNum=1
  7. }
  8. //不能是小数
  9. this.skuNum=Math.ceil(this.skuNum);
  10. }

 加入购物车

 点击加入购物车后,首先要先向购物车发送信息,如果成功返回则将相关数据存储在本地,最后进行路由跳转。

skuInfo不建议用路由传参,因为会显示在地址栏中,会很丑,所以这里用会话存储传参(因为是单页面的应用),简单的数据再用路由传参

浏览器存储功能(html5新增):一般存储的是字符串 可以用JSON.stringify()把对象转换成字符串存储,取的时候用JSON.parse()转回去

  1. 本地存储:不删除会一直存在
  2. 会话存储:会话结束就删除
  1. postAddToCart(){
  2. this.$store.dispatch('detail/postAddToCart',{skuId:this.$route.params.skuid,skuNum:this.skuNum}).then(
  3. response=>{
  4. sessionStorage.setItem('skuInfo',JSON.stringify(this.skuInfo))
  5. this.$router.push({name:'addcartsuccess',query:{skuNum:this.skuNum}})
  6. },error=>{
  7. alert('error')
  8. }
  9. )
  10. }

shopCart组件开发 

游客身份uuid

 uuid:能够生成一个随机的id

单独写一个js文件,放在新建的utils中,写一个生成uuid的函数,返回值为生成的uuid。

先看看本地存储里面是否已经有uuid,如果没有则生成uuid并存储后返回,有就直接返回

  1. import { v4 as uuidv4 } from 'uuid'
  2. export const getUUID = () => {
  3. let uuid_token = localStorage.getItem('UUIDTOKEN');
  4. if (!uuid_token) {
  5. uuid_token = uuidv4()
  6. localStorage.setItem('UUIDTOKEN', uuid_token);
  7. }
  8. return uuid_token
  9. }

在store里面生成并存储(应该在detail里面生成,因为在detail中加入购物车的时候就需要把uuid传回去)

  1. const state = {
  2. detail: {},
  3. uuid_token: getUUID()
  4. };

 在请求拦截器中设置,在request中引入store就可以获取store中的数值。

在请求头的userTepId(这是和后台商量好的)中携带

  1. if (store.state.detail.uuid_token) {
  2. config.headers.userTempId = store.state.detail.uuid_token
  3. };

购物车动态展示数据

Array.forEach(item=>{})遍历每个数组

Arry.every(item=>判断)如果都符合返回真否则为假 

  1. //计算总价格
  2. totalPrice(){
  3. let sum=0
  4. this.cartInfoList.forEach(item=>{
  5. if(item.isChecked==1)
  6. {sum=sum+item.skuNum*item.skuPrice}
  7. })
  8. return sum
  9. },
  10. //判断是否全选
  11. isAllCheck(){
  12. return this.cartInfoList.every(item=>{return item.isChecked==1})
  13. }

修改购物车中商品数量 

 该接口需要传递商品数量的变化量正数为增加,负数为减少,因此点击+号num=1,点击减号,当当前的skuNum大于1则num=-1否则num=0;在输入框输入数字的时候,如果输入的是非法字符或者负数则不改变,因此num=0,如果是合法的数字则取整数然后减去原先的skuNum获得变化量。最后重新发送请求,如果发送成功则重新获取购物车数据。

为了避免频繁修改并发送请求,添加了节流函数

  1. changeNum:throttle(async function(type,num,cartInfo){
  2. switch(type){
  3. case 'add':
  4. num=1;
  5. break;
  6. case 'sec':
  7. if(cartInfo.skuNum>=2){
  8. num=-1
  9. }else{
  10. num=0
  11. }
  12. break;
  13. case 'change':
  14. if(isNaN(num)||num<1){
  15. num=0
  16. }else{
  17. // 这里的num没有双向数据绑定,所以num是改变后的值
  18. num=parseInt(num)-cartInfo.skuNum;
  19. }
  20. }
  21. try{
  22. await this.$store.dispatch('detail/postAddToCart',{skuId:cartInfo.skuId,skuNum:num});
  23. this.getCartList()
  24. }catch(error){
  25. alert('error')
  26. }
  27. },500),

剩余的删除产品、改变产品状态的操作和前面差不多

删除全部选中的商品以及全选

在store里面处理逻辑,遍历购物车信息,选择的话就派发之前写的删除请求,并将返回的promise存在数组中,等遍历结束之后用promise.all来判断之前返回的promise中有没有失败的,只要有失败promise.all都会返回失败。

  1. deleteAll({ getters, dispatch }) {
  2. let promiseAll = []
  3. getters.cartInfoList.forEach(item => {
  4. let result = item.isChecked && dispatch('deleteCart', item.skuId)
  5. promiseAll.push(result)
  6. });
  7. // context.dispatch('deleteCart')
  8. //只要有一个失败,就会返回失败
  9. return Promise.all(promiseAll)
  10. },

Promise.all() 是一个内置的辅助函数,接受一组 promise(或者一个可迭代的对象),并返回一个promise

const allPromise = Promise.all([promise1, promise2, ...]);

 通过全选改变商品状态的方法和删除方法差不多

注册与登录界面

注册业务

 验证码

点击获取验证码的时候,先判断是否已经输入手机号,如果输入了手机号那就派发一个action。因为给手机发验证码要钱,这里就直接将返回的验证码存储在仓库里面,然后自动显示在验证码框上 

  1. async getCode(){
  2. try{
  3. this.phone && await this.$store.dispatch('users/getCode',this.phone);
  4. this.code=this.$store.state.users.code;
  5. }catch(error){
  6. console.log('error')
  7. }
  8. }

注册

首先确认所有要填写的内容都有并且密码和确认密码相同 ,并向后台要数据,如果成功返回,那就跳转到登录页面

  1. async userRegister(){
  2. try{
  3. const {phone,password,code,passwordSure,agree}=this;
  4. if(phone&&password&&code&&password==passwordSure&&agree){
  5. await this.$store.dispatch('users/getRegister',{phone,password,code});
  6. this.$router.push('/login')
  7. }
  8. }catch(error){
  9. console.log(error.message)
  10. }
  11. }

登录业务

token

 确认用户名和密码都有,就请求数据,成功则返回原来要去的界面(例如没有登录的情况下,如果去个人中心,会自动跳转到登录界面,登录成功后再跳转到个人中心界面)

  1. async login(){
  2. try{
  3. const {phone,password}=this
  4. if( phone&&password)
  5. {
  6. await this.$store.dispatch('users/getLogin',{phone,password})
  7. let toPath=this.$route.query.toPath||'/home'
  8. this.$router.push(toPath)
  9. }
  10. }catch(error){
  11. console.log(error.message)
  12. }
  13. }

 注意:表单标签form有默认行为,要取消可以用prevant

 <button class="btn" @click.prevent="login">登&nbsp;&nbsp;录</button>

 登录成功后,后台返回的数据中有token,是用户登录的唯一标识,拿到token要先存在localstorage(因为vuex不是持久化的,如果不存在本地,刷新一下就没有了)并且存在state里面

  1. async getLogin(context, { phone, password }) {
  2. let result = await reqLogin({ phone, password });
  3. if (result.code == 200) {
  4. localStorage.setItem('TOKEN', result.data.token)
  5. context.commit('GETTOKEN', result.data.token);
  6. return 'ok'
  7. } else {
  8. alert(result.message)
  9. return Promise.reject(new Error(result.message));
  10. }
  11. },

使用请求拦截器,在请求头中加上token 

  1. if (store.state.users.token) {
  2. config.headers.token = store.state.users.token
  3. }

登录后header状态的改变

登录成功后,登录的地方要显示用户名,因此需要获得用户信息,

由于header不是路由组件,只挂载一次,因此不能在header的mounted里面获取;

如果在App.vue里面获取,由于App只加载一次,第一次加载的时候没有登录就没有token,因此无法获取用户信息,必须要手动刷新一次。

因此在路由守卫里面设置,发送路由变化的时候,如果已经有token那就获取用户信息

退出登录

向服务器请求删除数据,然后返回首页 

  1. async logout(){
  2. try{
  3. await this.$store.dispatch('users/getLogout');
  4. this.$router.push('/home')
  5. }catch(error){
  6. console.log(error.message)
  7. }
  8. }

 服务器返回成功后,要将仓库中的token和用户信息需要清除,本地存储的token也需要情况

  1. //退出登录后原先的token就没用了要清除
  2. async getLogout(context) {
  3. let result = await reqLogout();
  4. if (result.code == 200) {
  5. context.commit('CLEARINFO')
  6. return 'ok'
  7. } else {
  8. return Promise.reject(new Error(result.message));
  9. }
  10. },
  1. CLEARINFO(state) {
  2. state.token = '',
  3. state.userInfo = {},
  4. localStorage.removeItem('TOKEN')
  5. }

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/42491
推荐阅读
相关标签
  

闽ICP备14008679号