购物车案例详解。利用cookie

购买页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #cont{1000px;overflow: auto;margin: 0 auto;border: solid 1px black;}
        #cont .box{ 250px;border: solid 1px black;box-sizing: border-box;float: left;text-align: center;}
        .box p{line-height: 20px;height:40px;overflow: hidden;margin: 6px 0}
        .box img{200px;height:200px;}
    </style>
</head>
<body>
<h2>这是商品列表<a href="car.html">去结算</a></h2>
<div id="cont">
    <p>不好意思,商品卖完了</p>
</div>
</body>
<script src="js/ajax.js"></script>
<script src="js/cookie.js"></script>
<script>

    // 一、渲染页面
    class Shop{
        constructor(){
            this.url = "http://localhost/1908/shopping/data/goods.json";
            this.cont = document.getElementById("cont");
            this.load();
            this.addEvent();
        }
        load(){
            ajax({
                url:this.url,
                success:res=>{
                this.res = JSON.parse(res);
            // console.log(this.res)
            this.display()
        }
        })
        }
        display(){
            var str = "";
            for(var i=0;i<this.res.length;i++){
                str += `<div class="box" index="${this.res[i].goodsId}">
                            <img src="${this.res[i].img}" alt="">
                            <p>${this.res[i].name}</p>
                            <span>${this.res[i].price}</span>
                            <input type="button" value="加入购物车" class="add">
                        </div>`
            }
            this.cont.innerHTML = str;
        }
        addEvent(){
            var that = this;
            // 二、点击加入
            this.cont.addEventListener("click",function(eve){
                var e = eve || window.event;
                var target = e.target || e.srcElement;
                if(target.className == "add"){
                    // 1.点击时找到当前点击商品的货号
                    that.id = target.parentNode.getAttribute("index");
                    // 2.准备存cookie
                    that.setCookie()
                }
            })
        }
        setCookie(){
            // 三、存储数据(cookie)
            // 商品id,商品数量
            // 多个商品
            // 数据格式:对象为基础,一个对象存储一个商品;多个商品,多个对象,放在一个数组中
            // [{id:"adasd",num:12},{id:"132a",num:6},{},{},{}....]

            this.goods = getCookie("goods") ? JSON.parse(getCookie("goods")) : [];//第一次执行getcookie获取不到,所以为空;这点最难理解。点击按钮的时候肯定是想在原先的基础num上加1,但是有可能你是第一次点击,这时候你就要往里面写cookie,而不能在原先的基础上改变cookie了。
            //this.goods中只有num和id;
            // 3.存之前,判断是第一次还是非第一次
            if(this.goods.length < 1){ //长度小于1,说明肯定是第一次存咯。

                this.goods.push({
                    id:this.id,//id就是你点击的那一个商品的goodsId;
                    num:1//num为1
                })

            }
            else{//虽然页面不是第一次点击,但是可能这个商品是第一次点击,所以依然进行判断
                var onoff = 1;
                for(var i=0;i<this.goods.length;i++){ //遍历整个cookie,判断点击的商品id在之前有没有点击过。
                    if(this.goods[i].id === this.id){

                        this.goods[i].num++;// 存在,增加数量

                        onoff = 0;// 同时修改状态,防止它继续往下执行
                    }
                }
                // 判断状态,不存在
                if(onoff == 1){ //这个商品是第一次点击,与第一次点击商品操作相同
                    // 直接增加
                    this.goods.push({
                        id:this.id,//这个this.id在构造函数时获取到的;
                        num:1
                    })
                }
            }
            // 4.经过第三步对数据的处理,可以将数据再设置回cookie了
            setCookie("goods",JSON.stringify(this.goods))//if执行完之后执行这个;
            console.log(this.goods)
            console.log(JSON.stringify(this.goods))
        }
    }

    new Shop();

</script>
</html>

购物车页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>这是购物车页面<a href="shop.html">继续购物</a></h2>
<table border="1" width="900" align="center">
    <thead>
    <tr>
        <th>图片</th>
        <th>名字</th>
        <th>价格</th>
        <th>数量</th>
        <th>操作</th>
    </tr>
    </thead>
    <tbody>
    <!-- <tr>
        <td><img src=""></td>
        <td>Data</td>
        <td>Data</td>
        <td>Data</td>
        <td>Data</td>
    </tr> -->
    </tbody>
