[Comprehensive Case] Implementing a Shopping Mall with Native JS


资料链接和启动方法:https://pan.baidu.com/s/1Ka2xcPmsL31MpQhqNnZlCw 提取码:1115

1. Case Description

1. Directory structure

insert image description here

2. conf folder

insert image description here

3. Regularization of username and password and encapsulation of ajax

import {
    
     confg } from "../cof/config.js";
// 1. 正则封装
function test(reg) {
    
    
    return function (str) {
    
    
        return reg.test(str);
    };
}

const testName = test(confg.nameReg);
const testPwd = test(confg.pwdReg);

// 2. 请求封装
function objToStr(obj) {
    
    
    let str = "";
    for (let k in obj) {
    
    
        str += `${
      
      k}=${
      
      obj[k]}&`;
    }
    str = str.slice(0, str.length - 1);
    return str;
}
function createAjax(url) {
    
    
    let baseUrl = url;

    function ajax(options) {
    
    
        if (options.url === undefined) {
    
    
            throw new Error("您没有传递 url, url 为 必传");
        }

        if (
            !(
                /^(GET|POST)$/i.test(options.method) ||
                options.method === undefined
            )
        ) {
    
    
            throw new Error("method 目前仅支持 post 或者 get");
        }

        if (
            !(options.async === undefined || typeof options.async === "boolean")
        ) {
    
    
            throw new Error("async 目前仅支持 ture 或者 false");
        }

        const optionsDataType = Object.prototype.toString.call(options.data);
        if (
            !(
                optionsDataType === "[object Object]" ||
                optionsDataType === "[object String]" ||
                optionsDataType === "[object Undefined]"
            )
        ) {
    
    
            throw new Error("data 目前仅支持 字符串或者 对象");
        }

        const headersType = Object.prototype.toString.call(options.headers);
        if (
            !(
                headersType === "[object Undefined]" ||
                headersType === "[object Object]"
            )
        ) {
    
    
            throw new Error("header 暂时仅支持 对象格式");
        }

        if (
            !(
                options.dataType === undefined ||
                /^(string|json)$/.test(options.dataType)
            )
        ) {
    
    
            throw new Error("dataType 目前仅支持 'string' 或者 'json'");
        }

        const _options = {
    
    
            url: baseUrl + options.url,
            method: options.method || "GET",
            async: options.async ?? true,
            data: options.data || "",
            headers: {
    
    
                "content-type": "application/x-www-form-urlencoded",
                ...options.headers,
            },
            dataType: options.dataType || "string",
        };

        if (!(typeof _options.data === "string")) {
    
    
            _options.data = objToStr(_options.data);
        }

        if (/^GET$/i.test(_options.method)) {
    
    
            _options.url = _options.url + "?" + _options.data;
        }

        const p = new Promise(function (res, rej) {
    
    
            const xhr = new XMLHttpRequest();
            xhr.open(_options.method, _options.url, _options.async);
            xhr.onload = function () {
    
    
                try {
    
    
                    if (_options.dataType === "string") {
    
    
                        res({
    
    
                            code: 1,
                            info: xhr.responseText,
                        });
                    } else {
    
    
                        res({
    
    
                            code: 1,
                            info: JSON.parse(xhr.responseText),
                        });
                    }
                } catch (error) {
    
    
                    res({
    
    
                        code: 0,
                        info: xhr.responseText,
                    });
                }
            };

            if (/^POST$/i.test(_options.method)) {
    
    
                xhr.setRequestHeader(
                    "content-type",
                    _options.headers["content-type"]
                );
            }

            if (_options.headers.authorization) {
    
    
                xhr.setRequestHeader(
                    "authorization",
                    _options.headers.authorization
                );
            }
            /^POST$/i.test(_options.method)
                ? xhr.send(_options.data)
                : xhr.send();
        });

        return p;
    }

    return ajax;
}

const ajax = createAjax(confg.baseUrl);

export const utils = {
    
    
    testName,
    testPwd,
    ajax,
};

Second, the realization of the login page

insert image description here

1. Case effects

insert image description here

2. Login page logic

  1. 采集用户信息     — when clicking on login
  2. 验证信息
    • non-null validation
    • Regular check
  3. 把用户名和密码发送给后端—> Do different things according to the results returned by the backend
    • Jump to the home page
    • Prompt account password error

3. Interface document

  • Request address :/users/login
  • Request method :post
  • Carry parameters :application/x-www-form-urlencoded 格式传递
    insert image description here
  • Response data :根据你的用户名和密码返回登录状态
    insert image description here

4. Code implementation

  • HTML code
<!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>
    <link rel="stylesheet" href="../css/login.css">
</head>
<body>
    <h1>登录页</h1>
    <div class="box">
        <span>用户名密码错误, 请重试 ! ^_^</span>
        <label>
            用户名: <input class="name" type="text">
        </label>
        <label>
            密码: <input class="pwd" type="text">
        </label>
        <button>登录</button>
        <a href="./register.html">没有账号, 请进入注册</a>
    </div>
    <script src="../js/login.js" type="module"></script>
</body>
</html>
  • CSS code
* {
    
    
    margin: 0;
    padding: 0;
}

h1 {
    
    
    width: 100%;
    height: 80px;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: skyblue;
}

.box {
    
    
    width: 600px;
    display: flex;
    flex-direction: column;
    padding: 20px;
    border: 3px solid pink;
    border-radius: 15px;
    margin: 30px auto;
    padding-top: 50px;
    position: relative;
}

.box>label {
    
    
    height: 50px;
    font-size: 22px;
}

.box>label>input {
    
    
    padding-left: 20px;
    font-size: 22px;
}

.box>button {
    
    
    font-size: 22px;
}

.box>span {
    
    
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    top: 10px;
    color: red;
    display: none;
}

.box>span.active {
    
    
    display: block;
}
  • JavaScript code
// 导入公共方法
import {
    
     utils } from "../utils/utils.js";
const {
    
     testName, testPwd, ajax } = utils;

// 获取标签对象
const oBtn = document.querySelector("button");
const nameInp = document.querySelector(".name");
const pwdInp = document.querySelector(".pwd");
const errBox = document.querySelector("span");

