购物车:
数量组件:
class StepNum {
constructor(parent, data) {
this._data = data;
this.num = data.num;
this.step = 1;
this.evt = new Event(StepNum.CHANGENUM);
// this.flag = false;
if (!parent) parent = document.body;
this.div = this.createDiv(parent);
this.animate();
}
createDiv(parent) {
if (this.div) return this.div;
let div = document.createElement('div');
div.className = 'quantity-form';
div.evt = new Event(StepNum.CHANGENUM);
Object.assign(div.style, {
// fontSize: '0',
textAlign: 'center',
position: 'absolute',
overflow: 'hidden',
})
let divCon = document.createElement('div');
let p1 = document.createElement('p');
p1.textContent = this.num;
// let p2 = document.createElement('p');
// p2.textContent = 2;
Object.assign(divCon.style, {
position: 'absolute',
top: '0',
left: '17px',
width: '47px',
backgroundColor: '#fff',
textAlign: 'center',
fontSize: '13px',
})
Object.assign(p1.style, {
margin: '0',
lineHeight: '22px',
})
divCon.appendChild(p1);
div.appendChild(divCon);
this.leftBtn = this.createBtn(div);
this.leftBtn.className = 'reduce';
this.leftBtn.textContent = '-';
this.leftBtn.disabled = this.num>1?false:true;
// this.leftBtn.disabled = true;
// this.createNumInput(div);
this.input = this.createNumInput(div);
this.rightBtn = this.createBtn(div);
this.rightBtn.className = 'increase';
this.rightBtn.textContent = '+';
// this.leftBtn.input = input;
// this.rightBtn.input = input;
this.leftBtn.divCon = divCon;
this.rightBtn.divCon = divCon;
divCon.input = this.input;
this.input.divCon = divCon;
// divCon.add = true;
divCon.self = this;
div.self = this;
parent.appendChild(div);
return div;
}
setNum(num) {
this.input.value = num;
this.num = num;
this.div.firstElementChild.firstElementChild.textContent = num;
// this.evt = new Event(StepNum.CHANGENUM);
// 触发事件,传递参数
this.evt.data = this._data;
this.evt.num = num;
document.dispatchEvent(this.evt);
}
createBtn(parent) {
let btn = document.createElement('button');
let btnStyle = {
outline: 'none',
border: '1px solid #ddd',
padding: '0',
height: '22px',
width: '17px',
cursor: 'pointer',
position: 'relative'
};
Object.assign(btn.style, btnStyle);
parent.appendChild(btn);
btn.addEventListener('click', this.clickHandler);
this.end = true;
return btn;
}
clickHandler(e) {
this.divCon.style.opacity = '1';
if (this.parentNode.self.flag === true) return;
// 隐藏input的value值
this.parentNode.self.input.value = '';
this.parentNode.self.input.style.backgroundColor = 'rgba(255,255,255,.3)';
// 点击加减
// 点击 - 就在p的前面增加一个p top 移动到 0px 然后删除最后一个p
// 点击 + 就在p的后面增加一个p top移动到-22px 然后删除第一个p
if (this === this.parentNode.self.leftBtn) {
// if(this.parentNode.self.num<2){
// this.disabled = true;
// return;
// };
this.divCon.style.top = '-22px';
// this.divCon.flag = false;
this.parentNode.self.num--;
let p2 = document.createElement('p');
Object.assign(p2.style, {
margin: '0',
lineHeight: '22px',
})
p2.textContent = this.parentNode.self.num;
this.divCon.insertBefore(p2, this.divCon.firstElementChild);
this.divCon.add = false;
if (this.parentNode.self.num === 1) {
this.disabled = true;
}
//
// this.disabled = false;
//
} else {
// 点击了+
// this.divCon.flag = true;
this.parentNode.self.leftBtn.disabled = false;
this.parentNode.self.num++;
let p2 = document.createElement('p');
Object.assign(p2.style, {
margin: '0',
lineHeight: '22px',
})
p2.textContent = this.parentNode.self.num;
this.divCon.add = true;
this.divCon.appendChild(p2);
// this.divCon.style.top = '-22px';
// // 1s 后删除
}
// console.log(this.parentNode.self);
this.parentNode.self.flag = true;
// 修改数据
this.parentNode.self._data.num = this.parentNode.self.num;
this.parentNode.self._data.sum = Number(this.parentNode.self._data.num)*Number(this.parentNode.self._data.price);
// this.parentNode.self.end = false;
// 抛出
// this.parentNode.self.evt.data = this.parentNode.self._data;
// this.parentNode.self.evt.num = num;
// document.dispatchEvent(this.parentNode.self.evt);
}
createNumInput(parent) {
let input = document.createElement('input');
// input.value = 1;
Object.assign(input.style, {
outline: 'none',
textAlign: 'center',
padding: '0',
boxSizing: 'border-box',
border: '1px solid #ddd',
height: '22px',
width: '46px',
backgroundColor: 'rgba(255,255,255,.3)',
borderLeftWidth: '0',
borderRightWidth: '0',
position: 'relative',
color: 'rgba(0,0,0,.8)',
fontSize: '13px'
}),
parent.appendChild(input);
input.addEventListener('blur', this.blurHandler);
input.addEventListener('focus', this.focusHandler);
return input;
}
focusHandler(e) {
this.value = '';
this.style.backgroundColor = 'rgb(255,255,255)';
this.style.opacity = 1;
this.divCon.style.opacity = '0';
}
blurHandler(e) {
// 改变数据时将数据抛出;
// 是数字 且大于1
if (isNaN(this.value) || parseInt(this.value) < 1 || !this.value) {
if(!this.parentNode.self.note){
this.parentNode.self.note = this.parentNode.self.createNote(this.parentNode.self.div);
console.log(this.parentNode.self.note);
}
this.parentNode.self.note.style.display = 'block';
this.parentNode.self.setNum(1);
// this.value = 1;
this.parentNode.self.leftBtn.disabled = true;
} else if (this.value === '1') {
this.parentNode.self.setNum(1);
this.parentNode.self.leftBtn.disabled = true;
} else {
this.parentNode.self.setNum(this.value);
this.parentNode.self.leftBtn.disabled = false;
}
}
createNote(parent, text = '商品数量超限') {
if(this.note) return this.note;
let div = document.createElement('div');
Object.assign(div.style, {
backgroundColor: '#fff',
border: '1px solid #ddd',
textAlign: 'center',
position: 'fixed',
zIndex: '1000',
transform: 'translate(-50%,-50%)',
left: '50%',
top: '50%',
display:'none'
})
let p = document.createElement('p');
p.textContent = text;
p.style.margin = '60px 60px 0';
let pCon = document.createElement('p');
pCon.style.margin = '40px';
let a = document.createElement('a');
a.addEventListener('click', function () {
this.parentElement.parentElement.style.display = 'none';
})
Object.assign(a.style, {
textDecoration: 'none',
backgroundColor: 'red',
display: 'inline-block',
padding: '10px 20px',
color: 'rgb(255, 255, 255)',
})
a.href = 'javascript:;';
a.textContent = '知道了';
Object.assign(a.style, {
backgroundColor: 'red',
padding: '10px 20px',
color: '#fff',
})
pCon.appendChild(a);
div.appendChild(p);
div.appendChild(pCon);
parent.appendChild(div);
return div;
}
static get CHANGENUM() {
return 'changenum';
}
animate() {
requestAnimationFrame(this.animate.bind(this));
// 当点击了按钮时 改变flag;
if (!this.flag) return;
if (this.div.firstElementChild.add) {
// +
if (this.div.firstElementChild.offsetTop <= -22) {
console.log('滚动结束');
this.flag = false;
this.div.firstElementChild.firstElementChild.remove();
this.div.firstElementChild.style.top = '0';
this.div.evt.data = this._data;
this.div.evt.num = this.div.firstElementChild.firstElementChild.textContent;
document.dispatchEvent(this.div.evt);
return;
}
this.div.firstElementChild.style.top = this.div.firstElementChild.offsetTop - this.step + 'px';
} else {
// -
if (this.div.firstElementChild.offsetTop >= 0) {
this.flag = false;
this.div.firstElementChild.lastElementChild.remove();
this.div.firstElementChild.style.top = '0';
this.div.evt.data = this._data;
this.div.evt.num = this.div.firstElementChild.firstElementChild.textContent;
document.dispatchEvent(this.div.evt);
return;
}
this.div.firstElementChild.style.top = this.div.firstElementChild.offsetTop + this.step + 'px';
}
}
}
购物列表:
class GoodsItem{
constructor(_props,parent){
this.prop = _props;
this.goods=this.initGoods(parent);
this.render(_props);
}
initGoods(parent){
if(this.goods) return this.goods;
let div=document.createElement("div");
Object.assign(div.style,{
width: "290px",
height: "390px",
marginLeft: "10px",
marginBottom: "20px",
backgroundColor: "white",
position: "relative",
float:"left"
});
this.createImgGoods(div);
this.createPriceCon(div);
parent.appendChild(div);
return div;
}
createImgGoods(parent){
let div=document.createElement("div");
Object.assign(div.style,{
textAlign: "center",
height: "330px",
width: "100%",
position: "relative"
});
this.goodsImg=new Image();
Object.assign(this.goodsImg.style,{
width:'85%',
marginTop: "20px",
transition: "all 1s",
});
this.goodsInfo=document.createElement("p");
Object.assign(this.goodsInfo.style,{
fontSize: "14px",
width: "230px",
overflow: "hidden",
height: "40px",
left: 0,
right: 0,
margin: "auto",
position: "absolute",
lineHeight: "22px",
bottom: "10px"
});
div.appendChild(this.goodsImg);
div.appendChild(this.goodsInfo);
div.addEventListener("mouseenter",this.mouseHandler);
div.addEventListener("mouseleave",this.mouseHandler);
parent.appendChild(div);
}
createPriceCon(parent){
let div=document.createElement("div");
Object.assign(div.style,{
border: "2px solid #e01222",
height: "58px",
width: "286px",
bottom: 0,
position: "absolute"
});
let priceDiv=document.createElement("div");
this.goodsBn=document.createElement("div");
Object.assign(this.goodsBn.style,{
width: "87px",
height: "58px",
position: "absolute",
right: 0,
top:0,
color: "white",
fontSize: "16px",
textAlign: "center",
lineHeight: "58px",
cursor: "pointer",
backgroundColor: "#e01222"
});
this.goodsBn.textContent="立即抢购";
this.goodsBn.self = this;
this.createPriceDiv(priceDiv);
div.appendChild(priceDiv);
div.appendChild(this.goodsBn);
this.goodsBn.addEventListener("click",this.clickHandler);
parent.appendChild(div);
}
createPriceDiv(parent){
let priceDivs=document.createElement("div");
let soldDivs=document.createElement("div");
this.nowPrice=document.createElement("span");
this.initPrice=document.createElement("span");
priceDivs.appendChild(this.nowPrice);
priceDivs.appendChild(this.initPrice);
this.percent=document.createElement("span");
let percentCon=document.createElement("span");
this.soldPercent=document.createElement("span");
percentCon.appendChild(this.soldPercent);
soldDivs.appendChild(this.percent);
soldDivs.appendChild(percentCon);
Object.assign(this.percent.style,{
fontSize: "16px",
marginLeft:"10px",
lineHeight:"10px"
});
Object.assign(this.nowPrice.style,{
fontSize: "24px",
color: "#e01222",
marginLeft: "5px",
lineHeight: "35px"
});
Object.assign(this.initPrice.style,{
fontSize: "14px",
textDecoration: "line-through",
marginLeft: "5px"
});
Object.assign(percentCon.style,{
display: "inline-block",
width: "100px",
height: "10px",
border: "1px solid #e01222",
marginLeft:"20px",
marginTop:"5px",
position: "absolute"
});
Object.assign(this.soldPercent.style,{
position: "absolute",
width: "0%",
height: "10px",
top:0,
bottom: 0,
backgroundColor: "#e01222"
});
parent.appendChild(priceDivs);
parent.appendChild(soldDivs);
}
mouseHandler(e){
if(e.type==="mouseenter"){
this.firstElementChild.style.marginTop="0px";
}else if(e.type==="mouseleave"){
this.firstElementChild.style.marginTop="20px";
}
}
clickHandler(e){
// 点击添加购物车,这里是要向外抛发事件,并且用event将数据传出;
let evt = new Event(GoodsItem.ADD_SHOPPING_CAR);
evt.data = this.self.prop;
document.dispatchEvent(evt);
}
render(_props){
this.goodsImg.src=_props.icon;
this.goodsInfo.textContent=_props.goods;
this.nowPrice.textContent="¥"+_props.nowPrice;
this.initPrice.textContent="¥"+_props.initPrice;
this.goodsBn.id=_props.id;
if(_props.sold>1) return;
this.percent.textContent=(_props.sold*100).toFixed(2)+"%";
this.soldPercent.style.width=_props.sold*100+"%";
}
static get ADD_SHOPPING_CAR(){
return 'add_shopping_car';
}
}
购物页面:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>类与其他之间的事件抛发</title>
<script src="./goodItem.js"></script>
<scrip src="./stepNum.js"></scrip>
</head>
<body>
<div>
<button>
进入购物车
</button>
<!-- <a href='' target="_blank">进入购物车</a>-->
</div>
<script>
let shoppinglist = [];
let data=[
{id:1001,icon:"imgs/03.jpg",goods:"德国DMK进口牛奶 欧德堡(Oldenburger)超高温处理全脂纯牛奶1L*12盒",info:"1L*12",nowPrice:139,initPrice:156,sold:0.5},
{id:1002,icon:"imgs/04.jpg",goods:"帮宝适(Pampers)超薄干爽绿帮纸尿裤L164片(9-14kg)大码 尿不湿箱装",info:"L【9-14kg】",nowPrice:225,initPrice:275,sold:0.5},
{id:1003,icon:"imgs/05.jpg",goods:" 意大利进口 百乐可(BALOCCO) 千层酥饼 脆皮酥薄脆饼干 焦糖味 200g",info:"焦糖脆皮酥200g",nowPrice:27.9,initPrice:40,sold:0.5},
{id:1004,icon:"imgs/06.jpg",goods:"百草味 坚果零食干果 每日坚果 奶油味夏威夷果200g/袋(内含开果器)",info:"夏威夷果奶油味200g/袋",nowPrice:16.9,initPrice:30,sold:0.5},
{id:1005,icon:"imgs/07.jpg",goods:"三星 Galaxy S10 8GB+512GB炭晶黑(SM-G9730)3D超声波屏下指纹超感官全视屏骁龙855双卡双待全网通4G游戏手机 ",info:"炭晶黑\n8GB+512GB",nowPrice:7699,initPrice:9899,sold:0.5},
{id:1006,icon:"imgs/01.jpg",goods:"罗技(G)G102 游戏鼠标 8000DPI RGB鼠标 黑色 吃鸡鼠标 绝地求生",info:"G102有线游戏鼠标 黑色",nowPrice:119,initPrice:146,sold:0.5},
{id:1007,icon:"imgs/02.jpg",goods:"联想(Lenovo)拯救者Y7000英特尔酷睿i5 15.6英寸游戏笔记本电脑( i5-8300H 8G 512G SSD GTX1050 黑)",info:"Y7000【1050 i5 512",nowPrice:5699,initPrice:6200,sold:0.5}
];
let drag = document.createDocumentFragment();
for(let i =0;i<data.length;i++){
let good = new GoodsItem(data[i],drag);
}
document.body.appendChild(drag);
document.addEventListener(GoodsItem.ADD_SHOPPING_CAR,addcarHandler)
function addcarHandler(e) {
// 添加商品
let prop = e.data;
// 如果商品id存在
let item = shoppinglist.filter((i)=>{
return i.id === prop.id;
})
// 找不到值返回空数组
if(!item.length){
let good = {
selected:false,
id:prop.id,
icon:prop.icon,
goods:prop.goods,
info:prop.info,
price:prop.nowPrice,
num:1,
sum:prop.nowPrice,
delete:false
}
shoppinglist.push(good);
}else{
// 浅拷贝
item[0].num++;
}
// 渲染商品购物车
}
let a = document.querySelector('button');
a.addEventListener('click',clickEvent);
function clickEvent(e) {
let url = 'carpage.html?list='+encodeURI(JSON.stringify(shoppinglist));
location.href = url;
}
</script>
</body>
</html>
购物车表格:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>购物车页面</title>
<script src="stepNum.js"></script>
<style>
table td{
/*display: inline-block;*/
}
</style>
</head>
<body>
<script>
let url = location.search;
let deUrl = decodeURI(url)
let data =JSON.parse(deUrl.split('?')[1].split('=')[1]);
let table;
let tdWidth = [40,82,220,170,160,80,140,75];
let inputs;
init();
function init() {
clearTable(table);
table = createTable(document.body,data);
inputs = document.querySelectorAll('input[type="checkbox"]');
document.addEventListener(StepNum.CHANGENUM,stepNumHandler);
}
function stepNumHandler(e) {
// 在data中找到e.data,修改里面的num
data.forEach((i)=>{
if(i.id === e.data.id){
i.num = e.data.num;
i.sum = e.data.sum;
}
})
clearTable(table);
table = createTable(document.body,data);
}
function createTable(parent,data) {
let table = document.createElement('table');
Object.assign(table.style,{
borderCollapse:'collapse',
border:'1px solid #ddd',
width:'990px'
})
createTableHead(table);
createTableBody(table,data);
parent.appendChild(table);
return table;
}
function createTableBody(parent,data) {
let fragment = document.createDocumentFragment();
for(let i =0;i<data.length;i++){
let tr = document.createElement('tr');
Object.assign(tr.style,{
verticalAlign: 'top',
border: '1px solid #ddd',
backgroundColor: 'antiquewhite',
fontSize: '13px'
})
for(let prop in data[i]){
if(prop === 'id')continue;
let td = document.createElement('td');
td.style.textAlign = 'center';
td.style.padding = '20px 0';
switch (prop) {
case 'selected':
let input = document.createElement('input');
input.type = 'checkbox';
input.checked = data[i][prop];
input.addEventListener('click',inputSelectHandler)
Object.assign(input.style,{
verticalAlign: 'baseline',
height: '10px',
marginRight: '20px',
marginLeft:'10px',
textAlign:'left',
})
td.appendChild(input);
td.style.width = '60px';
td.style.textAlign = 'left';
break;
case 'icon':
let img = new Image();
img.src = data[i][prop];
img.width = 100;
td.appendChild(img);
td.style.textAlign = 'left';
td.style.width = '200px';
break;
case 'num':
// parent,data
let stepNum = new StepNum(td,data[i]);
Object.assign(td.style,{
width: '80px',
textAlign: 'center'
})
break;
case 'sum':
td.style.width = '100px';
case 'price':
td.textContent ='¥'+data[i][prop].toFixed(2);
break;
case 'delete':
td.textContent = '删除';
td.style.padding='20px';
td.addEventListener('click',delHandler);
td.style.cursor = 'pointer';
break;
case 'goods':
data[i][prop]=data[i][prop].slice(0,36);
td.style.width = '200px';
td.textContent = data[i][prop];
td.style.textAlign = 'left';
break;
default:
td.textContent = data[i][prop];
break;
}
tr.appendChild(td);
}
fragment.appendChild(tr);
}
parent.appendChild(fragment);
}
function inputSelectHandler(e) {
let flag = true;
for(let i =1;i<inputs.length;i++){
if(inputs[i].checked === false){
flag = false;
break;
}
}
inputs[0].checked = flag;
}
function delHandler(e) {
// 将data中对应的datalist 删除
let trs = Array.from(table.children);
let idx = trs.indexOf(this.parentNode);
data = data.filter((i,index)=>{
return index !== idx-1;
})
this.parentNode.remove();
}
function createTableHead(parent) {
let thlist = ['全选','商品','单价','数量','小计','操作'];
let tr = document.createElement('tr')
for(let i =0;i<thlist.length;i++){
let th = document.createElement('th');
Object.assign(th.style,{
textAlign:'center',
padding:'10px 0',
fontSize:'14px',
fontWeight:'normal'
})
if(thlist[i]==='商品'){
th.colSpan = 2;
th.style.textAlign = 'left';
}
th.textContent = thlist[i];
if(thlist[i]==='全选'){
let selectAll = document.createElement('input');
selectAll.addEventListener('click',selectAllHandler);
selectAll.type = 'checkbox';
Object.assign(selectAll.style,{
verticalAlign: 'baseline',
height: '10px',
marginRight: '20px',
marginLeft:'10px'
})
th.colSpan = 2;
th.style.textAlign = 'left';
th.insertBefore(selectAll,th.firstChild);
}
tr.appendChild(th);
}
parent.appendChild(tr);
}
function selectAllHandler(e) {
// let inputs = document.querySelectorAll('input[type="checkbox"]');
for(let i =1;i<inputs.length;i++){
inputs[i].checked = this.checked;
}
}
function clearTable(table) {
if(table){
table.remove();
}
}
</script>
</body>
</html>