当前位置: 首页 > news >正文

可以做烟的网站吗常州网站推广公司

可以做烟的网站吗,常州网站推广公司,深圳企业登记网络服务平台,做网站一条龙文章目录 一、加入购物车1. 添加到购物车的接口2. 点击按钮的回调函数3. 请求成功后进行路由跳转(1)、创建路由并配置路由规则(2)、路由跳转并传参(本地存储) 二、购物车页面的业务1. uuid生成用户id2. 获取购物车数据3. 计算打勾商品总价4. 全选与商品打勾(1)、商品全部打勾&a…

文章目录

  • 一、加入购物车
    • 1. 添加到购物车的接口
    • 2. 点击按钮的回调函数
    • 3. 请求成功后进行路由跳转
      • (1)、创建路由并配置路由规则
      • (2)、路由跳转并传参(本地存储)
  • 二、购物车页面的业务
    • 1. uuid生成用户id
    • 2. 获取购物车数据
    • 3. 计算打勾商品总价
    • 4. 全选与商品打勾
      • (1)、商品全部打勾,自动勾全选(every方法)
      • (2)、打勾单个商品,更新数据
      • (3)、点击全选框,对每个商品的单选框进行操作
    • 5. 删除购物车
      • (1)、删除单个商品
      • (2)、删除选中的商品
    • 6. 处理购物车的产品数量(难)

一、加入购物车

思路分析:点击加入购物车按钮后,需要进行如下的几个操作
(1)、向服务器发送请求,将产品信息(产品Id,购买的产品数量)发给服务器进行存储。
(2)、服务器存储成功,进行路由跳转,跳转到加入购物车成功的界面。
(3)、服务器存储失败,给用户提示。

1. 添加到购物车的接口

写发送请求的接口:api/index.js

// 添加到购物车(对已有物品进行数量改动) url: /api/cart/addToCart/{ skuId }/{ skuNum } 请求方式post
export const reqAddOrUpdateShopCart = (skuId, skuNum) => {return requests({ url: `/cart/addToCart/${skuId}/${skuNum} `, method: 'post' })
}