// 给button添加点击事件 
oBtn.addEventListener('click', async function(){
    
    
    // 采集用户输入的用户名和密码
    const nameVal = nameInp.value;
    const pwdVal = pwdInp.value;

    // 验证用户信息 --- 非空校验
    // if(nameVal === '' || pwdVal === '')
    if(!nameVal || !pwdVal) {
    
    
        return alert("请填写用户名或密码");
    }

    // 验证用户信息 --- 正则验证
    // if (testName(nameVal) === false  || testPwd(pwdVal) === false) {
    
    
    if(!testName(nameVal) || !testPwd(pwdVal)) {
    
    
        return alert("您的用户名密码, 不符合规则, 请重新填写");
    }

    // 想后端返发送请求
    const res = await ajax({
    
    
        method: "POST",
        url: "/users/login",
        data: `username=${
      
      nameVal}&password=${
      
      pwdVal}`,
        dataType: 'json'
    });
    console.log(res);
    
    if (res.code === 0) {
    
    
        errBox.classList.add("active");
    } else {
    
    
        window.localStorage.setItem("token", res.info.token);
        window.localStorage.setItem("id", res.info.user.id);

        // 1. 先拿到跳转前存储的路径
        const page = window.sessionStorage.getItem('page');
        // 2. 清除存储的路径
        window.sessionStorage.removeItem('page');

        window.location.href = page || "./index.html";
    }
})

5. Return information display

  • Login failed
    insert image description here

  • login successful
    insert image description here

  • token
    insert image description here

3. Realization of the home page

1. Case effects

  • not logged in before
    insert image description here
  • after login
    insert image description here

2. The logic of the home page

  • Analyze the reasons
  1. http is one 无状态请求, there is no association between each request
  2. Just successfully logged in, and immediately jump to the homepage, at this time send a request to obtain user details, from the server's point of view, it is a 两个独立request
  3. so we need something, come on证明我们刚刚登陆成功了
  • Solution
  1. There is a tokenthing called, it is given to us by the server, pay attention有过期时间
  2. When we ask, I put 用户账号和密码给到服务端, and服务端会生成一个token信息
  3. When we send subsequent requests, carry this token, and the server can wait until we have just successfully logged in,
  4. The token is generated by the backend based on our information and only belongs to us加密的文本
  • code logic
  1. Judging that both token and id exist normally
  2. Send a request to the server, and display different pages according to the request result

3. Interface document

  • Note :登录后方可查看
  • Request address :/users/info
  • Request method :get
  • Carry parameters :支持restful风格 localhost:8888/users/info/:id insert image description here
  • response data insert image description here

4. Code implementation

  • HTML code
<!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>
    <link rel="stylesheet" href="../css/index.css">
</head>
<body>
    <h1>
        首页
        <p class="off"><a href="./login.html">您好, 请登录</a></p>
        <p class="on">
            您好, <span>用户名</span>
            <a href="./self.html">个人中心</a>
        </p>
    </h1>
    <div style="font-size: 40px;">
        <a href="./list.html">商品列表</a>
    </div>
    <script src="../js/index.js" type="module"></script>
</body>
</html>
  • CSS code
* {
    
    
    margin: 0;
    padding: 0;
}

h1 {
    
    
    width: 100%;
    height: 80px;
    background-color: skyblue;
    display: flex;
    justify-content: center;
    align-items: center;
    position: relative;
}

h1>p {
    
    
    font-size: 20px;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    right: 50px;
    display: none;
}

h1>p.active {
    
    
    display: block;
}

h1>p>span {
    
    
    color: red;
}
  • JavaScript code
// 导入公共方法
import {
    
     utils } from "../utils/utils.js";
const {
    
     ajax } = utils;

// 获取元素
const offBox = document.querySelector(".off");
const onBox = document.querySelector(".on");

test();
async function test() {
    
    
    const token = window.localStorage.getItem("token");
    const id = window.localStorage.getItem("id");

    if (!token || !id) {
    
    
        // 展示请登录
        offBox.classList.add("active");
        onBox.classList.remove("active");
        return alert("您的token 或者 id 为空, 请先登录");
    }

    // 如果运行这个位置, 证明token和id都存在
    let res = await ajax({
    
    
        url: "/users/info",
        data: `id=${
      
      id}`,
        headers: {
    
    
            authorization: token,
        },
        dataType: "json",
    });
    console.log(res);
    if (res.code == 1) {
    
    
        if (res.info.code === 1) {
    
    
            offBox.classList.remove("active");
            onBox.classList.add("active");
            console.log(res);

            onBox.firstElementChild.innerHTML = res.info.info.nickname;
        } else {
    
    
            window.location.href = './login.html'
        }
    } else {
    
    
        // 可能是token过期, 或者token是伪造的
        offBox.classList.add("active");
        onBox.classList.remove("active");
    }
}

5. Return information display

insert image description here

4. Personal center

1. Case effects

insert image description here

2. The logic of the personal page

  1. Can I enter this page casually?
    • Judging the current是否登录 (token)
  2. request user information渲染页面(users/info)
  3. After modifying user information, click Modify

3. Interface document

  • Interface Documentation for Page Rendering
  • Note :登录后方可查看
  • Request address :/users/info
  • Request method :get
  • Carry parameters :支持restful风格 localhost:8888/users/info/:id insert image description here
  • response data insert image description here
  • Interface document for modifying personal information
  • Notice: 登录后方可修改
  • Request address :/users/update
  • Request method :post
  • Carry parameters :insert image description here
  • response data insert image description here

4. Code implementation

  • HTML code
<!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>
    <link rel="stylesheet" href="../css/self.css">
</head>
<body>
    <h1>个人页
        <p>
            <a href="./index.html">回到首页</a>
            <a href="./rpwd.html">; 修改密码</a>
        </p>
    </h1>
    <div class="box">
        <label>
            用户名: <input class="name" type="text" disabled>
        </label>
        <label>
            用户年龄: <input class="age" type="text">
        </label>
        <label>
            用户昵称: <input class="nickname" type="text">
        </label>
        <label>
            用户性别: <select id="sel">
                <option value="">请选择</option>
                <option value=""></option>
                <option value=""></option>
            </select>
        </label>
        <button>确认修改</button>
    </div>
    <script src="../js/self.js" type="module"></script>