</table>
</body>
<script src="js/cookie.js"></script>
<script src="js/ajax.js"></script>

<script>
    //更改设置cookie都是用的是json样式
        class Car{
            constructor(){
                this.url="http://localhost/shopping/data/goods.json";
                this.tbody = document.querySelector("tbody");
                this.load();
                this.addEvent();
            }
            addEvent(){
                var that=this;
                this.tbody.addEventListener("click",function(eve){
                    var e = eve || window.event;
                    var target = e.target || e.srcElement;
                    if(target.tagName == "SPAN"){
                        // 8.保存删除时的商品id
                        that.id = target.parentNode.parentNode.getAttribute("index");
                        // console.log(that.id)
                        // 9.开始删除:删除DOM,修改cookie
                        target.parentNode.parentNode.remove();
                        that.removeCookie();
                    }
                })
                this.tbody.addEventListener("input",function(eve){
                    var e = eve || window.event;
                    var target = e.target || e.srcElement;
                    if(target.type == "number"){
                        // 11.保存修改商品的id
                        that.id = target.parentNode.parentNode.getAttribute("index");
                        // 保存修改商品的数量
                        that.val = target.value;//自己设的val等于 target.value(是由自己输得)
                        // 修改cookie
                        that.updateCookie()
                    }
                })
            }
            updateCookie(){ //当手动使num的数量增加时,仅仅是在页面上显示增加了,一刷新就恢复原样了。所以要更新cookie中的id。cookie中的id等于自己点击的那个按钮所在商品栏的id;
                // 准备保存出数据的索引
                var i = 0;
                // 遍历数组,找到符合条件的数据
                var onoff = this.goods.some((val,index)=>{//这里的val是cookie中的json的每一个对象。
                    i = index;
                    return val.id == this.id;//val.id是cookie中的id
            })
                if(onoff){
                    // 找到符合的数据之后,更新数组中的数据
                    this.goods[i].num = this.val;//这里的this.val是输入框总的值
                }
                // 将数组再设置回cookie
                setCookie("goods",JSON.stringify(this.goods)) //更改设置cookie都是用的是json样式
            }
            removeCookie(){
                var i=0;
                var onoff=this.goods.some((val,index)=>{ //val是数组对象中中,每一个对象。
                    i=index;//每次将传达的索引存出来。就是所点击的那个id在cookie数组中拍的那个位置。
                    return val.id==this.id;//返回val的id是否等当前点击的id;如果相等返回true,同时index停止往前走。
                })
                if(onoff){ //找到相同的了。
                    this.goods.splice(i,1)
                }
                setCookie("goods",JSON.stringify(this.goods)) //更改了原来的cookie;
            }
            load(){ //找ajax中的id
                var that=this;
                ajax({
                    url:this.url,
                    success:function (res) {
                        that.res=JSON.parse(res)//要在display中同时拿到this.res.id和this.goodsId;若果在ajax中display那就拿不到this.goods.id,若果在getCookie中执行那就拿不到this.res.id。做好的办法是用promise来是他们都执行完在执行diplay,但是目前情况没学。所以我们可以在ajax执行完执行getCookie,然后再getCookie中执行display;
                        that.getCookie();
                    }
                })
            }
            getCookie(){//找cookie中的id
                this.goods=getCookie("goods")?JSON.parse(getCookie("goods")):[];
                this.display();
            }
            display(){
                var str=""
                for(var i=0;i<this.goods.length;i++){
                    for(var j=0;j<this.goods.length;j++){
                        if(this.res[i].goodsId==this.goods[j].id){ //ajax中的数据与cookie中的数据相同时;渲染页面
                            str += `<tr index="${this.goods[j].id}">
                                    <td><img src="${this.res[i].img}"></td>
                                    <td>${this.res[i].name}</td>
                                    <td>${this.res[i].price}</td>
                                    <td><input type="number" value="${this.goods[j].num}" min=1 /></td>
                                    <td><span>删除</span></td>
                                </tr>`;
                        }
                    }

                }
                this.tbody.innerHTML=str
            }

        }
        new Car;
