目录
概述
通过原生的html+js+css实现添加到购物车的一个效果,包含了数据操作和动画效果
首先先看效果
购物车效果
一、先建立单个物品的相关数据
处理单个数据体,在里面处理单个的总价、选中数量、是否选中、增加数量、减少数量
class ZBClassGoodsInfo{
//构建
constructor(goods){
this.data = goods;
this.choose = 0;
}
//返回当前物品的总价
getTotalPrice(){
return this.choose * this.data.price;
}
//判断当前物品是否选中
isChoose(){
return this.choose > 0;
}
//增加数量
increase(){
this.choose++;
}
//减少数量
decrease(){
if(this.choose <= 0){
return;
}
this.choose--;
}
}
二、对单个数据进行处理
处理已准备好的数据,或者是从接口中拿的数据, 计算总价、增加数量、减少数量、获取选择的总数量、判断是否有选中数量、判断是否大于起送金额、计算距离起送的差、是否选中
//初始化页面数据
class ZBClassInitData{
//构建
constructor(){
var uiGoods = [];
for(var i in goodsList){
var tempGoods = new ZBClassGoodsInfo(goodsList[i]);
uiGoods.push(tempGoods);
}
this.uiGoods = uiGoods;
this.startPrice = 1000;
this.delivery = 50;
}
//获取总价
getTotalPrice(){
var totalPrice = 0;
for(var i=0;i<this.uiGoods.length;i++){
var goods = this.uiGoods[i];
totalPrice += goods.getTotalPrice();
}
return totalPrice;
}
//增加选中物品的数量
increase(index){
this.uiGoods[index].increase();
}
//减少选中物品的数量
decrease(index){
this.uiGoods[index].decrease();
}
//得到总计选中的数量
getChooseNum(){
var totalNum = 0;
for(var i=0;i<this.uiGoods.length;i++){
totalNum += this.uiGoods[i].choose;
}
return totalNum;
}
//判断购物车中是否有商品
hasGoods(){
return this.getChooseNum() > 0;
}
//判断是否大于最低起送要求
hasCrossDelivery(){
return this.getTotalPrice() > this.startPrice;
}
//计算还差多少钱达到起送金额
diffDelivery(){
return this.startPrice - this.getTotalPrice();
}
//是否选中
isChoose(index){
return this.uiGoods[index].isChoose();
}
}
三、使用原生的js初始化页面
创建页面要展示的数据对象,在里面完成各种需要的操作封装,直接看代码,不啰嗦
//展示页面数据
class ZBClassPage{
constructor(){
this.doms = {
container:document.querySelector("#container"),
goodsContnet:document.querySelector(".zb-goods-list"),
cateBlock:document.querySelector(".zb-cate-list"),
delivery:document.querySelector(".zb-bottom-delivery"),
totalprice:document.querySelector(".zb-bottom-total-price"),
cartblock:document.querySelector(".zb-page-cart"),
cartnum:document.querySelector(".zb-page-cart-num"),
subbtn:document.querySelector(".zb-bottom-right"),
tocar:document.querySelector(".zb-to-car")
};
this.pageGoods = new ZBClassInitData();
//物品列表
this.createHtml();
//计算分类的高度
//设置配送费用
this.updateFooter();
//监听动画
this.pageListener();
var cartRect = this.doms.cartblock.getBoundingClientRect();
var targetRect = {
x:cartRect.left + cartRect.width/2,
y:cartRect.top + cartRect.height/4,
};
this.cartRect = targetRect;
}
pageListener(){
this.doms.cartblock.addEventListener('animationend',function(){
this.classList.remove("zb-animate");
});
}
//创建页面的元素
createHtml(){
var html = "";//创建字符串
for(var i in this.pageGoods.uiGoods){
var goods = this.pageGoods.uiGoods[i];
html += `<div class="zb-goods-item">
<div class="zb-goods-img">
<img src="${goods.data.img}">
</div>
<div class="zb-goods-info">
<div class="zb-goods-title zb-elp-2">${goods.data.title}</div>
<div class="zb-goods-desc zb-elp-1">
${goods.data.desc}
</div>
<div class="zb-goods-sell">
月售 ${goods.data.sellNum} 好评${goods.data.favoriteRate}%
</div>
<div class="zb-goods-bottom">
<div class="zb-goods-price">
<span class="zb-goods-price-unit">¥</span>${goods.data.price}
</div>
<div class="zb-goods-btn">
<div class="zb-iconfont zb-icon-jianhao zb-decrease" data-index="${i}"></div>
<div class="zb-goods-num">${goods.choose}</div>
<div class="zb-iconfont zb-icon-jiahao1 zb-increase" data-index="${i}"></div>
</div>
</div>
</div>
</div>`;
}
this.doms.goodsContnet.innerHTML = html;
}
//增加数量
increase(index){
this.pageGoods.increase(index);
this.updateGoodsItem(index);
this.addMove(index);
this.cartAnimate();
}
//减少数量
decrease(index){
this.pageGoods.decrease(index);
this.updateGoodsItem(index);
}
//更新元素
updateGoodsItem(index){
var curItem = this.doms.goodsContnet.children[index];
if(this.pageGoods.isChoose(index)){
curItem.classList.add("zb-active");
}else{
curItem.classList.remove("zb-active");
}
var goodsnum = curItem.querySelector(".zb-goods-num");
goodsnum.textContent = this.pageGoods.uiGoods[index].choose;
//更新底部数据
this.updateFooter();
}
//更新底部
updateFooter(){
//总费用
this.doms.totalprice.textContent = `¥${this.pageGoods.getTotalPrice()}`;
//配送费
var deliveryDom = this.doms.delivery;
deliveryDom.textContent = `配送费¥${this.pageGoods.delivery}`;
//选中的总数量
var chooseTotal = this.pageGoods.getChooseNum();
this.doms.cartnum.textContent = chooseTotal;
//先移除样式
this.doms.cartblock.classList.remove("zb-active");
if(chooseTotal > 0){
this.doms.cartnum.style.display = "block";
this.doms.cartblock.classList.add("zb-active");
}else{
this.doms.cartnum.style.display = "none";
}
this.doms.subbtn.classList.remove("zb-cross");
this.doms.subbtn.textContent = `还差¥${this.pageGoods.diffDelivery()}元起送`;
//计算起送费
if(this.pageGoods.hasCrossDelivery()){
this.doms.subbtn.textContent = `去结算`;
this.doms.subbtn.classList.add("zb-cross");
}
}
//动画
cartAnimate(){
this.doms.cartblock.classList.add("zb-animate");
}
//加入的动画
addMove(index){
//计算点击的位置
var increaseBtn = this.doms.goodsContnet.children[index].querySelector(".zb-increase");
var increaseRect = increaseBtn.getBoundingClientRect();
var sourceRect = {
x:increaseRect.left,
y:increaseRect.top
}
var div = document.createElement("div");
div.className = "zb-to-car";
var divChild = document.createElement("div");
divChild.className = "zb-iconfont zb-icon-jiahao1 zb-increase";
div.style.transform = `translateX(${sourceRect.x}px)`;
divChild.style.transform = `translateY(${sourceRect.y}px)`;
div.appendChild(divChild);
document.body.appendChild(div);
//先进行渲染
div.clientWidth;
div.style.transform = `translateX(${this.cartRect.x}px)`;
divChild.style.transform = `translateY(${this.cartRect.y}px)`;
var that = this;
div.addEventListener('transitionend',function(){
div.remove();
that.cartAnimate();
},{
once:true
});
}
}
四、调用已封装好的方法
直接调用已经封装好的方法来完成整个过程
var ui = new ZBClassPage();
ui.doms.goodsContnet.addEventListener("click",function(e){
if(e.target.classList.contains("zb-increase")){
var index = +e.target.dataset.index;
ui.increase(index)
}else if(e.target.classList.contains("zb-decrease")){
var index = +e.target.dataset.index;
ui.decrease(index)
}
});
总结
通过原生的js操作dom对象,来完成页面的展示,使用css来实现动画展示,整个过程中没有用到任何的框架。