</body>
</html>
  • CSS code
* {
    
    
    margin: 0;
    padding: 0;
}

h1 {
    
    
    width: 100%;
    height: 80px;
    display: flex;
    justify-content: space-evenly;
    align-items: center;
    background-color: skyblue;
}

.box {
    
    
    width: 600px;
    display: flex;
    flex-direction: column;
    padding: 20px;
    border: 3px solid pink;
    border-radius: 15px;
    margin: 30px auto;
    padding-top: 50px;
    position: relative;
}

.box > label {
    
    
    height: 50px;
    font-size: 22px;
}

.box > label > input {
    
    
    padding-left: 20px;
    font-size: 22px;
}

.box > button {
    
    
    font-size: 22px;
}

.box > span {
    
    
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    top: 10px;
    color: red;
    display: none;
}

.box > span.active {
    
    
    display: block;
}
.box select {
    
    
    font-size: 20px;
    padding-left: 15px;
}

  • JavaScript code
// 导入公共方法
import {
    
     utils } from "../utils/utils.js";
const {
    
     ajax } = utils;

// 获取DOM节点
const nameInp = document.querySelector(".name");
const ageInp = document.querySelector(".age");
const nickInp = document.querySelector(".nickname");
const selBox = document.querySelector("#sel");
const btn = document.querySelector("button");

// 获取到 token 与 id
const token = window.localStorage.getItem("token");
const id = window.localStorage.getItem("id");

test();
async function test() {
    
    
    // 0. 必须登陆状态, 才能进入页面
    if (!token || !id) {
    
    
        if (confirm("您当前没有登陆, 点击确定跳转登录页")) {
    
    
            window.sessionStorage.setItem("page", window.location.href);
            window.location.href = "./login.html";
        }
    }

    // 1. 确保登陆过后, 拿到用户信息并渲染页面
    let {
    
     info } = await ajax({
    
    
        url: "/users/info",
        data: `id=${
      
      id}`,
        dataType: "json",
        headers: {
    
    
            authorization: token,
        },
    });

    console.log(info);
    if (info.code === 1) {
    
    
        // 页面渲染
        nameInp.value = info.info.username;
        ageInp.value = info.info.age;
        nickInp.value = info.info.nickname;
        selBox.value = info.info.gender;
    } else if (info.code === 401 || info.code === 0) {
    
    
        window.location.href = "./login.html";
    }
}


// 2. 修改用户信息, 发送请求
btn.onclick = async function () {
    
    
    // 2.1 用户信息收集
    const age = ageInp.value;
    const gender = selBox.value;
    const nickname = nickInp.value;

    // console.log(age, gender, nickname)
    if (!age || !gender || !nickname) {
    
    
        alert("请输入年龄昵称,以及性别后再次修改");
        return;
    }
    // 2.2 拿到用户信息 发送请求
    let {
    
     info } = await ajax({
    
    
        url: "/users/update",
        method: "POST",
        data: {
    
     id, age, gender, nickname },
        dataType: "json",
        headers: {
    
    
            authorization: token,
        },
    });

    if (info.code == 1) {
    
    
        alert("用户信息修改成功");
    }
};

5. Return information display

insert image description here

5. Modify password

1. Case effects

insert image description here

2. The logic of changing the password

  1. Thinking: Can I enter casually?
    • must be登陆状态的 (token)
  2. front-end validation
    • 不能为空
    • 正则验证
    • verify新密码与重复新密码必须相同
  3. Satisfy the above three points, send the request

3. Interface document

  • Note :登录后方可修改
  • Request address :/users/rpwd
  • Request method :post
  • Carry parameters :insert image description here
  • Response data :修改密码成功后, 会自动注销当前登录状态, 需要重新登录 insert image description here

4. Code implementation

  • HTML
<!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>
    <link rel="stylesheet" href="../css/self.css">
</head>
<body>
    <h1>修改密码
        <p>
            <a href="./index.html">回到首页</a>
            <a href="./rpwd.html">; 修改密码</a>
        </p>
    </h1>

    <div class="box">
        <label>
            旧密码: <input class="oldpwd" type="text">
        </label>
        <label>
            新密码: <input class="newpwd" type="text">
        </label>
        <label>
            重复新密码: <input class="rnewpwd" type="text">
        </label>
        <button>确认修改</button>
    </div>
    <script src="../js/rpwd.js" type="module"></script>
</body>
</html>
  • CSS code
* {
    
    
    margin: 0;
    padding: 0;
}

h1 {
    
    
    width: 100%;
    height: 80px;
    display: flex;
    justify-content: space-evenly;
    align-items: center;
    background-color: skyblue;
}

.box {
    
    
    width: 600px;
    display: flex;
    flex-direction: column;
    padding: 20px;
    border: 3px solid pink;
    border-radius: 15px;
    margin: 30px auto;
    padding-top: 50px;
    position: relative;
}

.box > label {
    
    
    height: 50px;
    font-size: 22px;
}

.box > label > input {
    
    
    padding-left: 20px;
    font-size: 22px;
}

.box > button {
    
    
    font-size: 22px;
}

.box > span {
    
    
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    top: 10px;
    color: red;
    display: none;
}

.box > span.active {
    
    
    display: block;
}
.box select {
    
    
    font-size: 20px;
    padding-left: 15px;
}
  • JavaScript code
import {
    
     utils } from "../utils/utils.js";
const {
    
     ajax, testPwd } = utils;

// 0. 获取元素
const oBtn = document.querySelector("button");
const oldpwd = document.querySelector(".oldpwd");
const newpwd = document.querySelector(".newpwd");
const rnewpwd = document.querySelector(".rnewpwd");

const token = window.localStorage.getItem("token");
const id = window.localStorage.getItem("id");

test();
function test() {
    
    
    if (!token || !id) {
    
    
        window.sessionStorage.setItem("page", window.location.href);
        window.location.href = "./login.html";
    }
}

