本地存储local storage
-
也是浏览器提供的一个存储空间
-
和 cookie 的区别
- cookie 前后台来回跑,localStorage 只存储再浏览器不会来回跑
- cookie 前后台都可以设置, localStorage 只能由前台操作
- cookie 存储的是字符串,localStorage 只能存储 json 格式的字符串或者普通字符串
- cookie 存储 4KB 左右,localStorage 20M 左右
- cookie 自己封装 API 去操作,localStorage 有自己的 API 直接操作
- cookie 默认会话级别时效性,localStorage 默认永久时效(除非手动删除)
-
和 cookie 一样的地方
- cookie 按照域名存储,localStorage 也是
-
操作 localStorage
- 设置:localStorage.setItem(‘你要设置的 key’, ‘你要设置的 value’)
- 获取:localStorage.getItem(‘你要获取的 key’)
- 删除:localStorage.removeItem(‘你要删除的 key’)
- 清空:localStorage.clear()
<script>
// 设置localstorage 本地存储
// localStorage 值只能存储 普通的字符串 或者 json数据
// localStorage 也是按照域名来存储和使用
localStorage.setItem("login", 1);
var data = [{ name: "aaa" }];
// js转化为json数据
localStorage.setItem("data", JSON.stringify(data));
</script>
<script>
// 获取 localStorage
let res = localStorage.getItem("data");
console.log(res);
// 删除localStorage
// localStorage.removeItem('login');
// 清除所有的localStorage 里面的数据
localStorage.clear();
</script>
购物车逻辑
1.单表查询
- 需要一张购物车的数据库表
- 这张表中存储的是 商品的详细信息的字段
- userName
- goods_id
- goods_name
- goods_price
- goods_introduce
- goods_small_logo
- goods_num
- 当点击加入购物车的时候把 当前点击的商品id的商品一些详细信息 以字段的形式传递给后端
- 后端获取到相应的信息,就存入数据库
- 当前端去到购物车页面,就把购物车表中 的信息显示
- 获取购物车数据的时候,需要传递用户名过去,显示用户名对应的数据
总结:逻辑稍微简单一些,但是数据库存储的数据更加复杂,如果想要商品的相信息传递参数较复杂(前端较复杂)
2.多表查询
-
需要一张购物车表
-
这张表中需要存储
- userName 用户名
- goods_id 商品的id
- goods_num 商品的数量
- id 唯一值
-
当用户点击加入购物车的时候,把点击的这条商品的goods_id 和点击的数量 和 哪个用户添加到购物车的表中
- 当添加商品的时候,先判断购物车中是否存在该 goods_id 和 对应 userName
- 如果存在就把 goods_num的值+1
- 如果不存在 就把这个条goods_id userName 和goods_num字段添加进去,其中goods_num的值为1
- 当添加商品的时候,先判断购物车中是否存在该 goods_id 和 对应 userName
-
当去到购物车页面的时候,获取数据(根据用户名去获取对应的购物车数据)
- 当前端把用户名传递过,后端根据用户名去购物车表中 查询 这个用户 对应商品的goods_id
- 拿到的是这个用户的所有goods_id
- 然后循环这个数据,去拿出每一条goods_id对应的的信息商品详细信息
- 然后把处理的数据给会前端
"SELECT * FROM `goods` WHERE `goods_id` in (SELECT `goods_id` FROM `car` WHERE `username` = '$username')"
- 当前端把用户名传递过,后端根据用户名去购物车表中 查询 这个用户 对应商品的goods_id
总结:购物车表存储的数据简单,后端处理数据的逻辑较为复杂,但是可以获取商品的所有详细信息
3.购物车的接口文档:
(1)获取购物车数据的接口
- 接口地址:
getCarData.php
- 传递参数的key:
username
把当前登录的用户名传递过去
- 请求的类型:
get
(2)添加购物车
- 接口地址:
addCarData.php
- 传递参数的key:
username
添加商品的用户名goods_id
添加本条商品的goods_id
- 请求方式:
post
(3)修改商品的数量
- 接口地址:
updCarData.php
- 传递参数的key:
username
是哪个用户需要修改商品的数量goods_id
修改那条商品的数量goods_num
修改数量为多少
(4)删除商品
- 接口地址:
removeCarData.php
- 传递参数的key:
username
删除哪个用户购物车中的商品goods_id
删除用户中哪条商品数据
(5)清空购物车
- 接口地址:
clearCarData.php
- 传递参数:
username
清空哪个用户的购物车
购物车案例
(1)html
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="bootstrap-3.3.7-dist/css/bootstrap.min.css">
</head>
<body>
<div class="jumbotron">
<h1>暂时没有写首页,你可以去列表页看看数据</h1>
<p><a class="btn btn-primary btn-lg" href="html/list.html" role="button">跳转列表页</a></p>
</div>
</body>
</html>
- login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="../bootstrap-3.3.7-dist/css/bootstrap.min.css">
<link rel="stylesheet" href="../css/login.css">
</head>
<body>
<div class="container">
<form class="form-horizontal">
<div class="form-group">
<label for="username" class="col-sm-2 control-label">用户名:</label>
<div class="col-sm-10">
<input type="username" class="form-control" id="username" placeholder="请输入用户名">
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-2 control-label">密码:</label>
<div class="col-sm-10">
<input type="password" class="form-control" id="password" placeholder="请输入密码">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">登录</button>
</div>
</div>
</form>
</div>
<script src="../js/ajax.js"></script>
<script src="../js/cookie.js"></script>
<script src="../js/login.js"></script>
</body>
</html>
- list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="../bootstrap-3.3.7-dist/css/bootstrap.min.css">
<link rel="stylesheet" href="../css/list.css">
</head>
<body>
<h1>我是列表页数据</h1>
<div class="container">
<ul class="list">
<!-- <li class="list-item">
<div class="title">
<ol class="breadcrumb">
<li><a href="#">Home</a></li>
<li><a href="#">Library</a></li>
<li class="active">Data</li>
</ol>
</div>
<div class="row">
<div>
<div class="thumbnail">
<img src="https://g-search3.alicdn.com/img/bao/uploaded/i4/i3/2114784451/O1CN01cdNJpt1ikbU1UmZ35_!!2114784451-0-lubanu-s.jpg_230x230.jpg"
alt="...">
<div class="caption">
<h3>诗绪刺绣改良旗袍连衣裙女夏装2020年新款中国风印花A字裙子52150</h3>
<div class="price">
<i class="glyphicon glyphicon-yen"></i>
<span>199.8</span>
</div>
<p>
<a href="./car.html" class="btn btn-primary" role="button">查看购物车</a>
<a href="./detail.html" class="btn btn-info" role="button">查看商品详情</a>
</p>
</div>
</div>
</div>
</div>
</li> -->
</ul>
<div class="page"></div>
</div>
<script src="../js/ajax.js"></script>
<script src="../js/pagination.js"></script>
<script src="../js/list.js"></script>
</body>
</html>
- detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="../bootstrap-3.3.7-dist/css/bootstrap.min.css">
<link rel="stylesheet" href="../css/detail.css">
</head>
<body>
<h1>我是详情页</h1>
<div class="container">
<!-- <ol class="breadcrumb">
<li><a href="#">详情</a></li>
</ol>
<div class="media">
<div class="media-left">
<a href="#">
<img class="media-object"
src="https://image5.suning.cn/uimg/b2c/newcatentries/0070081143-000000000144879464_2_800x800.jpg"
alt="...">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">诗绪刺绣改良旗袍连衣裙女夏装2020年新款中国风印花A字裙子52150
</h4>
<div class="price">
<i class="glyphicon glyphicon-yen"></i>
<span>199.8</span>
</div>
<div class="btn-group" role="group" aria-label="...">
<button type="button" class="btn btn-default">XL</button>
<button type="button" class="btn btn-default">L</button>
<button type="button" class="btn btn-default">M</button>
<button type="button" class="btn btn-default">S</button>
<button type="button" class="btn btn-default">XS</button>
</div>
<div>
<button class="btn btn-warning btn-lg">立即购买</button>
<button class="btn btn-danger btn-lg">查看购物车</button>
</div>
</div>
</div>
<ul class="nav nav-tabs">
<li role="presentation" class="active"><a href="#">Home</a></li>
<li role="presentation"><a href="#">Profile</a></li>
<li role="presentation"><a href="#">Messages</a></li>
</ul>
<div class="goods_detail">
</div> -->
</div>
<script src="../js/cookie.js"></script>
<script src="../js/ajax.js"></script>
<script src="../js/details.js"></script>
</body>
</html>
- car.html
<!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>
<link
rel="stylesheet"
href="../bootstrap-3.3.7-dist/css/bootstrap.min.css"
/>
<link rel="stylesheet" href="../css/car.css" />
</head>
<body>
<div class="car">
<div class="panel panel-default">
<div class="panel-heading">
<div class="checkbox">
<label>
<input
type="checkbox"
id="allChecked"
/>
全选
</label>
</div>
<ul class="nav nav-pills" role="tablist">
<li role="presentation">
<a href="#">
商品种类
<span class="badge kind">0</span>
</a>
</li>
<li role="presentation">
<a href="#">
所选商品的数量
<span class="badge countTotal">0</span>
</a>
</li>
</ul>
</div>
<div class="panel-body">
<!-- <div class="media">
<div class="media-left media-middle">
<label>
<input
type="checkbox"
id="blankCheckbox"
value="option1"
aria-label="..."
/>
</label>
<a href="#">
<img
class="media-object"
src="https://image4.suning.cn/uimg/mcmp/tm/0010131143000000000690044837_1_200x200.jpg"
alt="..."
/>
</a>
</div>
<div class="media-body">
<div class="content">
<h4 class="media-heading">
Middle aligned media
</h4>
<span
class="glyphicon glyphicon glyphicon-yen"
aria-hidden="true"
>
0
</span>
</div>
<div class="btn-group">
<button type="button" class="btn btn-default">
-
</button>
<button type="button" class="btn btn-default">
-
</button>
<button type="button" class="btn btn-default">
+
</button>
</div>
<div class="total">
小计:
<span>¥0</span>
</div>
<button
type="button"
class="close"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
</div>
</div> -->
</div>
<div class="panel-footer">
<div>
总价格:
<span class="totalPrice">¥0</span>
</div>
<button type="button" class="btn btn-info settlement">结算</button>
</div>
</div>
</div>
<!-- 把需要用的js插件引入 -->
<script src="../js/cookie.js"></script>
<script src="../js/ajax.js"></script>
<script src="../js/car.js"></script>
</body>
</html>
(2)js
- login.js
let username = document.querySelector("#username");
let password = document.querySelector("#password");
let form = document.querySelector(".form-horizontal");
form.onsubmit = function () {
let e = window.event;
e.preventDefault();
pAjax({
type: 'post',
url: '../api/login.php',
data: {
username: username.value,
password: password.value
}
}).then(res => {
res = JSON.parse(res);
if (res.code == 1) {
// 登录成功存储 登录的状态
setCookie('login', username.value);
// 跳转页面 如果从购物车过来的时候登录成功去购物车页面
// 否则就去到首页
let url = localStorage.getItem('url');
if (url) {
location.href = url;
// 登录成功的时候把url的这个localstorage值清除
localStorage.removeItem('url');
} else {
location.href = '../index.html';
}
}
})
}
- list.js
let list = document.querySelector(".list");
let page = document.querySelector(".page");
let defaultInfo = {
len: 20,
num: 1,
};
pAjax({
url: "../api/getData.php",
data: {
start: defaultInfo.num,
len: defaultInfo.len,
},
}).then((res) => {
res = JSON.parse(res);
new Pagination(page, {
pageInfo: {
pagenum: 1,
pagesize: defaultInfo.len,
total: res.total,
totalpage: Math.ceil(res.total / defaultInfo.len),
},
textInfo: {
first: "首页",
prev: "上一页",
list: "",
next: "下一页",
last: "最后一页",
},
change: function (num) {
defaultInfo.num = num;
getData();
scrollTo(0, 0);
},
});
});
async function getData() {
let res = await pAjax({
url: "../api/getData.php",
data: {
start: defaultInfo.num,
len: defaultInfo.len,
},
});
res = JSON.parse(res);
renderHtml(res.list);
}
function renderHtml(data) {
let str = "";
data.forEach((item, index) => {
str += ` <li class="list-item">
<div class="title">
<ol class="breadcrumb">
<li><a href="#">${item.cat_one_id}</a></li>
<li><a href="#">${item.cat_two_id}</a></li>
<li class="active">${item.cat_three_id}</li>
</ol>
</div>
<div class="row">
<div>
<div class="thumbnail">
<img src="${item.goods_big_logo}"
alt="...">
<div class="caption">
<h3>${item.goods_name}</h3>
<div class="price">
<i class="glyphicon glyphicon-yen"></i>
<span>${item.goods_price}</span>
</div>
<p>
<a href="./car.html" class="btn btn-primary" role="button">查看购物车</a>
<a href="./detail.html?id=${item.goods_id}" class="btn btn-info" role="button">查看商品详情</a>
</p>
</div>
</div>
</div>
</div>
</li>`;
});
list.innerHTML = str;
}
- details.js
// 打开详情页的时候先查看是否有携带id参数
// 如果没有id参数的时候 跳转到列表
// 如果有id参数的时候 根据id去获取对象的数据 渲染
// http://gz2008.com/day06_code/project/html/detail.html?id=4
let reg = /id=(\d+)/;
if (!reg.test(location.search)) {
location.href = "../html/list.html";
}
// exec() 捕获字符串中满足正则的数据
// 以数组的形式返回
// 索引为0 的位置 得到就是满足正则条件的字符串
// 索引为1 的位置 满足正则条件 圆括号中的字符
let id = reg.exec(location.search)[1];
// console.log(id);
let container = document.querySelector(".container");
// 根据id获取数据
pAjax({
url: "../api/getDetail.php",
data: {
id,
},
}).then((res) => {
res = JSON.parse(res);
renderHtml(res.detail);
});
function renderHtml(data) {
container.innerHTML = `
<ol class="breadcrumb">
<li><a href="#">详情</a></li>
</ol>
<div class="media">
<div class="media-left">
<a href="#">
<img class="media-object"
src="${data.goods_big_logo}"
alt="...">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">${data.goods_name}
</h4>
<div class="price">
<i class="glyphicon glyphicon-yen"></i>
<span>${data.goods_price}</span>
</div>
<div class="btn-group" role="group" aria-label="...">
<button type="button" class="btn btn-default">XL</button>
<button type="button" class="btn btn-default">L</button>
<button type="button" class="btn btn-default">M</button>
<button type="button" class="btn btn-default">S</button>
<button type="button" class="btn btn-default">XS</button>
</div>
<div>
<button class="btn btn-warning btn-lg" id="goCar">查看购物车</button>
<button class="btn btn-danger btn-lg" id="addCar">加入购物车</button>
</div>
</div>
</div>
<ul class="nav nav-tabs">
<li role="presentation" class="active"><a href="#">Home</a></li>
<li role="presentation"><a href="#">Profile</a></li>
<li role="presentation"><a href="#">Messages</a></li>
</ul>
<div class="goods_detail">
${data.goods_introduce}
</div>`;
}
container.onclick = function () {
let e = window.event;
if (e.target.id == "goCar") {
location.href = "../html/car.html";
}
if (e.target.id == "addCar") {
// alert('添加购物车')
// 把当前这个条商品的goods_id ,用户名 ,goods_num 添加到 购物车的表
// goods_id = id
// userName = getCookie('login) 如果没有登录的时候 不能添加数据,提示进行登录
// goods_num 判断这个用户对应的这个goods_id 是否已经存在,如果存在 goods_num++,如果不存在操作添加商品到购物车,其中 goods_num = 1
let login = getCookie("login");
console.log(login);
if (!login) {
alert("没有登录请到登录页面进行登录");
localStorage.setItem("url", location.href);
location.href = "../html/login.html";
return;
}
// 发添加购物车的ajax请求
pAjax({
url: "../api/addCar.php",
type: "post",
data: {
goods_id: id,
userName: login,
},
}).then(function (res) {
console.log(res);
});
}
};
- car.html
/*
【1】 列表页中 点击查看购物车的时候 跳转到购物车页面
【2】 详情页中 点击加入购物车 ,判断是否有的登录
【3】 详情页查看购物车 的时候 跳转到购物车页面
当你打开购物车页面的时候
【1】需要判断 是否有登录
+ 有登录 直接显示购物车数据
+ 没有登录的时候跳转道登录页面(需要把当前页面的地址 存储在本地存储中) 进行登录
+ 登录页面登录成功的时候 需要获取本地存储中的url地址
【4】能够打开购物车页面
+ 把购物车中的数据显示出来(按照用户名获取)
+ 渲染数据
+ 点击 + - 删除的时候 操作购物车的数据
*/
// 判断是否有登录
let login = getCookie("login");
if (!login) {
// 需要把当前页面的地址 存在本地存储
localStorage.setItem("url", location.href);
location.href = "../html/login.html";
}
// 获取当前用户名的 购物车中的数据 渲染到 页面
/*
描述对象:
静态属性:
car :页面中一个名字
login:用户名
动态方法:
init() 初始化,获取元素
getData() 获取数据
render() 渲染结构
calculation() 计算总价 和 数量
changeCount() 加减计算
deleteData()
clearData()
*/
class Car {
constructor(ele, user) {
this.ele = document.querySelector(ele);
this.user = user;
this.init();
}
init() {
this.panelBody = this.ele.querySelector(".panel-body");
this.kind = this.ele.querySelector(".kind");
this.countTotal = this.ele.querySelector(".countTotal");
this.totalPrice = this.ele.querySelector(".totalPrice");
this.allChecked = this.ele.querySelector("#allChecked");
this.getData();
// 利用事件委托给购物车中的元素绑定点击事件
this.ele.onclick = () => {
let e = window.event;
// 全选和单选
if (e.target.id == "allChecked") {
// 商品列表中的数据 前面的复选框的选上
// 操作数据形式来进行选择的操作
// 不能直接操作 数据库中的数据
// 只能把对应数据存在本地 localstorage
// console.log(this.res);
// if (e.target.checked) {
// this.res.forEach((item) => {
// item.is_select = "1";
// });
// } else {
// this.res.forEach((item) => {
// item.is_select = "0";
// });
// }
this.res.forEach((item) => {
item.is_select = e.target.checked ? "1" : "0";
});
} else if (e.target.className == "checked") {
// console.log(e.target.checked);
let id = e.target.getAttribute("index");
// if (e.target.checked) {
// this.res.forEach(item => {
// if (item.goods_id == id) {
// item.is_select = '1'
// }
// })
// } else {
// this.res.forEach((item) => {
// if (item.goods_id == id) {
// item.is_select = "0";
// }
// });
// }
this.res.forEach((item) => {
if (item.goods_id == id) {
item.is_select = e.target.checked ? "1" : "0";
}
});
}
localStorage.setItem("data", JSON.stringify(this.res));
this.render();
// 减少商品的数量
if (e.target.classList.contains("reduce")) {
// 发送一个ajax请求
let id = e.target.parentNode.getAttribute("index");
// 数量的判断
let value = e.target.nextElementSibling.innerHTML * 1 - 1;
this.changeCount(id, value);
}
// 增加商品数量
if (e.target.classList.contains("add")) {
let id = e.target.parentNode.getAttribute("index");
let value = e.target.previousElementSibling.innerHTML * 1 + 1;
this.changeCount(id, value);
}
// 删除商品
if (e.target.classList.contains("del")) {
let id = e.target.getAttribute("index");
this.deleteData(id);
}
// 结算按钮
// 先把本地存储中商品数据 is_select = 1的数据删除
// 循环本地 数据 判断如果 这个条数据的is_select= 1
// 把这条数据的id传递给后端 进行删除
// 结算的是 被勾选的数据
// 当这个数据被勾选之后 is_select = 1
if (e.target.classList.contains("settlement")) {
this.res.forEach((item) => {
if (item.is_select == "1") {
this.deleteData(item.goods_id);
}
});
}
};
}
async getData() {
let res = await pAjax({
url: "../api/getCarData.php",
data: {
username: this.user
},
});
// 获取完数据之后就把数据存在本地
localStorage.setItem("data", res);
// 把数据 直接添加在this对象上
// this.res = JSON.parse(res);
this.render();
}
render() {
this.res = JSON.parse(localStorage.getItem("data"));
this.calculation();
var str = "";
this.res.forEach(function (item, index) {
str += `<div class="media">
<div class="media-left media-middle">
<label>
<input index="${item.goods_id}"
type="checkbox"
class="checked"
${item.is_select == "1" ? "checked" : ""}
/>
</label>
<a href="#">
<img
class="media-object"
src="${item.goods_small_logo}"
/>
</a>
</div>
<div class="media-body">
<div class="content">
<h4 class="media-heading">
${item.goods_name}
</h4>
<span
class="glyphicon glyphicon glyphicon-yen"
aria-hidden="true"
>
${item.goods_price}
</span>
</div>
<div class="btn-group" index="${item.goods_id}">
<button type="button" ${
item.goods_num == 1 ? "disabled" : ""
} class="btn btn-default reduce">-</button>
<button type="button" class="btn btn-default">${
item.goods_num
}</button>
<button type="button" class="btn btn-default add">+</button>
</div>
<div class="total">
小计:
<span>¥${
item.goods_price * item.goods_num
}</span>
</div>
<button
type="button"
class="close del"
index="${item.goods_id}"
>
<span class="del" index="${
item.goods_id
}">×</span>
</button>
</div>
</div>`;
});
this.panelBody.innerHTML = str;
}
calculation() {
// 商品的种类 (data数据的length)
// console.log(this.res);
this.kind.innerHTML = this.res.length;
// 判断数据中的is_select 是否为1
// 如果为1的时候 就把这个条商品的数量相加
this.countTotal.innerHTML = this.res.reduce((pre, cur) => {
if (cur.is_select == "1") {
return pre + cur.goods_num * 1;
}
return pre;
}, 0);
// 计算选中的总价格
let total = this.res.reduce((pre, cur) => {
if (cur.is_select == "1") {
return pre + cur.goods_price * cur.goods_num;
}
return pre;
}, 0);
this.totalPrice.innerHTML = "¥" + total.toFixed(2);
// 当所有的数据的is_select 的值为1 的时候 应该让全选自动选上
this.allChecked.checked = this.res.every((item) => {
return item.is_select == "1";
});
}
async changeCount(id, value) {
let res = await pAjax({
url: "../api/updataCar.php",
data: {
username: this.user,
goods_id: id,
goods_num: value,
},
});
res = JSON.parse(res);
if (res.code) {
this.res.forEach((item) => {
item.goods_num = item.goods_id == id ? value : item.goods_num;
});
}
localStorage.setItem("data", JSON.stringify(this.res));
this.render();
}
async deleteData(id) {
let res = await pAjax({
url: "../api/deleteCar.php",
data: {
username: this.user,
goods_id: id,
},
});
// 当把数据库中的数据删除成功之后 需要更改一下本地存储的数据
res = JSON.parse(res);
if (res.code) {
this.res = this.res.filter((item) => {
return item.goods_id != id;
});
}
localStorage.setItem("data", JSON.stringify(this.res));
this.render();
}
}
new Car(".car", login);
- ajax.js
// 封装ajax请求
/*
参数:
【1】请求的地址
【2】请求方式(get||post)
【3】回调函数(用于获取异步代码执行结果),成功,失败
【4】请求的携带的参数
【5】设置同步或者异步
当函数的参数 过多的时候 应该把参数 写成一个对象传递
{
url:'请求的地址', //请求地址是必须
type:'get', 选填,不填的时候 默认值为get请求
data:{username:'aaa',password:'123123'} || "username=aaa&password=123123", 选填,有参数就传递 没有可以不填,需要有默认值为 ''
async:false, 选填 ,值为布尔值,不填写的时候为 true
success:fucntion(){}, 必填 请求成功之后执行的函数 获取到请求的结果
error:function(){} 选填 请求失败之后执行的函数
}
*/
function ajax(obj) {
// 判断必填的属性 是否有传递
if (!obj.url) {
// d当url没有填写的时候 抛出错误
throw Error("url属性不能为空");
}
// 判断success 是否有传递
if (!obj.success) {
throw Error("success属性不能为空");
}
// 当有一些参数没有传递的时候 需要添加默认值
let option = {
url: obj.url,
type: obj.type || "get",
data: obj.data || "",
async: obj.async || true,
success: obj.success,
error: obj.error || function (err) {
console.log(err);
},
};
// 判断一下 请求方式是否正确 post || get
if (!(option.type == "get" || option.type == "post")) {
throw Error("type属性的取值 暂时只支持 get 和 post");
}
// 判断data参数 是否是 对象 或者字符串
let datatype = Object.prototype.toString.call(option.data);
if (!(datatype == "[object Object]" || datatype == "[object String]")) {
throw Error("data参数的格式 暂时只支持对象或者字符串");
}
// 判断 async 是否是布尔值
if (!(Object.prototype.toString.call(option.async) == "[object Boolean]")) {
throw Error("async的取值只能为布尔值(true|| false)");
}
// 判断success 是否是函数
if (
!(Object.prototype.toString.call(option.success) == "[object Function]")
) {
throw Error("success 必须是一个函数");
}
// 判断error参数是否为函数
if (
!(Object.prototype.toString.call(option.error) == "[object Function]")
) {
throw Error("error 必须是一个函数");
}
// 如果参数为对象的时候 需要把对象转化为
// {name:'老谢',age:48}==>name=老谢&age=18
// "key=value&key=value"
if (Object.prototype.toString.call(option.data) == "[object Object]") {
let str = "";
for (let key in option.data) {
str += key + "=" + option.data[key] + "&";
}
option.data = str.substr(0, str.length - 1);
}
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
// ajax状态
if (xhr.readyState == 4 && /^[23]\d{2}$/.test(xhr.status)) {
// console.log(xhr.responseText);
option.success(xhr.responseText);
}
// http的状态码为 4 或者 5开头的时候
if (/^[45]\d{2}$/.test(xhr.status)) {
option.error(xhr.responseText)
}
};
// 判断请求方式
if (option.type == "get") {
xhr.open(option.type, `${option.url}?${option.data}`, option.async);
xhr.send();
return;
}
xhr.open(option.type, option.url, option.async);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(option.data);
}
function pAjax(obj) {
return new Promise((resolve, reject) => {
ajax({
url: obj.url,
type: obj.type,
data: obj.data,
async: obj.async,
success: function (res) {
resolve(res)
},
error: function(err){
reject(err)
}
})
})
}
- cookie.js
/**
* setCookie 用来设置 cookie 的方法
* @param {STRING} key 你要存储的 cookie 的名称
* @param {STRING} value 你要存储的 cookie 的值
* @param {INT} expires 你设置的过期时间,按照秒计算的
*/
function setCookie(key, value, expires) {
var time = new Date()
var t1 = time.getTime() - 1000 * 60 * 60 * 8 + 1000 * expires
time.setTime(t1)
document.cookie = `${key}=${value};expires=${expires ? time : ''}`
}
/**
* getCookie 用域获取 cookie 的某一个属性的值
* @param {STRING} key 你要获取的 cookie 属性的名
* @return {STRING} 就是你要获取的 cookie 属性的值
*/
function getCookie (key) {
var arr = document.cookie.split('; ')
// 提前准备一个变量,用于记录 cookie 的值
var value = ''
// 如果数组中的 第 0 项 为 true
if (arr[0]) {
// 如果能进入到这里,证明 arr[0] 为 true
// console.log(arr)
// 遍历数组
arr.forEach(item => {
// url=http://gz2008.com/day06_code/project/html/detail.html?id=5
// [url,http://gz2008.com/day06_code/project/html/detail.html?id,5]
var tmp = item.split('=');
if (tmp[0] === key) {
value = tmp[1]
}
})
}
return value
}
/**
* delCookie 用来删除 cookie 中指定的内容的
* @param {STRing} key 你要删除的 cookie 的名
*/
function delCookie (key) {
setCookie(key, 'suibain', -10)
}
- pagination.js
function Pagination(ele, options) {
if (!ele) {
throw new Error('方法必须传递参数,第一个为dom元素,第二个为对象');
}
this.ele = ele
// 把用户传递进来的信息保存一下
this.options = options || {}
// 准备一些分页信息
this.default = {
pageInfo: {
pagenum: 1, // 当前页数
pagesize: 10, // 每页多少条
total: 1000, // 数据总数
totalpage: 100 // 页码总数
},
textInfo: {
first: 'first',
prev: 'prev',
list: '',
next: 'next',
last: 'last'
}
}
// 当页码发生改变的时候就执行这个函数
this.change = this.options.change || function () { }
// 提前准备一个变量,保存 list 里面的元素
this.list = null
// 调用过的入口函数
this.init()
}
Pagination.prototype.init = function () {
this.setDefault()
this.setStyle()
this.dongcidaci()
}
// 使用用户传递的信息替换我自己的信息
Pagination.prototype.setDefault = function () {
if (this.options.pageInfo) {
for (let attr in this.options.pageInfo) {
this.default.pageInfo[attr] = this.options.pageInfo[attr]
}
}
if (this.options.textInfo) {
for (let attr in this.options.textInfo) {
this.default.textInfo[attr] = this.options.textInfo[attr]
}
}
}
// 给大盒子设置样式
Pagination.prototype.setStyle = function () {
this.ele.innerHTML = ''
setCss(this.ele, {
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
})
// 设置完样式就添加元素
this.createEle()
// 添加列表
this.creteList()
// 添加文本框
this.go()
// 禁用的判断
this.isDis()
// 动过以后要执行函数
this.change(this.default.pageInfo.pagenum)
}
// 添加上一页下一页首页末页列表标签到 this.ele 里面
Pagination.prototype.createEle = function () {
for (let attr in this.default.textInfo) {
const div = document.createElement('div')
div.className = attr
if (attr === 'list') {
this.list = div
setCss(div, {
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
})
} else {
setCss(div, {
border: '1px solid #333',
padding: '0 5px',
margin: '0 5px'
})
}
div.innerHTML = this.default.textInfo[attr]
this.ele.appendChild(div)
}
}
// 设置页码
Pagination.prototype.creteList = function () {
const pagenum = this.default.pageInfo.pagenum
const totalpage = this.default.pageInfo.totalpage
if (totalpage <= 9) { // 小于九个直接渲染
for (let i = 1; i <= this.default.pageInfo.totalpage; i++) {
const p = this.crealeP(i)
this.list.appendChild(p)
}
} else { // 大于九个分成几个步骤来渲染
if (pagenum < 5) {
// 1 2 3 4 5 ... 99 100
for (let i = 1; i <= 5; i++) {
this.list.appendChild(this.crealeP(i))
}
const span = document.createElement('span')
span.innerHTML = '...'
this.list.appendChild(span)
for (let i = totalpage - 1; i <= totalpage; i++) {
this.list.appendChild(this.crealeP(i))
}
} else if (pagenum === 5) {
// 1 2 3 4 5 6 7 ... 99 100
for (let i = 1; i <= 7; i++) {
this.list.appendChild(this.crealeP(i))
}
const span = document.createElement('span')
span.innerHTML = '...'
this.list.appendChild(span)
for (let i = totalpage - 1; i <= totalpage; i++) {
this.list.appendChild(this.crealeP(i))
}
} else if (pagenum > 5 && pagenum < totalpage - 4) {
for (let i = 1; i <= 2; i++) {
this.list.appendChild(this.crealeP(i))
}
const span = document.createElement('span')
span.innerHTML = '...'
this.list.appendChild(span)
for (let i = pagenum - 2; i <= pagenum + 2; i++) {
this.list.appendChild(this.crealeP(i))
}
const span2 = document.createElement('span')
span2.innerHTML = '...'
this.list.appendChild(span2)
for (let i = totalpage - 1; i <= totalpage; i++) {
this.list.appendChild(this.crealeP(i))
}
} else if (pagenum === totalpage - 4) {
for (let i = 1; i <= 2; i++) {
this.list.appendChild(this.crealeP(i))
}
const span = document.createElement('span')
span.innerHTML = '...'
this.list.appendChild(span)
for (let i = totalpage - 6; i <= totalpage; i++) {
this.list.appendChild(this.crealeP(i))
}
} else if (pagenum > totalpage - 4) {
for (let i = 1; i <= 2; i++) {
this.list.appendChild(this.crealeP(i))
}
const span = document.createElement('span')
span.innerHTML = '...'
this.list.appendChild(span)
for (let i = totalpage - 4; i <= totalpage; i++) {
this.list.appendChild(this.crealeP(i))
}
}
}
}
// 提取了一个专门用来创建 li 的函数
Pagination.prototype.crealeP = function (i) {
// i 形参就是要拿到循环中的 i 我好渲染文字
// 和当前页面进行比较
const p = document.createElement('p')
p.innerHTML = i
setCss(p, {
border: '1px solid #333',
margin: '0 5px',
padding: '0 5px'
})
if (i === this.default.pageInfo.pagenum) {
setCss(p, {
backgroundColor: 'orange'
})
}
return p
}
// 设置文本款和按钮
Pagination.prototype.go = function () {
const inp = document.createElement('input')
const btn = document.createElement('button')
setCss(inp, {
outline: 'none',
width: '50px',
height: '20px'
})
inp.value = this.default.pageInfo.pagenum
inp.type = 'number'
inp.setAttribute('min', '1')
inp.setAttribute('max', this.default.pageInfo.totalpage)
setCss(btn, {
outline: 'none',
width: '30px',
height: '24px',
marginLeft: '5px'
})
btn.innerHTML = 'go'
this.ele.appendChild(inp)
this.ele.appendChild(btn)
}
// 判断一下禁用
Pagination.prototype.isDis = function () {
if (this.default.pageInfo.pagenum === 1) {
this.ele.children[0].style.backgroundColor = '#ccc'
this.ele.children[1].style.backgroundColor = '#ccc'
}
if (this.default.pageInfo.pagenum === this.default.pageInfo.totalpage) {
this.ele.children[3].style.backgroundColor = '#ccc'
this.ele.children[4].style.backgroundColor = '#ccc'
}
}
// 动起来
Pagination.prototype.dongcidaci = function () {
// 事件委托来做
this.ele.addEventListener('click', e => {
e = e || window.event
const target = e.target
if (target.className === 'first' && this.default.pageInfo.pagenum !== 1) {
this.default.pageInfo.pagenum = 1
this.setStyle()
}
if (target.className === 'prev' && this.default.pageInfo.pagenum !== 1) {
this.default.pageInfo.pagenum--
this.setStyle()
}
if (target.className === 'next' && this.default.pageInfo.pagenum !== this.default.pageInfo.totalpage) {
this.default.pageInfo.pagenum++
this.setStyle()
}
if (target.className === 'last' && this.default.pageInfo.pagenum !== this.default.pageInfo.totalpage) {
this.default.pageInfo.pagenum = this.default.pageInfo.totalpage
this.setStyle()
}
if (target.nodeName === 'P' && target.innerHTML - 0 !== this.default.pageInfo.pagenum) {
this.default.pageInfo.pagenum = target.innerHTML - 0
this.setStyle()
}
if (target.nodeName === 'BUTTON' && target.previousElementSibling.value - 0 !== this.default.pageInfo.pagenum) {
this.default.pageInfo.pagenum = target.previousElementSibling.value - 0
this.setStyle()
}
})
}
function setCss(ele, options) {
for (let attr in options) {
ele.style[attr] = options[attr]
}
}
(3)css
- login.css
.form-horizontal {
width: 500px;
border: 1px solid #ccc;
padding: 20px;
margin: auto;
margin-top: 100px;
border-radius: 5px;
box-shadow: 0px 0px 5px #000;
}
.form-horizontal label {
width: 100px;
}
.form-horizontal>.form-group>div {
width: 300px;
}
- detail.css
.container {
border: 1px solid #ccc;
}
.container .breadcrumb {
margin-left: -15px;
margin-right: -15px;
}
.media .media-object {
width: 300px;
}
.media .price {
font-size: 50px;
color: red;
margin: 10px 0px;
}
.media .btn-group {
margin-bottom: 20px;
}
.goods_detail img{
width: 100%;
}
- list.css
* {
padding: 0;
margin: 0;
}
ul,
li {
list-style: none;
}
.container {
padding-bottom: 30px;
}
ul {
overflow: hidden;
}
.list-item {
width: 260px;
border: 1px solid #ccc;
float: left;
margin: 10px 10px;
}
.list-item .row {
margin: 0;
}
.list-item .title {
margin-top: 10px;
display: flex;
justify-content: center;
}
.list-item .title .breadcrumb {
height: 36px;
overflow: hidden;
}
.list-item .row h3 {
text-overflow: ellipsis;
/*有些示例里需要定义该属性,实际可省略*/
display: -webkit-box;
-webkit-line-clamp: 2;
/*规定超过两行的部分截断*/
-webkit-box-orient: vertical;
overflow: hidden;
word-break: break-all;
/*在任何地方换行*/
}
.list-item .row .price {
font-size: 30px;
color: red
}
.page {
height: 40px;
border: 1px solid skyblue;
width: 60%;
margin: auto;
}
.page p {
cursor: pointer;
}
- car.css
* {
padding: 0;
margin: 0;
}
ul,
li {
list-style: none;
}
.car {
width: 80%;
margin: 10px auto;
}
.car .panel-heading {
height: 60px;
}
.car .checkbox {
float: left;
height: 100%;
}
.car .nav {
float: right;
height: 100%;
}
.car .panel-footer {
height: 60px;
}
.car .panel-footer div {
float: left;
height: 100%;
line-height: 40px;
}
.car .panel-footer button {
float: right;
height: 100%;
}
.car .media {
display: flex;
}
.car .media-left {
width: 120px;
display: flex;
align-items: center;
margin-right: 20px;
}
.car .media-left label {
margin-right: 10px;
}
.car .media-object {
width: 100px;
height: 100px;
}
.car .media-body {
display: flex;
align-items: center;
}
.car .media-body .content {
flex: 4;
height: 100%;
}
.car .media-body .btn-group{
flex: 1;
}
.car .media-body .total{
text-align: center;
flex: 1;
}
.car .media-body .close{
flex: 1;
}
- index.css
(4)api
- login.php
<?php
$con = mysqli_connect('localhost','root','123456','goodsList');
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM `userlist` WHERE `username`='$username' AND `password`='$password'";
$res = mysqli_query($con,$sql);
if (!$res) {
die('error for mysql: ' . mysqli_error());
}
$row = mysqli_fetch_assoc($res);
if (!$row) {
// 没有匹配的数据 登录失败
echo json_encode(array(
"code" => 0,
"message" => "登录失败"
));
} else {
// 有匹配的数据 登录成功
echo json_encode(array(
"code" => 1,
"message" => "登录成功"
));
}
?>
- getData.php
<?php
$con = mysqli_connect('localhost','root','123456','goodsList');
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM `userlist` WHERE `username`='$username' AND `password`='$password'";
$res = mysqli_query($con,$sql);
if (!$res) {
die('error for mysql: ' . mysqli_error());
}
$row = mysqli_fetch_assoc($res);
if (!$row) {
// 没有匹配的数据 登录失败
echo json_encode(array(
"code" => 0,
"message" => "登录失败"
));
} else {
// 有匹配的数据 登录成功
echo json_encode(array(
"code" => 1,
"message" => "登录成功"
));
}
?>
- getDetail.php
<?php
$con = mysqli_connect('localhost','root','123456','goodsList');
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM `userlist` WHERE `username`='$username' AND `password`='$password'";
$res = mysqli_query($con,$sql);
if (!$res) {
die('error for mysql: ' . mysqli_error());
}
$row = mysqli_fetch_assoc($res);
if (!$row) {
// 没有匹配的数据 登录失败
echo json_encode(array(
"code" => 0,
"message" => "登录失败"
));
} else {
// 有匹配的数据 登录成功
echo json_encode(array(
"code" => 1,
"message" => "登录成功"
));
}
?>
- getCarData.php
<?php
$userName = $_GET['username'];
// x先去获取car中这个用户所有的goods_id
// 循环获取的结果 然后执行SELECT * FROM `goods` WHERER `goods_id` = id
$con = mysqli_connect('localhost','root','123456','goodsList');
$sql = "SELECT * FROM `goods` WHERE `goods_id` in (SELECT `goods_id` FROM `car` WHERE `username` = '$userName')";
$res = mysqli_query($con,$sql);
if(!$res){
die('数据库链接错误' . mysqli_error($con));
}
$arr = array();
$row = mysqli_fetch_assoc($res);
while($row){
array_push($arr,$row);
$row = mysqli_fetch_assoc($res);
}
// 获取购物车表这个用户所有的数据
$carSql = "SELECT * FROM `car` WHERE `userName` = '$userName'";
$carRes = mysqli_query($con,$carSql);
if(!$carRes){
die('数据路链接错误' . mysqli_error($con));
}
$car = array();
$carRow = mysqli_fetch_assoc($carRes);
while($carRow){
array_push($car,$carRow);
$carRow = mysqli_fetch_assoc($carRes);
}
// 需要给返回的数据添加 goods_num
for($i = 0;$i <count($arr);$i++){
for($j = 0;$j< count($car);$j++){
if($arr[$i]['goods_id'] == $car[$j]['goods_id']){
$arr[$i]['goods_num'] = $car[$j]['goods_num'];
}
}
}
print_r(json_encode($arr,JSON_UNESCAPED_UNICODE));
?>
- deleteCar.php
<?php
$userName = $_GET['username'];
// x先去获取car中这个用户所有的goods_id
// 循环获取的结果 然后执行SELECT * FROM `goods` WHERER `goods_id` = id
$con = mysqli_connect('localhost','root','123456','goodsList');
$sql = "SELECT * FROM `goods` WHERE `goods_id` in (SELECT `goods_id` FROM `car` WHERE `username` = '$userName')";
$res = mysqli_query($con,$sql);
if(!$res){
die('数据库链接错误' . mysqli_error($con));
}
$arr = array();
$row = mysqli_fetch_assoc($res);
while($row){
array_push($arr,$row);
$row = mysqli_fetch_assoc($res);
}
// 获取购物车表这个用户所有的数据
$carSql = "SELECT * FROM `car` WHERE `userName` = '$userName'";
$carRes = mysqli_query($con,$carSql);
if(!$carRes){
die('数据路链接错误' . mysqli_error($con));
}
$car = array();
$carRow = mysqli_fetch_assoc($carRes);
while($carRow){
array_push($car,$carRow);
$carRow = mysqli_fetch_assoc($carRes);
}
// 需要给返回的数据添加 goods_num
for($i = 0;$i <count($arr);$i++){
for($j = 0;$j< count($car);$j++){
if($arr[$i]['goods_id'] == $car[$j]['goods_id']){
$arr[$i]['goods_num'] = $car[$j]['goods_num'];
}
}
}
print_r(json_encode($arr,JSON_UNESCAPED_UNICODE));
?>
- updataCar.php
<?php
$userName = $_GET['username'];
// x先去获取car中这个用户所有的goods_id
// 循环获取的结果 然后执行SELECT * FROM `goods` WHERER `goods_id` = id
$con = mysqli_connect('localhost','root','123456','goodsList');
$sql = "SELECT * FROM `goods` WHERE `goods_id` in (SELECT `goods_id` FROM `car` WHERE `username` = '$userName')";
$res = mysqli_query($con,$sql);
if(!$res){
die('数据库链接错误' . mysqli_error($con));
}
$arr = array();
$row = mysqli_fetch_assoc($res);
while($row){
array_push($arr,$row);
$row = mysqli_fetch_assoc($res);
}
// 获取购物车表这个用户所有的数据
$carSql = "SELECT * FROM `car` WHERE `userName` = '$userName'";
$carRes = mysqli_query($con,$carSql);
if(!$carRes){
die('数据路链接错误' . mysqli_error($con));
}
$car = array();
$carRow = mysqli_fetch_assoc($carRes);
while($carRow){
array_push($car,$carRow);
$carRow = mysqli_fetch_assoc($carRes);
}
// 需要给返回的数据添加 goods_num
for($i = 0;$i <count($arr);$i++){
for($j = 0;$j< count($car);$j++){
if($arr[$i]['goods_id'] == $car[$j]['goods_id']){
$arr[$i]['goods_num'] = $car[$j]['goods_num'];
}
}
}
print_r(json_encode($arr,JSON_UNESCAPED_UNICODE));
?>
- clearCarData.php
<?php
// 获取传递过来的用名 和 商品id
$username = $_GET['username'];
$con = mysqli_connect('localhost','root','123456','goodsList');
$sql = "DELETE FROM `car` WHERE `username` = '$username'";
$res = mysqli_query($con,$sql);
if(!$res){
// die('error for mysqli' . mysqli_error());
echo json_encode(array("code"=>false,"msg"=>"删除数据失败"));
}else{
echo json_encode(array("code"=>$res,"msg"=>"删除数据成功"));
}
?>
- addCar.php
<?php
$goods_id = $_POST['goods_id'];
$userName = $_POST['userName'];
$con = mysqli_connect('localhost','root','123456','goodsList');
// 先去判断 这个用户对应的这个goods_id是否存在,如果存在直接修改这条数据的goods_num
// 如果不存在 才把这个条数据添加到购物车数据表中
$sql = "SELECT * FROM `car` WHERE `userName` = '$userName' AND `goods_id` = '$goods_id'";
$res = mysqli_query($con,$sql);
if(!$res){
die('数据库链接错误' . mysqli_error($con));
}
$row = mysqli_fetch_assoc($res);
if(!$row){
// 说明不存在 这个用户名对应的这个条goods_id
// 把这条数据添加到购物车表
$addSql = "INSERT INTO `car` VALUES (null, '$goods_id', '$userName', '1')";
$addRes = mysqli_query($con,$addSql);
if(!$addRes){
die('数据库链接错误' . mysqli_error($con));
}
print_r(json_encode(array('code'=>$addRes,"msg"=>"添加成功"),JSON_UNESCAPED_UNICODE));
}else{
$goods_num = ++$row['goods_num'];
$updat = "UPDATE `car` SET `goods_num` = '$goods_num' WHERE `userName` = '$userName' AND `goods_id` = '$goods_id'";
$updataRes = mysqli_query($con,$updat);
if(!$updataRes){
die('数据库链接错误' . mysqli_error($con));
}
print_r(json_encode(array('code'=>$updataRes,"msg"=>"添加成功"),JSON_UNESCAPED_UNICODE));
}
?>