一、购物车ShopCart的数据处理
(一)批量删除
找到total,加一个逻辑进行判断
![](https://i-blog.csdnimg.cn/blog_migrate/de6765878edb1525eb9d06a2d941964f.png)
找到按钮,绑定点击事件
![](https://i-blog.csdnimg.cn/blog_migrate/48e7b3ab79d848dcea43c44d62b07624.png)
找到api文件,编写批量删除的接口
//该函数专门用于:获取删除一些商品的状态
export const reqBatchDeleteCart = (idList) => ajax.post('/cart/batchDeleteCart',idList)
找到methods编写批量删除商品的回调方法
![](https://i-blog.csdnimg.cn/blog_migrate/06a8ab09b6322bffb536ed6eee78c125.png)
别忘了在import中引入reqBatchDeleteCart
(二)购物车数量的修改
因为携带给服务器的是差值,不是我们最终想要的值,而且购物车是要向服务器发送请求的
获取用户输入的数量以及商品的skuId
![](https://i-blog.csdnimg.cn/blog_migrate/0b793a04baada5ff7a4788bc0f6f07bb.png)
在methods中校验输入的是否合法的逻辑(难点)
// 修改数量的一些回调
async handleChangeGoodNum(type, cartInfo,e) {
// 若此时不可操作购物车数量,则停掉逻辑,否则正常执行
if(!this.isExecute) return
// 即将操作购物车数量,立刻锁掉逻辑
this.isExecute = false
switch (type) {
// 若是点击了+号
case "increment":
if (cartInfo.skuNum === 200) {
alert("最大购买数量为200!");
} else {
// 发送请求让服务器+1
let result = await reqAddGood2Cart(cartInfo.skuId, 1);
// 根据服务器返回的结果,来维护本地数据
if (result.code === 200) {
// 本地加1
cartInfo.skuNum++;
// 勾选
cartInfo.isChecked = 1;
} else {
alert(result.message);
}
}
break;
// 若是点击了-号
case "decrement":
if (cartInfo.skuNum === 1) {
alert("最小购买数量为1!");
} else {
// 发送请求让服务器+1
let result = await reqAddGood2Cart(cartInfo.skuId, -1);
// 根据服务器返回的结果,来维护本地数据
if (result.code === 200) {
// 本地减1
cartInfo.skuNum--;
// 勾选
cartInfo.isChecked = 1;
} else {
alert(result.message);
}
}
break;
// 若是直接修改
case "input":
// 获取用户输入的数量
const { value } = e.target;
// 获取当前的数量以及商品的skuId
const { skuId, skuNum } = cartInfo;
// 校验输入
if (goodNumReg.test(value)) {
// 合法
// 计算差值
const disNum = value - skuNum;
// 发请求联系服务器
let result = await reqAddGood2Cart(skuId, disNum);
// 判断业务逻辑是否成功
if (result.code === 200) {
// 修改数量成功了
cartInfo.skuNum = value * 1;
// 只要修改数量成功,必须勾选
cartInfo.isChecked = 1;
} else {
// 修改数量失败了
alert(result.message);
// 亲手操作DOM,将值变为输入前的值
e.target.value = skuNum;
}
}
// 用户输入的太多了
else if (value > 200) {
// 计算差值
const disNum = 200 - skuNum;
// 如果差值是0,直接将DOM置为200,逻辑停止,请求根本无需发送
if (disNum === 0) {
return (e.target.value = 200);
}
// 发请求联系服务器
const result = await reqAddGood2Cart(skuId, disNum);
// 判断业务逻辑是否成功
if (result.code === 200) {
// 若成功,则更新本地数据,同时直接操作DOM,将内容变为200
cartInfo.skuNum = e.target.value = 200;
// 只要修改数量成功,必须勾选
cartInfo.isChecked = 1;
} else {
// 若失败,更新本地数据
alert(result.message);
// 亲手操作DOM,将值变为输入前的值
e.target.value = skuNum;
}
}
// 用户输入的不合法
else {
// 打回原来的值
e.target.value = skuNum;
}
}
// 释放数量修改逻辑
this.isExecute = true
}
},
补充:函数的防抖与节流
函数的防抖
什么是函数的防抖?
事件被触发后等n秒后再执行逻辑,若这n秒内事件又被触发,则重新计时n秒,之前的逻辑不再执行。简单来说就是生活中我们要做的事情总是被改来改去,那这样就等下发指令后的n秒,再做,免得再改来改去。也就是等那最后一下。
什么是抖?
就是发送了太多次的没用的请求,用专业的话来说就是服务器太累了。
怎么防抖?
等获得完整的输入之后再发送请求,可以先进入一段判断,再包一个定时器,但这样写过于麻烦,可以使用lodash库,引入相对应的文件之后,利用._debounce方法,正常书写指定的回调,正常发送请求就好了。
具有代表性的应用场景:实时搜索
代码片段:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入lodash:lodash全部的功能引入 -->
<script src="./js/lodash.js"></script>
</head>
<body>
<p>
请你输入搜索的内容:<input type="text">
</p>
</body>
</html>
<script>
//防抖:前面的所有的触发都被取消,最后一次执行在规定的时间之后才会触发,也就是说如果连续快速的触发,只会执行一次
let input = document.querySelector('input');
//文本发生变化立即执行
input.oninput = _.debounce(function(){
console.log('ajax发请求')
},1000);
//lodash插件:里面封装函数的防抖与节流的业务【闭包+延迟器】
//1.lodash函数库对外暴露_函数
</script>
函数的节流
什么是函数的节流?
在规定的间隔时间范围内不会重复触发回调,只有大于这个时间间隔才会触发回调,把频繁触发变为少量触发。
例子:玩游戏。例如在玩王者荣耀,当人物放大招时,会有技能冷却时间,如果说不点的话就不会进入冷却期;或者也可以比喻成在车站等车吃面,吃一口面的时间是60s,不管车是不是到站了,吃面的时间还是60s。再或者是射击游戏中的射速,就算是一直点着鼠标射击,也只会在规定射速内射出子弹。
为什么要使用函数节流?
因为在前端开发当中,有一些事情或者是函数,会频繁地触发,例如onresize、scroll、mousemove等,这些事件的触发频率很高,如果不做限制的话,很可能会触发n次,服务器会很累。
解决思路
主要解决思路是包一个定时器(setTimeout),通过设置延时时间,在第一次调用时,创建定时器,先设定一个变量true,写入需要执行的函数。第二次执行这个函数时,会判断变量是否true,是则返回。当第一次的定时器执行完函数最后会设定变量为false。那么下次判断变量时则为false,函数会依次运行。目的在于在一定的时间内,保证多次函数的请求只执行最后一次调用。(本段原文链接如下)
原文链接:https://blog.csdn.net/ZiChen_Jiang/article/details/121163381
代码片段:这里是使用了_.throttle这一属性,throttle本身就有节流阀的意思。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./js/lodash.js"></script>
</head>
<body>
<div>
<h1>我是计数器<span>0</span></h1>
<button>点我加上1</button>
</div>
</body>
</html>
<script>
//节流:在规定的间隔时间范围内不会重复触发回调,只有大于这个时间间隔才会触发回调,把频繁触发变为少量触发
//获取节点
let span = document.querySelector('span');
let button = document.querySelector('button');
let count = 0;
//计数器:在一秒以内,数字只能加上1
button.onclick = _.throttle(function(){
//节流:目前这个回调函数5s执行一次
//假如这里面有很多业务代码,是不是可以给浏览器很充裕的时间去解析
count++;
span.innerHTML = count;
console.log('执行');
},5000)
</script>
使用场景
懒加载、滚动加载、加载更多或监听滚动条位置;防止高频点击提交、防止表单重复提交
防抖与节流的区别
防抖:用户操作很频繁,但只会执行一次
节流:用户操作很频繁,但会把频繁操作变为少量操作
(三)使用标识解决购物车的bug
代码如下
![](https://i-blog.csdnimg.cn/blog_migrate/96cbfaa2de3071bbe6287328394b058b.png)
二、element-ui的基本使用
控制台输入命令npm i element-ui进行安装
引入并应用插件,在main.js中输入以下代码
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
但这样引入,资源内存过大,这时候需要按需引入
按需引入:控制台输入命令npm install babel-plugin-component -D进行安装
找到babel文件,进行如下的修改
![](https://i-blog.csdnimg.cn/blog_migrate/674fcab0bf1228b0b2208d32b16cbea8.png)
因为在register和login组件中要使用提示框,所以需要我们在main.js文件中引入如下代码
![](https://i-blog.csdnimg.cn/blog_migrate/425165d84444588a2e402e98f57e80d7.png)
三、注册组件的完成
(一)静态组件
将手机号、验证码、密码、确认密码、同意协议都绑定一个v-model
![](https://i-blog.csdnimg.cn/blog_migrate/62296d3899fd0134696750f1de89e9f9.png)
在data里进行定义,存储它们的值
![](https://i-blog.csdnimg.cn/blog_migrate/510943510993daa3241944b22ca82cd8.png)
(二)获取验证码+完成注册
在api/index.js文件中编写获取验证码的接口
// 该函数专门用于:获取验证码的状态
export const reqSendCode = (phone) => ajax.get(`/user/passport/sendCode/${phone}`)
2.回到组件文件里,在获取验证码的按钮上绑定点击事件,然后利用methods定义方法,import引入reqSendCode
![](https://i-blog.csdnimg.cn/blog_migrate/2b7a2e18dd0886ec72052e0d84d5daed.png)
3.完成注册
在api/index.js文件中编写完成注册的接口
// 该函数专门用于:完成注册
export const reqRegister = (paramsOdj) => ajax.post('user/passport/register',paramsOdj)
回到Registar组件里,在methods中编写完成注册的回调
![](https://i-blog.csdnimg.cn/blog_migrate/4dd7e9949cf4c4fbb26c26e70529dcfe.png)
四、登录组件的完成
(一)静态组件
copy准备好的文件,在手机号还有输入密码的input框都绑定v-model
![](https://i-blog.csdnimg.cn/blog_migrate/47fa9f43104a7b52ddafe20b686e29c0.png)
在data里面赋予它们意义
![](https://i-blog.csdnimg.cn/blog_migrate/25318c3a86c3f9952457b4fb4945fee6.png)
(二)完成登录
回到api/index.js文件中编写登录的接口
// 该函数专门用于:用户登录
export const reqLogin = (paramsOdj) => ajax.post('/user/passport/login',paramsOdj)
回到Login组件里,在methods中编写完成登录的回调
![](https://i-blog.csdnimg.cn/blog_migrate/a4dff4e9bf9e00892a50063ef85d2fee.png)
在登录按钮上绑定点击事件,别忘了引入reqLogin
<button class="btn" @click="handleLogin">登 录</button>
import { reqLogin } from "@/api";
五、token的理解
token的本质就是字符串,唯一的;只有在用户登录成功后,服务器才会为用户生成一个token。
token是用户真正的标识,最好是在localStorage中存储下。
为什么?为了能让用户打开浏览器后是自动登录状态
3.服务器在用户登录成功后,会向浏览器返回用户昵称、用户真实姓名、还有token,但我们只存token。
为什么?因为我们可以根据token找到用户更多的信息,而且服务器不会给多余的东西,只给一个token。
4.如果不允许多端登录,服务器要在用户登录之后,将之前的token销毁,再生成一个新的token。
5.token并不是长期有效的,到了过期时间,服务器就不再认可token了。
6.如果用户主动触发退出登录,那么服务器就会销毁该用户的token。
7.在utils/auth.js文件中编写代码存储token、读取token
![](https://i-blog.csdnimg.cn/blog_migrate/1b6c5ddce4e9d078c68cc39a3316589a.png)
login.vue方法里编写代码读取到用户唯一的token
![](https://i-blog.csdnimg.cn/blog_migrate/d5bcabd15e81d7083116411bdfa8849f.png)