oBtn.addEventListener('click', async function () {
    
    
    // 收集用户输入的信息
    const oldPassword = oldpwd.value;
    const newPassword = newpwd.value;
    const rNewPassword = rnewpwd.value;

    // 1. 验证密码不能为空
    if (!oldPassword || !newPassword || !rNewPassword) {
    
    
        return alert("密码不能为空");
    }

    // 2. 正则校验
    if (!testPwd(oldPassword) || !testPwd(newPassword) || !testPwd(rNewPassword)) {
    
    
        return alert("请正确填写密码");
    }

    // 3. 新密码与重复新密码 必须相同
    if (newPassword !== rNewPassword) {
    
    
        return alert("新密码与重复新密码 必须相同");
    }

    let {
    
     info } = await ajax({
    
    
        url: "/users/rpwd",
        method: "POST",
        data: {
    
     id, oldPassword, newPassword, rNewPassword },
        dataType: 'json',
        headers: {
    
    
            authorization: token
        }
    });

    if (info.code === 1) {
    
    
        if (confirm('修改密码成功, 已经注销登录状态, 点击确定, 跳转登录页 ^_^')) {
    
    
            // window.sessionStorage.setItem("page", window.location.href);
            window.location.href = "./login.html";
        }
    }
    console.log(info)
})

6. Register a new user

1. Case effects

insert image description here

2. The logic of registering new users

  1. Thinking: Do you need a login status?
    • 不需要登陆状态
  2. inside the click event
    • 收集用户信息
    • 非空校验
    • Regular check:密码与重复密码必须相同
    • Send registration request
      成功:提示用户注册成功; 跳转到登录页
      失败:可能就用户名重复, 提示用户重新输入用户名

3. Interface document

  • Request address :/users/register
  • Request method :post
  • Carry parameters :application/x-www-form-urlencoded 格式传递 insert image description here
  • response data insert image description here

4. Code implementation

  • HTML code
<!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>
    <link rel="stylesheet" href="../css/self.css">
</head>
<body>
    <h1>注册页</h1>
    <div class="box">
        <label>
            用户名: <input class="username" type="text">
        </label>
        <label>
            密码: <input class="pwd" type="text">
        </label>
        <label>
            重复密码: <input class="rpwd" type="text">
        </label>
        <label>
            用户昵称: <input class="nickname" type="text">
        </label>
        <label>已有账号, <a href="./login.html">直接登录</a></label>
        <button>注册</button>
    </div>
    <script src="../js/register.js" type="module"></script>
</body>
</html>
  • CSS code
* {
    
    
    margin: 0;
    padding: 0;
}

h1 {
    
    
    width: 100%;
    height: 80px;
    display: flex;
    justify-content: space-evenly;
    align-items: center;
    background-color: skyblue;
}

.box {
    
    
    width: 600px;
    display: flex;
    flex-direction: column;
    padding: 20px;
    border: 3px solid pink;
    border-radius: 15px;
    margin: 30px auto;
    padding-top: 50px;
    position: relative;
}

.box > label {
    
    
    height: 50px;
    font-size: 22px;
}

.box > label > input {
    
    
    padding-left: 20px;
    font-size: 22px;
}

.box > button {
    
    
    font-size: 22px;
}

.box > span {
    
    
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    top: 10px;
    color: red;
    display: none;
}

.box > span.active {
    
    
    display: block;
}
.box select {
    
    
    font-size: 20px;
    padding-left: 15px;
}
  • JavaScript code
// 导入公共方法
import {
    
     utils } from "../utils/utils.js";
const {
    
     testName, testPwd, ajax } = utils;

// 获取 DOM 节点
const btn = document.querySelector("button");
const usernameInp = document.querySelector(".username");
const pwdInp = document.querySelector(".pwd");
const rpwdInp = document.querySelector(".rpwd");
const nicknameInp = document.querySelector(".nickname");

btn.onclick = async function () {
    
    
    // 收集用户信息
    const username = usernameInp.value;
    const password = pwdInp.value;
    const rpassword = rpwdInp.value;
    const nickname = nicknameInp.value;

    // 非空校验
    if (!username || !password || !rpassword || !nickname) {
    
    
        alert("请输入用户名、密码、重复密码和昵称");
        return;
    }

    // 3. 正则校验
    if (!testName(username) || !testPwd(password) || !testPwd(rpassword)) {
    
    
        alert("请按照格式输入用户名或密码");
        return;
    }
    // 密码与重复密码必须相同
    if (password !== rpassword) {
    
    
        alert("密码与重复密码不相同");
        return;
    }

    let {
    
     info } = await ajax({
    
    
        url: "/users/register",
        method: "POST",
        data: {
    
     username, password, rpassword, nickname },
        dataType: "json",
    });

    if (info.code === 1) {
    
    
        alert("注册成功, 请跳转登录页登录");
    } else {
    
    
        alert("注册失败, 用户名重复, 请更改用户名重新注册");
    }
};

5. Server data

insert image description here

7. Commodity list

1. Case effects

insert image description here

2. The logic of the product list

  • Render Classification
  • Render product list
  • switch category
  • filter toggle
  • discount toggle
  • Sort Toggle
  • Page switch
  • Display data switching per page
  • search content
  • After switching categories, the page number is required to return to the first page
  • Click on the product (picture) to enter the product details page (the page is free to fly, it is required to be able to get the corresponding product data, the method is not limited)

3. Interface document

获取购物车列表

  • Request address :/goods/list
  • Request method :get
  • carry parameters
    insert image description here
  • response data
    insert image description here

加入购物车的接口文档

  • Request address:/cart/add
  • Request method:post
  • Carry parameters:insert image description here
  • response datainsert image description here

4. Code implementation

  • HTML code
<!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="../css/base.css">
    <link rel="stylesheet" href="../css/index.css">
    <link rel="stylesheet" href="../css/list.css">