2. 点击按钮的回调函数

 <!-- 加入购物车 --><div class="add"><a href="javascript:" @click="addShopCar">加入购物车</a></div><script>addShopCar () {// 1. 派发action请求,将数据给服务器进行存储this.$store.dispatch('detail/addOrUpdateShopCart', { skuId: this.$route.params.goodsId, skuNum: this.skuNum })// 2. 服务器存储成功---进行路由跳转并携带参数 // 3. 服务器存储失败----给用户提示}</script>

这里需要注意的是
(1)、这里发请求不需要服务器返回数据,所以拿到服务器的返回结果时并不需要存储。服务器的返回结果只会告知请求是发送成功or发送失败。
(2)、问题: 请求的返回结果在仓库的actions里,组件中如何拿到这个返回结果以判断是请求成功还是请求失败。

解决async函数返回的是一个Promise对象,组件中派发请求相当于调用了这个async函数,应该得到一个Promise对象。那我们就在这个async函数里判断请求成功或失败来实例化一个Promise对象,返回给组件。

// detail小仓库里:async addOrUpdateShopCart (context, { skuId, skuNum }) {let result = await reqAddOrUpdateShopCart(skuId, skuNum)if (result.code == 200) {// 加入购物车成功return 'ok'} else {// 加入购物车失败return Promise.reject(new Error('faile'))}}

回调函数中接收到这个

addShopCar () {// 1. 派发action请求,将数据给服务器进行存储:this.$store.dispatch('detail/addOrUpdateShopCart')就是在调用这个函数addOrUpdateShopCarttry {this.$store.dispatch('detail/addOrUpdateShopCart', { skuId: this.$route.params.goodsId, skuNum: this.skuNum })// 2. 服务器存储成功---进行路由跳转并携带参数this.$router.push({ name: 'addCartSuccess', })} catch (error) {// 3. 存储失败----给用户提示alert(error.message)}
}

3. 请求成功后进行路由跳转

(1)、创建路由并配置路由规则

1. 创建路由
将路由组件添加到pages文件夹
在这里插入图片描述
2. 配置路由规则
在这里插入图片描述

(2)、路由跳转并传参(本地存储)

如果路由跳转的时候不携带产品信息参数,则需要在跳转页面之后根据产品Id再次发送请求。这样做没必要。直接携带就好了。但是之前路由跳转传参都是简单的数字之类的。这里的产品信息(产品名称,产品属性)涉及到对象,还要传递购买的产品数量。

二、购物车页面的业务

1. uuid生成用户id

  进入购物车页面时,应将用户的id传给后端,后端根据用户id检索出该用户的购物车商品信息,传递给前端用于展示及进行其他操作。在这个系统中,我们用uuid库生成一个用户Id,在向后台发送请求时传递给后端。

1、创建文件utils/uuid_token.js:
  需要注意:一个用户只能有一个Id,所以这里采用本地存储来存储uuid生成的用户id。每次先读取本地存储中是否有用户id,有的话直接用,没有就生成一个新的。

// 用于生成用户的临时身份Id
import { v4 as uuidv4 } from 'uuid'
/*
- 先检查本地存储中有没有这个用户Id,
- 有就直接返回,
- 没有则生成新的
*/
export const getUUID = () => {let uuid_token = localStorage.getItem('UUID_TOKEN')// 如果没有if (!uuid_token) {// 生成用户iduuid_token = uuidv4();// 存储到localStorage.setItem('UUID_TOKEN', uuid_token)}return uuid_token
}

2、在仓库里调用函数,得到userTempId.
在这里插入图片描述
3、将userTempId配置在请求头里
  查看文档里的接口会发现:请求中并没有让携带参数,所以除了通过参数能将数据传递给后台,还能用什么方式呢?答:请求头。可以将用户Id放在请求头中。
在这里插入图片描述

2. 获取购物车数据

1、写接口

api/index.js

// 获取购物车列表   url: /api/cart/cartList 请求方式 get
export const reqShopCart = () => {return requests({ url: '/cart/cartList ', method: 'get' })
}

2、vuex三连环
在这里插入图片描述

3、组件发请求
  因为在购物车页面,其他的操作也会重新向服务器发请求,所以这里将放请求的操作包装成一个函数。
在这里插入图片描述
根据获取到的数据渲染界面
在这里插入图片描述

3. 计算打勾商品总价

 computed: {...mapState('shopCart', ['cartInfoList']),// 计算总价totalPrice () {let sum = 0this.cartInfoList.forEach((el) => {if (el.isChecked === 1) { // 商品是否被选中sum += (el.skuPrice * el.skuNum)}})return sum},
}

4. 全选与商品打勾

(1)、商品全部打勾,自动勾全选(every方法)

<div class="select-all"><input  class="chooseAll" type="checkbox" :checked="isAllChecked"/><span>全选</span>
</div>
<script>
computed:{isAllChecked () {// 统计checked的数量,是否等于数组长度let flag = this.cartInfoList.every((item) => {return item.isChecked == 1})return flag}
}
</script>

关于every方法,回顾博客:

(2)、打勾单个商品,更新数据

  选中某个商品后,商品的isChecked属性发生变化,需要将更新后的商品信息发给后台保存。(我感觉这个业务在实际中没必要,每次勾选或取消勾选都发送请求,服务器压力增大,没必要。但是这里是为了练习一些知识点)。
在这里插入图片描述
接口

// 切换商品选中状态   url: /api/cart/checkCart/{skuID}/{isChecked} 请求方式 get
export const changeIsChecked = (skuID, isChecked) => {return requests({ url: `/cart/checkCart/${skuID}/${isChecked}`, method: 'get' })
}

仓库Vuex

  // 改变商品选中的状态async changeChecked (context, { skuID, isChecked }) {let res = await changeIsChecked(skuID, isChecked)if (res.code === 200) {return 'ok'} else {return Promise.reject(new Error('faile'))}},

组件

 <!-- 选择框 --><li class="cart-list-con1"><input  type="checkbox"  name="chk_list" :checked="good.isChecked == 1"@change="handleChange(good.skuId, $event)" /></li><script>// 切换商品选中的状态async handleChange (skuId, e) {try {// 接口中的参数是1或0,不是true 或falselet isChecked = e.target.checked ? 1 : 0await this.$store.dispatch('shopCart/changeChecked', { skuID: skuId, isChecked: isChecked })this.getCartData()// 成功重新发请求} catch (e) {alert(e.message)}}</script>

(3)、点击全选框,对每个商品的单选框进行操作

在这里插入图片描述由于没有修改多个商品的接口,所以思路是多次调用打勾单个商品的接口,把每个商品的勾选状态改为当前全选框的状态。

此处需要注意在actions里,如何通过dispatch调用其他actions的函数

 // 改变商品选中的状态async changeChecked (context, { skuID, isChecked }) {let res = await changeIsChecked(skuID, isChecked)if (res.code === 200) {return 'ok'} else {return Promise.reject(new Error('faile'))}},// 改变所有商品的状态// 第一个参数是context,包含:state,dispatch,getters登,通过解构将需要的解构出来async changeAllState ({ dispatch, state }, stateFlag) {let promiseAll = []state.cartInfoList.forEach(el => {if (el.isChecked !== stateFlag) {// 通过dispatch调用其他的actions函数let promise = dispatch('changeChecked', { skuID: el.skuId, isChecked: stateFlag })promiseAll.push(promise)}});return Promise.all(promiseAll)},

在这里插入图片描述

给组件添加的全选点击事件

<div class="select-all">
<!--&& cartInfoList.length > 0 是考虑到处于当商品全部被删除时,全选框不应该处于选中状态--><input class="chooseAll"  type="checkbox":checked="isAllChecked && cartInfoList.length > 0"@change="handleAllChange" /><span>全选</span>
</div>
<script>async handleAllChange (e) {try {// e.target.checked获取全选框的值,let stateFlag = e.target.checked ? 1 : 0await this.$store.dispatch('shopCart/changeAllState', stateFlag)// 成功则重新发送请求this.getCartData()} catch (error) {alert(error.message);}}
</script>

5. 删除购物车

文档接口
在这里插入图片描述

(1)、删除单个商品

接口:

// 删除购物车商品 url:/api/cart/deleteCart/{skuId}   请求方式:delete
export const reqDeleteGoodById = (skuId) => {return requests({ 	url: `/cart/deleteCart/${skuId}`, method: 'delete' })
}

Vuex (这里也不需要三连环)

  // 删除商品async deleteOneGood (context, skuId) {let res = await reqDeleteGoodById(skuId)if (res.code === 200) {return 'ok'} else {return Promise.reject(new Error('failed'))}}

组件

<a class="sindelet" @click="deleteOneGood(good.skuId)">删除</a>
<script>// 删除一个商品async deleteOneGood (skuId) {try {await this.$store.dispatch('shopCart/deleteOneGood', skuId)this.getCartData() // 重新发送请求 } catch (error) {alert(error.message)}}
</script>

注意这里有一个bug!

(2)、删除选中的商品

没有删除多个商品的接口,所以思路是多次调用删除单个商品的接口,将选中的商品全都删除。
组件

 // 删除已选中的商品;async deleteAllChecked () {try {await this.$store.dispatch('shopCart/deleteAllSelected')// 重新发请求获取购物车列表this.getCartData()} catch (error) {alert(error.message)}}

重点是Vuex中:
  如果有一个删除失败,则这个操作就是失败了。采用Promise.all()方法给组件反馈成功或失败

actions:{// 删除全部商品deleteAllSelected ({ dispatch, state }) {let promiseAll = []// 获取购物车的全部商品state.cartInfoList.forEach((el) => {// 如果被该商品被勾选if (el.isChecked === 1) {let promise = dispatch('deleteOneGood', el.skuId)// 将每一次返回的Promise添加到数组当中promiseAll.push(promise)}})//Promise.all([p1,p2,p3]) p1,p2,p3都是Promise对象,其中有一个失败则全失败return Promise.all(promiseAll)}
}

6. 处理购物车的产品数量(难)

这里用到的接口之前写过,注意参数的描述!
在这里插入图片描述
根据这个文档描述,猜测这个skuNum的值是商品数量的变化量。
这个接口可以用在两个地方,添加到购物车和对已有物品进行数量改动。在添加到购物车的场景中,skuNum的值一直都是正的值。

HTML结构:

 <!--修改产品数量  --><li class="cart-list-con5"><!-----减号------><a class="mins" @click="handler('sub', -1, good)">-</a><!-----文本框输入,注意事件是失去焦点事件blur。$event.target.value * 1 是因为 非数值字符串*1 的值为NaN	------><input autocomplete="off"type="text":value="good.skuNum"minnum="1"class="itxt"@blur="handler('input', $event.target.value * 1, good)"/><!----加号------><a class="plus" @click="handler('add', 1, good)">+</a></li>

回调函数:

 /*type:操作的类型 add sub inputdisNum: 1,-1,输入框的最终数good:产品*/async handler (type, disNum, good) {// 判断不同的情况switch (type) {case 'add': // 加disNum = 1;break;case 'sub': // 减if (good.skuNum > 1) {disNum = -1} else {disNum = 0}break;case 'input':if (isNaN(disNum) || disNum < 0) {disNum = 0} else {// 增量disNum = parseInt(disNum) - good.skuNum}break;}// 发送请求 try {await this.$store.dispatch('detail/addOrUpdateShopCart', { skuId: good.skuId, skuNum: disNum })this.getCartData() // 请求成功,重新获取数据} catch (e) {alert(e.message)}}

但是这样做,有个小bug。当用户频繁点击-是,数量可能会出现负值
在这里插入图片描述
这是因为连续快速点击,请求还来不及发送,数据没改,所以每次disnum都是-1。解决办法就是节流,给服务器一些缓冲的时间,防止数据不同步出现上述bug。

// 按需引入
import throttle from 'lodash/throttle'
handler: throttle(async function (type, disNum, good) {// 判断不同的情况switch (type) {   ... }try {await this.$store.dispatch('detail/addOrUpdateShopCart', { skuId: good.skuId, skuNum: disNum })this.getCartData()} catch (e) {alert(e.message)}
}, 800)

最后分析一下,这个功能为什么要设计的这么麻烦,
(1) 为什么每+-或输入一次都要发送一次请求,
(2) 为什么不能直接把输入框的商品最终数量传给后端,还要计算差值。
答:
(1) 每+-或输入一次都是对数据进行了修改。购物车的商品数量改变后,刷新页面时,数量应该保持修改后的样子。所以每次操作完都要保存一下数据。
(2) 为什么要计算差值?因为这个接口还用来实现将商品添加到购物车。
  我用淘宝试了一下,这个业务逻辑是当在页面详情页,多次重复的将商品添加到购物车时。购物车里该商品的数量应该是这几次重复添加的数量的和。而不是最后一次添加时选择的商品数量。
  所以如果只将输入框里的最终数量传过去的话,商品数量只会是最后一次将该商品添加到购物车里时的选择的数量。


文章转载自:
http://nonprotein.nLkm.cn
http://hyposulfurous.nLkm.cn
http://quadricentennial.nLkm.cn
http://denlture.nLkm.cn
http://disembowel.nLkm.cn
http://pulpitry.nLkm.cn
http://unforeseeing.nLkm.cn
http://zeugmatic.nLkm.cn
http://taa.nLkm.cn
http://pelargonium.nLkm.cn
http://undispersed.nLkm.cn
http://kinneret.nLkm.cn
http://basilar.nLkm.cn
http://conclusively.nLkm.cn
http://quatercentenary.nLkm.cn
http://vocalism.nLkm.cn
http://pickerel.nLkm.cn
http://knurr.nLkm.cn
http://certificate.nLkm.cn
http://ebro.nLkm.cn
http://colorcast.nLkm.cn
http://gerund.nLkm.cn
http://delator.nLkm.cn
http://kufa.nLkm.cn
http://watershoot.nLkm.cn
http://perilous.nLkm.cn
http://favelado.nLkm.cn
http://rdo.nLkm.cn
http://gk97.nLkm.cn
http://basketballer.nLkm.cn
http://squeezable.nLkm.cn
http://cryptogrammic.nLkm.cn
http://desulfuration.nLkm.cn
http://reputation.nLkm.cn
http://postwar.nLkm.cn
http://bipropellant.nLkm.cn
http://deciduoma.nLkm.cn
http://suffice.nLkm.cn
http://rectificatory.nLkm.cn
http://sgraffito.nLkm.cn
http://sestertius.nLkm.cn
http://roughly.nLkm.cn
http://archibald.nLkm.cn
http://hoydenish.nLkm.cn
http://fifthly.nLkm.cn
http://whinger.nLkm.cn
http://disconcert.nLkm.cn
http://prerequisite.nLkm.cn
http://sadden.nLkm.cn
http://semiglobular.nLkm.cn
http://editorialist.nLkm.cn
http://disesteem.nLkm.cn
http://vibrato.nLkm.cn
http://giver.nLkm.cn
http://santak.nLkm.cn
http://sanceful.nLkm.cn
http://nonsoap.nLkm.cn
http://overcunning.nLkm.cn
http://recordable.nLkm.cn
http://krantz.nLkm.cn
http://metonym.nLkm.cn
http://microcurie.nLkm.cn
http://pisatin.nLkm.cn
http://envoi.nLkm.cn
http://hydroponist.nLkm.cn
http://contentment.nLkm.cn
http://piezoresistance.nLkm.cn
http://seawater.nLkm.cn
http://yellowback.nLkm.cn
http://prizeman.nLkm.cn
http://acrolith.nLkm.cn
http://draco.nLkm.cn
http://currier.nLkm.cn
http://caudal.nLkm.cn
http://daimon.nLkm.cn
http://unzip.nLkm.cn
http://fishline.nLkm.cn
http://prorogation.nLkm.cn
http://arrisways.nLkm.cn
http://penumbral.nLkm.cn
http://softish.nLkm.cn
http://scarus.nLkm.cn
http://nabs.nLkm.cn
http://dialytically.nLkm.cn
http://department.nLkm.cn
http://nonprofessional.nLkm.cn
http://subcordate.nLkm.cn
http://subdomains.nLkm.cn
http://indignant.nLkm.cn
http://kuru.nLkm.cn
http://cyclization.nLkm.cn
http://cineol.nLkm.cn
http://delenda.nLkm.cn
http://muton.nLkm.cn
http://stalagmometer.nLkm.cn
http://capon.nLkm.cn
http://seajelly.nLkm.cn
http://brrr.nLkm.cn
http://imperception.nLkm.cn
http://walter.nLkm.cn
http://www.hrbkazy.com/news/80584.html

相关文章:

  • wordpress小程序开发文档东莞百度seo
  • 下载的Wordpress怎么用上海网站seo
  • 中国十大门窗品牌排行榜前十名seo推广效果
  • 网站建设与管理教程视频教程国外免费推广网站有哪些
  • 郑州软件开发公司网站中铁建设集团有限公司
  • 云服务器 做网站百度图片识别在线识图
  • 短视频推广营销太原搜索引擎优化
  • 网站在美国做的服务器百度网盘资源搜索入口
  • 大型网站制作公司网站注册步骤
  • 婴儿衣服做的网站网站关键词推广工具
  • WordPress网校系统seo还有前景吗
  • ios网站开发工具怎么寻找网站关键词并优化
  • 郴州市建设网站自己怎么优化网站
  • 自己如何做棋牌网站今日国内新闻大事件
  • 嘉定网站建设百度关键词搜索排行榜
  • 哪个网站的旅游板块做的好网站优化推广seo
  • 购物网站配色怎么设计脚上起小水泡还很痒是什么原因
  • 凤岗东莞微信网站建设网络推广方法有哪些
  • 旅游网站建设与实现关键词难易度分析
  • 做企业网站外贸新手怎样用谷歌找客户
  • 网站中英文转换怎么做怎么做网络推广优化
  • 网站建设 内容缺乏今天宣布疫情最新消息
  • 百度制作网页需要多少钱天津seo优化公司哪家好
  • 最新的网络营销手段成都百度推广和seo优化
  • 哈尔滨建设网站的免费咨询nba排名最新排名
  • 施工企业会计制度抖音seo是什么
  • dede 如何做视频网站恶意点击软件哪几种
  • 南京工程建设招聘信息网站域名注册1元
  • 为什么wordpress 草稿不能阅读郑州seo外包收费标准
  • 重庆网站开发解决方案百度人工客服电话怎么转人工