</script>
</html>

ajax.js

function ajax(options){
    // 1.处理默认参数
    var {type,url,success,error,data,timeout} = options;
    type = type || "get";
    data = data || {};
    timeout = timeout || 2000;

    // 2.解析要发送的数据
    var str = "";
    for(var i in data){
        str += `${i}=${data[i]}&`;
    }

    // 3.根据方式,决定是否处理url
    if(type == "get"){
        var d = new Date();
        url = url + "?" + str + "__qft=" + d.getTime();
    }

    // 4.开启ajax
    var xhr = new XMLHttpRequest();
    // 注意:open中的方式
    xhr.open(type,url,true);
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4 && xhr.status == 200){
            // 5.执行成功之前,先判断是否传入
            success && success(xhr.responseText);
            // 成功之后,不应有失败
            error = null;
        }else if(xhr.readyState == 4 && xhr.status != 200){
            // 6.执行失败之前,先判断是否传入
            error && error(xhr.status);
            // 失败之后,不应有成功
            success = null;
            // 且失败不应多次执行
            error = null;
        }
    }

    // 7.如果请求超时,执行失败
    setTimeout(() => {
        error && error("timeout");
    // 失败之后,不应有成功
    success = null;
}, timeout);

    // 8.最后根据type的方式,决定send的发送内容和格式
    if(type == "post"){
        xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
        xhr.send(str)
    }else{
        xhr.send()
    }
}

cookie.js

function setCookie(key,val,options){
    options = options || {};
    var path = "";
    if(options.path){
        path = ";path=" + options.path;
    }
    var expires = "";
    if(options.expires){
        var d = new Date();
        d.setDate(d.getDate()+options.expires);
        expires = ";expires=" + d;
    }
    document.cookie = key + "="+ val + path + expires;
}

function removeCookie(key,options){
    options = options || {};
    options.expires = -1;
    setCookie(key,132,options);
}

function getCookie(key){
    var arr = document.cookie.split("; ");
    for(var i=0;i<arr.length;i++){
        if(arr[i].split("=")[0] === key){
            return arr[i].split("=")[1];
        }
    }
    return "";
}

所需要的Json数据

[{
    "img":"https://img10.360buyimg.com/n7/jfs/t5617/321/1137763311/121847/b9326254/5923eb44Ndae8df59.jpg.webp",
    "name":"微软(Microsoft)Surface Pro 二合一平板电脑 12.3英寸(Intel Core i5 8G内存 256G存储 )",
    "price":"9888.00",
    "goodsId":"ajdaj"
},{
    "img":"https://img13.360buyimg.com/n7/jfs/t17425/6/1117130719/77250/b4afe949/5abb0fc0Nb0fd7afd.jpg.webp",
    "name":"Apple iPad 平板电脑 2018年新款9.7英寸(128G WLAN版/A10 芯片/Touch ID MRJP2CH/A)金色",
    "price":"5999.00",
    "goodsId":"254654"
},{
    "img":"https://img14.360buyimg.com/n2/jfs/t22945/291/2044515279/67669/7a4a50e/5b713f0eN0caa8e0b.jpg.webp",
    "name":"微软(Microsoft)Surface Go 二合一平板电脑 10英寸(英特尔 奔腾 金牌处理器4415Y 8G内存 128G存储)",
    "price":"3738.00",
    "goodsId":"qwqwe"
},{
    "img":"https://img11.360buyimg.com/n2/jfs/t5935/195/2108753717/176060/c849dcb6/593a49a3Nf9c2a052.jpg.webp",
    "name":"Apple MacBook Air 13.3英寸笔记本电脑 银色(2017新款Core i5 处理器/8GB内存/128GB闪存 MQD32CH/A)",
    "price":"5999.00",
    "goodsId":"13ads"
}]
原文地址:https://www.cnblogs.com/hy96/p/11550789.html