</head>
<body>
    <h1>
        商品列表
        <p class="active"><a href="./cart.html">去到购物车; </a><a href="./index.html">回到首页</a></p>
    </h1>
    <div class="filterBox container">
        <div class="cateBox box">
            <p>分类 : </p>
            <ul></ul>
        </div>
        <div class="saleBox box">
            <p>筛选 : </p>
            <ul>
                <li class="saleItem active" data-sale="">全部</li>
                <li class="saleItem" data-sale="hot">热销</li>
                <li class="saleItem" data-sale="sale">折扣</li>
            </ul>
        </div>
        <div class="numberBox box">
            <p>折扣 : </p>
            <ul>
                <li class="numberItem active" data-number="10">全部</li>
                <li class="numberItem" data-number="5">5</li>
                <li class="numberItem" data-number="6">6</li>
                <li class="numberItem" data-number="7">7</li>
                <li class="numberItem" data-number="8">8</li>
                <li class="numberItem" data-number="9">9</li>
            </ul>
        </div>
        <div class="searchBox box">
            <p>搜索 : </p>
            <input class="search" type="text">
        </div>
        <div class="sortBox box">
            <p>排序 : </p>
            <ul>
                <li class="sortItem active" data-type="id" data-method="ASC">综合升序</li>
                <li class="sortItem" data-type="id" data-method="DESC">综合降序</li>
                <li class="sortItem" data-type="price" data-method="ASC">价格升序</li>
                <li class="sortItem" data-type="price" data-method="DESC">价格降序</li>
                <li class="sortItem" data-type="sale" data-method="ASC">折扣升序</li>
                <li class="sortItem" data-type="sale" data-method="DESC">折扣降序</li>
            </ul>
        </div>
    </div>
    <div class="pagination container">
        <span class="prev disable">上一页</span>
        <span class="total">1 / 100</span>
        <span class="next">下一页</span>
        <select>
            <option value="12">12</option>
            <option value="16">16</option>
            <option value="20">20</option>
            <option value="24">24</option>
        </select>
    </div>
    <ul class="list container">
        <li>
            <div class="show">
                <img src="" alt="">
                <span class="hot">热销</span>
                <span class="sale">折扣</span>
            </div>
            <p class="title">ashjdkgashjdg</p>
            <p class="price">
                <span class="current">¥ 80.00</span>
                <span class="origin">¥ 100.00</span>
            </p>
            <button>加入购物车</button>
        </li>
    </ul>
    <script src="../js/list.js" type="module"></script>
</body>
</html>
  • CSS code
.filterBox {
    
    
    border: 1px solid #333;
    padding: 20px;
}

.filterBox > .box {
    
    
    font-size: 20px;
    font-weight: 400;
}

.filterBox > .box {
    
    
    display: flex;
    margin-bottom: 10px;
}

.filterBox > .box > p {
    
    
    width: 150px;
    text-align: right;
    padding-right: 30px;
    box-sizing: border-box;
}

.filterBox > .box > ul {
    
    
    flex: 1;
    display: flex;
    flex-wrap: wrap;
}

.filterBox > .box > ul > li {
    
    
    padding: 5px 10px;
    cursor: pointer;
    margin: 5px 10px;
}

.filterBox > .box > ul > li.active {
    
    
    background-color: skyblue;
    color: #fff;
}

.filterBox > .box > input {
    
    
    width: 220px;
    padding: 5px 0 5px 20px;
    font-size: 20px;
}

.pagination {
    
    
    border: 1px solid #333;
    margin: 10px auto;
    font-size: 22px;
    font-weight: 400;
    height: 50px;
    display: flex;
    align-items: center;
    padding: 0 10px;
}

.pagination > span {
    
    
    padding: 5px 10px;
    margin: 0 15px;
}

.pagination > span.prev,
.pagination > span.next {
    
    
    background-color: skyblue;
}

.pagination > span.disable {
    
    
    background-color: #ccc;
    color: #fff;
    cursor: not-allowed;
}

.pagination > select {
    
    
    padding: 0 0 0 20px;
    font-size: 22px;
}

.list {
    
    
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
}

.list > li {
    
    
    height: 480px;
    width: 290px;
    border: 1px solid #333;
    margin-bottom: 10px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}

.list > li > .show {
    
    
    width: 290px;
    height: 290px;
    border-bottom: 1px solid #333;
    box-sizing: border-box;
    padding: 5px;
    position: relative;
}

.list > li > .show > span {
    
    
    padding: 10px 20px;
    background-color: red;
    color: #fff;
    position: absolute;
    right: 0;
    top: 0;
    font-size: 20px;
}

.list > li > .show > span.sale {
    
    
    background-color: orange;
    right: 90px;
}

.list > li > p.title {
    
    
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.list > li > p.price {
    
    
    font-size: 26px;
    color: red;
    font-weight: 600;
    margin: 10px;
}

.list > li > p.price > .origin {
    
    
    color: #ccc;
    text-decoration: line-through;
    font-size: 20px;
}

.list > li > * {
    
    
    pointer-events: none;
    /*
        该元素永远不会成为鼠标事件的 target
        但是,当其后代元素的 pointer-events 属性指定其他值时,
        鼠标事件可以指向后代元素
    */
}

.list > li > button {
    
    
    padding: 10px 0;
    font-size: 22px;
    pointer-events: all;
}
  • JavaScript code
// 0. 准备全局变量
let totalNum = 0;
const id = window.localStorage.getItem("id");
const token = window.localStorage.getItem("token");

// 1. 渲染分类列表
async function getCategory() {
    
    
    let {
    
     info } = await ajax({
    
    
        url: "/goods/category",
        dataType: "json",
    });

    cateBoxUl.innerHTML = info.list.reduce((prev, item) => {
    
    
        return (prev += `
            <li class='cate_box_item'>${
      
      item}</li>
        `);
    }, "<li class='cate_box_item active'>全部</li>");
}
getCategory();

// 2. 渲染商品列表

// 全局的参数
const data = {
    
    
    current: 1,
    pagesize: 12,
    search: "",
    filter: "",
    saleType: 10,
    sortType: "id",
    sortMethod: "ASC",
    category: "",
};

// 请求数据渲染页面
async function getList() {
    
    
    let {
    
     info } = await ajax({
    
    
        url: "/goods/list",
        // data: data
        data,
        dataType: "json",
    });

    // 保存总页码
    totalNum = info.total;
    // 修改页面 页码展示
    total.innerHTML = `${
      
      data.current} / ${
      
      info.total}`;

    // 修改按钮样式
    if (data.current > 1) {
    
    
        prev.classList.remove("disable");
    }
    if (data.current === info.total) {
    
    
        next.classList.add("disable");
    }
    if (data.current === 1) {
    
    
        prev.classList.add("disable");
    }
    if (data.current !== info.total) {
    
    
        next.classList.remove("disable");
    }

    // 商品列表渲染
    listBox.innerHTML = info.list.reduce((prev, item) => {
    
    
        return (prev += `
            <li class="list-item" data-goods_id="${
      
      item.goods_id}">
                <div class="show">
                    <img src="${
      
      item.img_big_logo}" alt="">
                    ${
      
      item.is_hot ? '<span class="hot">热销</span>' : ""}
                    ${
      
      item.is_sale ? '<span class="sale">折扣</span>' : ""}
                </div>
                <p class="title">${
      
      item.title}</p>
                <p class="price">
                    <span class="current">¥ ${
      
      item.current_price}</span>
                    <span class="origin">¥ ${
      
      item.price}</span>
                </p>
                <button>加入购物车</button>
            </li>
        `);
    }, "");
}
getList();

// 事件委托---切换分类;筛选;折扣;排序
filterBox.onclick = function (e) {
    
    
    // 1. 点击分类
    if (
        e.target.className === "cate_box_item" ||
        e.target.className === "cate_box_item active"
    ) {
    
    
        removeClass(e);

        data.category = e.target.innerText === "全部" ? "" : e.target.innerText;
        data.current = 1;

        getList();
    }

    // 点击筛选
    if (e.target.className === "saleItem") {
    
    
        removeClass(e);

        // console.log(e.target.dataset.sale)
        data.filter = e.target.dataset.sale;
        data.current = 1;

        getList();
    }

    // 点击 折扣
    if (e.target.className === "numberItem") {
    
    
        removeClass(e);

        data.saleType = e.target.dataset.number;
        data.current = 1;

        getList();
    }

    // 点击排序
    if (e.target.className === "sortItem") {
    
    
        removeClass(e);

        data.sortType = e.target.dataset.type;
        data.sortMethod = e.target.dataset.method;
        data.current = 1;

        getList();
    }
};
// 排他; 修改样式
function removeClass(e) {
    
    
    // 获取到自己父级的所有子级, 并放到数组内
    const list = [...e.target.parentElement.children];
    // 遍历数组, 给数组内所有元素, 取消 active 类名
    list.forEach((item) => item.classList.remove("active"));
    // 给自身添加类名
    e.target.classList.add("active");
}
// 模糊搜索
searchBox.oninput = function () {
    
    
    // 1. 拿到用户输入的值
    const inpVal = this.value;
    // 2. 改变参数
    data.search = inpVal;
    data.current = 1;
    // 3. 发送请求
    getList();
};

// 上一页
prev.onclick = function () {
    
    
    if (data.current === 1) return;
    data.current -= 1;
    getList();
};

// 下一页
next.onclick = function () {
    
    
    if (data.current === totalNum) return;
    data.current += 1;
    getList();
};

// 切换每页展示数据
selBox.onchange = function () {
    
    
    data.pagesize = this.value;
    getList();
};

// 点击商品
listBox.onclick = async function (e) {
    
    
    if (e.target.className === "list-item") {
    
    
        // 拿到商品ID
        window.sessionStorage.setItem("goods_id", e.target.dataset.goods_id);

        // 跳转商品详情页面
        window.location.href = "./detail.html";
    }

    // 点击加入购物车
    if (e.target.nodeName == "BUTTON") {
    
    
        console.log("点击按钮, 发请求, 加入购物车");

        // 如果我们现在没有 用户ID 需要跳转登录
        // console.log(id, token)
        if (!id || !token) {
    
    
            window.sessionStorage.setItem("page", window.location.href);
            window.location.href = "./login.html";
        }
        const goodsId = e.target.parentElement.dataset.goods_id;

        // 商品 ID 和 用户 ID 和 token 都有了
        let {
    
     info } = await ajax({
    
    
            url: "/cart/add",
            method: "POST",
            data: {
    
     id, goodsId },
            headers: {
    
     authorization: token },
            dataType: "json",
        });
        // console.log(info);
        if (info.code === 1) {
    
    
            alert(info.message);
        } else {
    
    
            // alert('登陆状态过期,  请重新登陆')
            if (confirm("登陆状态过期,  点击确定跳转登录页")) {
    
    
                window.sessionStorage.setItem("page", window.location.href);
                window.location.href = "./login.html";
            }
        }
    }
};

8. Product details page

1. Case effects

insert image description here

2. Interface document

获取商品详细信息

  • Request address :localhost:8888/goods/item
  • Request method :get
  • Carry parameters :支持 restful 风格 localhost:8888/goods/item/:id insert image description here
  • Response data :如果该商品存在, 即为该商品的详细信息 insert image description here

4. Code implementation

  • HTML code
<!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="../css/base.css">
  <link rel="stylesheet" href="../css/index.css">
  <link rel="stylesheet" href="../css/detail.css">
</head>
<body>
  <h1>
    商品详情
    <p class="active"><a href="./list.html">继续购物</a><a href="./cart.html">去到购物车</a><a href="./index.html">回到首页</a></p>
  </h1>
  <div class="content container">
    <div class="left">
      <div class="show">
        <img src="" alt="">
      </div>
      <ul class="list">
        <li></li>
        <li></li>
      </ul>
    </div>
    <div class="right">
      <div class="title">asjhdgj</div>
      <div class="price">¥ 100.00</div>
      <p class="size">
        <span>XS</span>
        <span>S</span>
        <span>M</span>
        <span>L</span>
        <span>XL</span>
      </p>
      <p class="btns">
        <button>加入购物车</button>
        <button>立即结算</button>
      </p>
    </div>
  </div>
  <div class="desc container">
    a
  </div>
  <script src="../js/detail.js" type="module"></script>
</body>
</html>
  • CSS code
.desc {
    
    
  margin-top: 30px;
}

.content {
    
    
  display: flex;
  justify-content: space-between;
}

.content > .left {
    
    
  width: 450px;
  height: 600px;
  margin-right: 15px;
  display: flex;
  flex-direction: column;
  border: 1px solid #333;
}

.content > .left > .show {
    
    
  width: 450px;
  height: 450px;
  border-bottom: 1px solid #333;
}

.content > .left > .list {
    
    
  flex: 1;
  align-items: center;
  display: flex;
}

.content > .left > .list > li {
    
    
  width: 70px;
  height: 70px;
  border: 1px solid #333;
  margin-left: 20px;
}

.content > .right {
    
    
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  box-sizing: border-box;
  padding: 10px;
}

.content > .right > .title {
    
    
  font-weight: 700;
  font-size: 22px;
}

.content > .right > .price {
    
    
  font-size: 60px;
  color: red;
}

.content > .right > .size {
    
    
  display: flex;
}

.content > .right > .size > span {
    
    
  padding: 5px 10px;
  height: 30px;
  border: 1px solid #333;
  border-right: none
}

.content > .right > .size > span:last-child {
    
    
  border-right: 1px solid #333;
  border-radius: 0 10px 10px 0;
}

.content > .right > .size > span:first-child {
    
    
  border-radius: 10px 0 0 10px;
}

.content > .right > .btns {
    
    
  display: flex;
  justify-content: space-between;
}

.content > .right > .btns > button {
    
    
  width: 45%;
  height: 50px;
  font-size: 26px;
  border: none;
  background-color: lightgreen;
  color: #fff;
}

.content > .right > .btns > button:first-child {
    
    
  background-color: lightblue;
}
  • JavaScript code
// 导入公共方法
import {
    
     utils } from "../utils/utils.js";
const {
    
     ajax } = utils;

//  获取DOM节点
const content = document.querySelector(".content");
const desc = document.querySelector(".desc");

const id = window.sessionStorage.getItem("goods_id");

// console.log(id)
if (!id) {
    
    
    // 没有 商品 ID 跳转 商品详情页
    window.location.href = "./list.html";
}

// 发送请求
async function getItem() {
    
    
    const {
    
     info } = await ajax({
    
    
        url: "/goods/item",
        data: {
    
     id },
        dataType: "json",
    });

    console.log(info.info);

    content.innerHTML = `
        <div class="left">
            <div class="show">
                <img src="${
      
      info.info.img_big_logo}" alt="">
            </div>
            <ul class="list">
                <li></li>
                <li></li>
            </ul>
        </div>
        <div class="right">
            <div class="title">${
      
      info.info.title}</div>
            <div class="price">¥ ${
      
      info.info.current_price}</div>
            <p class="size">
                <span>XS</span>
                <span>S</span>
                <span>M</span>
                <span>L</span>
                <span>XL</span>
            </p>
            <p class="btns">
                <button>加入购物车</button>
                <button>立即结算</button>
            </p>
        </div>
    `;

    desc.innerHTML = info.info.goods_introduce
}
getItem();

Nine, shopping cart operation

1. Case effects

insert image description here

2. Code implementation

这里对购物车操作的接口文档还挺多,就不一一列举了

  • HTML code
<!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>
    <link rel="stylesheet" href="../css/cart.css">
</head>
<body>
    <div class="header">页面顶部</div>
    <div class="content">
        <div class="top">
            <input type="checkbox"> 全选
        </div>
        <!-- 动态生成 -->
        <ul></ul>
        <div class="bottom">
            <div class="totalNum">
                总件数 : 3
            </div>
            <div class="btns">
                <button>清空购物车</button>
                <button>去结算</button>
                <button>删除所有已选中</button>
            </div>
            <div class="totalPrice">
                总价格 : ¥ <span>100.00</span>
            </div>
        </div>
    </div>
    <div class="footer">页面底部</div>

    <script src="../js/cart.js" type="module"></script>
</body>
</html>
  • CSS code
* {
    
    
    margin: 0;
    padding: 0;
}

ul,ol,li {
    
    
    list-style: none;
}

.header,.footer {
    
    
    width: 1200px;
    height: 100px;
    background-color: skyblue;
    color: #fff;
    font-size: 50px;
    display: flex;
    justify-content: center;
    align-items: center;
    margin: 0 auto;
}

.footer {
    
    
    height: 400px;
}

.content {
    
    
    width: 1200px;
    margin: 0 auto;
    padding: 10px 0;
}

.content > .top,
.content > .bottom {
    
    
    height: 50px;
    background-color: pink;
    display: flex;
    align-items: center;
}

.content > .bottom {
    
    
    justify-content: space-between;
    box-sizing: border-box;
    padding: 0 10px;
}

.content > .bottom > .totalPrice > span {
    
    
    font-size: 20px;
    color: red;
}

.content > .bottom > .btns > button {
    
    
    font-size: 18px;
    padding: 5px 10px;
    cursor: pointer;
}

.content > .top > input {
    
    
    width: 30px;
    height: 30px;
    margin: 0 15px 0 50px;
}

.content > ul {
    
    
    padding-top: 10px;
}

.content > ul > li {
    
    
    width: 100%;
    border: 1px solid #333;
    box-sizing: border-box;
    height: 100px;
    margin-bottom: 10px;

    display: flex;
}

.content > ul > li > div {
    
    
    display: flex;
    justify-content: center;
    align-items: center;
    border-right: 1px solid #333;
}

.content > ul > li > div:last-child {
    
    
    border: none;
}

.content > ul > li > .show,
.content > ul > li > .status {
    
    
    width: 100px;
}

.content > ul > li > .status > input {
    
    
    width: 30px;
    height: 30px;
}

.content > ul > li > .show > img {
    
    
    width: 100%;
    height: 100%;
    display: block;
}

.content > ul > li > .price,
.content > ul > li > .sub {
    
    
    width: 200px;
    color: red;
    font-size: 20px;
}

.content > ul > li > .title {
    
    
    width: 300px;
    align-items: flex-start;
    justify-content: flex-start;
    box-sizing: border-box;
    padding: 5px;
}

.content > ul > li > .number {
    
    
    width: 230px;
}

.content > ul > li > .number > input {
    
    
    width: 50px;
    height: 30px;
    text-align: center;
    margin: 0 5px;
    border: none;
    outline: none;
    font-size: 18px;
}

.content > ul > li > .number > button {
    
    
    width: 30px;
    height: 30px;
    cursor: pointer;
}

.content > ul > li > .destory {
    
    
    flex: 1;
}

.content > ul > li > .destory > button {
    
    
    padding: 5px;
    font-size: 18px;
    cursor: pointer;
}

  • JavaScript code
// 导入公共方法
import {
    
     utils } from "../utils/utils.js";
const {
    
     ajax } = utils;

// 判断用户是否登录, 没有登录跳转登录页
const id = window.localStorage.getItem("id");
const token = window.localStorage.getItem("token");
if (!id || !token) {
    
    
    window.sessionStorage.setItem("page", window.location.href);
    window.location.href = "./login.html";
}

// 获取元素
var content = document.querySelector(".content");

// 准备渲染函数
async function bindHtml() {
    
    
    // 发送请求, 请求到原本的cartList
    let {
    
     info } = await ajax({
    
    
        url: "/cart/list",
        data: {
    
     id },
        headers: {
    
     authorization: token },
        dataType: "json",
    });
    let cartList = info.cart;

    var selctItem = 0;      // 存储选中商品的数量
    var selctTotalNum = 0;  // 存储选中商品的总数量
    var totalPrice = 0;     // 存储选中商品的总价
    // 1.0 找到选中商品
    cartList.forEach(function (item) {
    
    
        if (item.is_select) {
    
    
            selctItem++;
            selctTotalNum += item.cart_number;
            totalPrice += item.cart_number * item.current_price;
        }
    });

    // 1.1 查询数据, 渲染页面
    var str = `<div class="top">
        <input class="selcet_all" type="checkbox" ${
      
      
            // 选中的商品数量如果等于商品数量, 代表所有商品被选中
            selctItem === cartList.length ? "checked" : ""
        }> 全选
    </div>
    <ul>`;

    cartList.forEach(function (item) {
    
    
        str += `<li>
            <div class="status">
                <input data-id="${
      
      
                    item.goods_id
                }" class="item" type="checkbox" ${
      
      
            item.is_select ? "checked" : ""
        }>
            </div>
            <div class="show">
                <img src="${
      
      item.img_small_logo}" alt="">
            </div>
            <div class="title">
                ${
      
      item.title}
            </div>
            <div class="price">
                ¥ ${
      
      item.current_price}
            </div>
            <div class="number">
                <button class="sub_btn" data-id=${
      
      item.goods_id} data-num="${
      
      
            item.cart_number
        }">-</button>
                <input type="text" value="${
      
      item.cart_number}">
                <button class="add_btn"
                    data-id="${
      
      item.goods_id}"
                    data-num="${
      
      item.cart_number}"
                    data-goods_number="${
      
      item.goods_number}"
                >+</button>
            </div>
            <div class="sub">
                ¥ ${
      
      (item.cart_number * item.current_price).toFixed(2)}
            </div>
            <div class="destory">
                <button data-id="${
      
      item.goods_id}" class="del">删除</button>
            </div>
        </li>`;
    });

    str += `</ul>
    <div class="bottom">
        <div class="totalNum">
            总件数 : ${
      
      selctTotalNum}
        </div>
        <div class="btns">
            <button class="clear">清空购物车</button>
            <button class="go_pay" data-TotalPrice="${
      
      totalPrice}">去结算</button>
            <button class="del_item">删除所有已选中</button>
        </div>
        <div class="totalPrice">
            总价格 : ¥ <span>${
      
      totalPrice.toFixed(2)}</span>
        </div>
    </div>`;

    content.innerHTML = str;
}

// 2. 首次打开页面, 调用渲染函数
bindHtml();

// 3. 利用事件冒泡, 将所有的事件委托给统一的父级
content.onclick = async function (e) {
    
    
    // 3.1 全选按钮事件
    if (e.target.className === "selcet_all") {
    
    
        // 发送 修改 全选按钮 的请求
        await ajax({
    
    
            url: "/cart/select/all",
            method: "POST",
            data: {
    
    
                id,
                type: e.target.checked ? 1 : 0,
            },
            headers: {
    
     authorization: token },
        });

        //重新渲染视图
        bindHtml();
    }

    //清空购物车
    if (e.target.className === "clear") {
    
    
        var boo = confirm("请问您确定清空吗");
        if (boo) {
    
    
            await ajax({
    
    
                url: "/cart/clear",
                data: {
    
     id },
                headers: {
    
     authorization: token },
            });

            // 重新渲染页面
            bindHtml();
        }
    }

    // 删除已选中  (没有选中项时 禁止执行)
    if (e.target.className === "del_item") {
    
    
        var boo = confirm("请问您确定删除已选中吗");
        if (boo) {
    
    
            await ajax({
    
    
                url: "/cart/remove/select",
                data: {
    
     id },
                headers: {
    
     authorization: token },
            });

            // 重新渲染视图
            bindHtml();
        }
    }

    // 减少商品数量
    if (e.target.className === "sub_btn") {
    
    
        const goodsId = e.target.dataset.id;
        const number = e.target.dataset.num - 0 - 1;

        if (number < 1) return;

        await ajax({
    
    
            url: "/cart/number",
            method: "POST",
            data: {
    
     id, goodsId, number },
            headers: {
    
     authorization: token },
        });

        // 重新渲染视图
        bindHtml();
    }

    // 增加商品数量
    if (e.target.className === "add_btn") {
    
    
        const goodsId = e.target.dataset.id;
        const number = e.target.dataset.num - 0 + 1;
        const goods_number = e.target.dataset.goods_number - 0;

        if (number > goods_number) return;

        await ajax({
    
    
            url: "/cart/number",
            method: "POST",
            data: {
    
     id, goodsId, number },
            headers: {
    
     authorization: token },
        });

        // 重新渲染视图
        bindHtml();
    }

    // 选中商品
    if (e.target.className === "item") {
    
    
        const goodsId = e.target.dataset.id;

        await ajax({
    
    
            url: "/cart/select",
            method: "POST",
            data: {
    
     id, goodsId },
            headers: {
    
     authorization: token },
        });

        // 重新渲染视图
        bindHtml();
    }

    // 删除某一项
    if (e.target.className === "del") {
    
    
        var boo = confirm("请问您确定删除当前项吗");
        // 询问用户是否需要删除
        if (!boo) return;

        const goodsId = e.target.dataset.id - 0;

        await ajax({
    
    
            url: "/cart/remove",
            data: {
    
     id, goodsId },
            headers: {
    
     authorization: token },
        });

        // 重新渲染视图
        bindHtml();
    }
};


Guess you like

Origin blog.csdn.net/m0_58190023/article/details/128122574