整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

小白学代码使用原生JS写购物车模块过程中的踩坑总结

小白学代码使用原生JS写购物车模块过程中的踩坑总结

着过年放假在家复习了之前学的JS知识,用原生撸了一个购物车模块,下面我来整理一下我的思路分享给大家。

一、功能和效果图

1.1 废话不多说,首先上个效果图,如下:

购物车功能效果图

1.2 功能介绍:

  1. 点击全选按钮,每一项商品的复选框处于被勾选的状态,同时计算出商品数量和商品总价;
  2. 点击数量切换的按钮,能自动计算出修改数量之后的商品数量和价格;
  3. 商品的总计数量和总价格应该只计算被勾选的商品的数量和金额。

功能介绍完毕,下面开始介绍我写这个购物车的步骤。


二、购物车的页面结构

2.1 HTML代码

<table>
        <caption>
            购物车
        </caption>
        <thead>
            <tr>
                <!-- 全选复选框 -->
                <th>
                    <input type="checkbox" name="checkAll" id="check-all" checked /><label for="check-all">全选</label>
                </th>
                <th>图片</th>
                <th>品名</th>
                <th>单位</th>
                <th>单价/元</th>
                <th>数量</th>
                <th>金额/元</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>
                    <input type="checkbox" name="item" value="SN-1020" checked />
                </td>
                <td>
                    <a href=""><img src="images/p1.jpg" alt="" /></a>
                </td>
                <td>iPhone 11</td>
                <td>台</td>
                <td class="price">4799</td>
                <td><input type="number" min="1" value="1" /></td>
                <td class="amount">xxxx</td>
            </tr>
            <tr>
                <td>
                    <input type="checkbox" name="item" value="SN-1020" checked />
                </td>
                <td>
                    <a href=""><img src="images/p2.jpg" alt="" /></a>
                </td>
                <td>小米pro 11</td>
                <td>部</td>
                <td class="price">3999</td>
                <td><input type="number" min="1" value="2" /></td>
                <td class="amount">xxxx</td>
            </tr>
            <tr>
                <td>
                    <input type="checkbox" name="item" value="SN-1030" checked />
                </td>
                <td>
                    <a href=""><img src="images/p3.jpg" alt="" /></a>
                </td>
                <td>MacBook Pro</td>
                <td>台</td>
                <td class="price">18999</td>
                <td><input type="number" min="1" value="1" /></td>
                <td class="amount">xxxx</td>
            </tr>
            <tr>
                <td>
                    <input type="checkbox" name="item" value="SN-1040" checked />
                </td>
                <td>
                    <a href=""><img src="images/p4.jpg" alt="" /></a>
                </td>
                <td>小米75电视</td>
                <td>台</td>
                <td class="price">5999</td>
                <td><input type="number" min="1" value="2" /></td>
                <td class="amount">xxxx</td>
            </tr>
            <tr>
                <td>
                    <input type="checkbox" name="item" value="SN-1050" checked />
                </td>
                <td>
                    <a href=""><img src="images/p5.jpg" alt="" /></a>
                </td>
                <td>Canon 90D单反</td>
                <td>台</td>
                <td class="price">9699</td>
                <td><input type="number" min="1" value="1" /></td>
                <td class="amount">xxxx</td>
            </tr>
        </tbody>
        <tfoot>
            <tr style="font-weight: bolder; font-size: 1.2em">
                <td colspan="5">总计:</td>
                <td id="sum">xxxx</td>
                <td id="total-amount">xxxx</td>
            </tr>
        </tfoot>
    </table>

2.2 CSS代码

table {
    border-collapse: collapse;
    width: 90%;
    text-align: center;
    margin: auto;
}

table caption {
    margin-bottom: 15px;
    font-size: 1.5rem;
}

table th, table td {
    border-bottom: 1px solid #ccc;
    padding: 5px;
    font-weight: normal;
}

table thead tr:first-of-type {
    background-color: #e6e6e6;
    height: 3em;
}

table input[type="checkbox"] {
    width: 1.5em;
    height: 1.5em;
}

table tbody tr {
    border-bottom: 1px solid #ccc;
}

table tbody tr:hover {
    background-color: #f6f6f6;
    cursor: pointer;
}

tbody img {
    width: 3em;
}

tbody input[type="number"] {
    width: 3em;
}

button {
    width: 150px;
    height: 30px;
    outline: none;
    border: none;
    background-color: teal;
    color: white;
    letter-spacing: 5px;
}

button:hover {
    opacity: 0.7;
    cursor: pointer;
}

2.3 效果图

购物车效果图

以上就是一个简单的购物车页面的HTML和CSS样式代码。


三、完成相关JS代码

首先,我们先完成商品的全选与取消全选的功能,所以肯定是需要拿到全选复选框元素和商品前面的复选框元素,代码如下:

// 获取全选复选框,所有的商品都有一个独立的复选框
const checkAll=document.querySelector('#check-all');
const checkItems=document.getElementsByName('item');

拿到全选和每个商品的复选框元素之后,给全选框添加一个change事件,监听它的checked值的变化。此时全选框的checked值可以通过事件监听回调函数中的ev参数下的ev.target.checked拿到。

checkALl.onchange=ev=> {
    // 如果全选框处于选中状态,ev.target.checked的值就为true,反之,为false。
    console.log(ev.target.checked);
};

如果想让全选框的的状态和每个商品前的复选框状态保持一致,那么就使他们的checked值一致即可。因此,我们可以在全选复选框的change事件中遍历每个商品的复选框元素。

checkALl.onchange=ev=> {
    // 如果全选框处于选中状态,ev.target.checked的值就为true,反之,为false。
    console.log(ev.target.checked);
    checkItems.forEach(item=> item.checked=ev.target.checked);
};

这样点击全选框的时候,就可以实现全部选中,和取消全选的功能了。效果如图:

全选与取消全选

全选和取消全选的功能完成之后,下面开始完善逐个勾选商品,直至勾选全部商品,让全选按钮自动变成被选中的状态。

要完成这个功能,我们可以通过对每个商品的复选框添加一个change事件来监听checked的变化。因此需要通过forEach()方法对遍历每一个商品。

checkItems.forEach(item=> item.onchange=ev=> {
    // 在这里处理每一项的checked值
});

此时,我们可以这样考虑:当每个商品的复选框都被勾选,即:所有商品复选框的checked的值全部为true时,全选复选框才会显示被勾选的状态,也就是全选复选框的checked的值也要为true。

由于checkAll的状态依赖于每一项商品的checked值,那么可以利用一个数组函数:Array.every()遍历每一项商品,当所有商品的checked值都为true时,every()方法的返回值就是一个true,然后再赋值给checkAll即可。注意:由于我们拿到的checkItems是一个NodeList数组,需要先将其转换成数组后再进行操作。

checkItems.forEach(item=> item.onchange=ev=> {
    checkAll.checked=Array.from(checkItems).every(checkItem=> checkItem.checked);
});

点击选中每个商品

至此,全选和单选功能全部完成了。下面开始写自动计算金额的和总数的功能。

购物车的数量和金额不仅包含每一项商品的数量和每一项商品的总金额,还包含了计算选中的商品总数,以及所有选中的商品的总金额。

下面首先完成单个商品的总金额计算,总金额=单价 * 数量,根据这个公式,我们首先拿到商品的单价和数量元素。

// 获取单价组成的数组
const priceLists=document.querySelectorAll('.price');
// 获取数量组成的数组
const numberLists=document.querySelectorAll('body input[type=number]');

以上单价(priceLists)数量(numberLists)都是NodeList类型的,需要先将它们转换成数组,由于表单中获取的内容都是string类型,而参与计算的需要的是整型,所以这里需要进行一下转换,使用parseInt()方法即可。

// 获取商品单价组成的数组
const priceLists=document.querySelectorAll('.price');
const priceArr=Array.from(priceLists).map(item=> parseInt(item.textContent)); // [ 4799, 3999, 18999, 5999, 9699 ]
// 获取商品数量组成的数组
const numberLists=document.querySelectorAll('body input[type=number]');
const numbersArr=Array.from(numberLists).map(item=> parseInt(item.value)); // 默认值:[ 1, 1, 1, 1, 1 ]

注意:商品价格和商品数量在取值时有些不同。商品的单价是普通元素直接使用textContent即可拿到它内部的值,而数量这个用的是表单控件,所以需要使用value才可以拿到值。 我刚开始写这个功能的时候懵逼了半天,此处一定要注意。

拿到商品的单价和数量之后就可以按照上面的公式进行计算了,由于商品的价格和商品的数量都是一个数组,并且价格和数量在数组中都是一一对应的关系,因此可以使用JS数组的reduce()方法进行遍历。

let amountArr=[priceArr, numbersArr].reduce((prev, curr)=> {
    return prev.map((item, index)=> {
        return item * curr[index];
    });
});

总感觉上述写法有点怪怪的,是不是可以进行简化呢?根据箭头函数的特征,当只有一条返回语句的时候可以省略掉return关键字和大括号,因此上述方法可以简写成下面这样:

let amountArr=[priceArr, numbersArr].reduce((prev, curr)=> prev.map((item, index)=> item * curr[index]));
console.log(amountArr); // [ 4799, 3999, 18999, 5999, 9699 ]

(PS:上面的方法我一开始也没有发现可以简写,我是把代码发给我朋友看了之后,朋友给我点醒了。还是才疏学浅呀。)

这时已经计算出来了每个商品的总金额,那么我们将其渲染到页面中。

// 获取单个商品总金额的元素数组
const amountDOM=document.querySelectorAll('.amount');
amountDOM.forEach((item, index)=> item.textContent=amountArr[index]);

计算每个商品的金额并渲染到页面中

单个商品的总金额渲染到页面之后,下面就开始计算商品的总数,和总金额了。根据某东、某宝的购物车功能,我们可以发现,总计那里统计的商品总数是一般是我们勾选上的商品总数,总金额也是一样的,那么我们就需要根据商品的状态来进行计算了。

首先声明一个数组,用于存储被选中的商品的状态,如果被选中,值为1,未被选中,则为0。

let  isChecked=[];
checkItems.forEach(item=> isChecked.push(item.checked===true ? 1 : 0));
// 打印出商品状态值
console.log(isChecked);
  • 效果如图:

打印商品状态值

商品的状态已经记录好了,那么现在就需要统计选中的商品对应的数量了。

// 声明一个用于存储商品数量的数组,该数组的作用是用于与对应的商品的状态值的数组进行相乘,得到实际的被选中的商品的数组。
let checkedNumbers=[];
numbersArr.forEach((item, index)=> checkedNumbers.push(item * isChecked[index]));
// 打印被选中的商品的数量
console.log(checkedNumbers);

打印出选中的商品的数量数组

计算出被选中的商品数量的总数并渲染到页面中:

let checkedSum=checkedNumbers.reduce((prev, curr)=> prev + curr);
// 将获取的数量结果渲染到页面中
document.querySelector('#sum').textContent=checkedSum;

效果如上图已经出来了。

下面开始计算被选中的商品的总金额,该总金额等于上面所有被选中的商品的总金额之和。计算出结果之后渲染到页面中。

// 声明一个数组用于存储每一个被选中的商品的总金额
let checkedPrice=[];
checkedNumbers.forEach((item, index)=> checkedPrice.push(item * priceArr[index]));
// 打印被选中的每个被选中的商品总金额
console.log(checkedPrice);
// 计算被选中的商品总金额
let totalAmount=checkedPrice.reduce((prev, curr)=> prev + curr);
// 将选中的商品总金额渲染到页面中
document.querySelector('#total-amount').textContent=totalAmount;
  • 效果图:

将总金额渲染到页面

至此,关于计算单个商品的总金额以及被选中商品的数量和总金额的功能已经全部完成了,但是我们还需要实现在页面加载以及更改某个商品数量时自动计算的功能。那么就需要将上述的计算功能封装成一个函数,以便后面每一次执行计算时使用。

  • 封装后的代码如下:
function autoCalculate() {
    // 获取单价组成的数组
    const priceLists=document.querySelectorAll('.price');
    const priceArr=Array.from(priceLists).map(item=> parseInt(item.textContent));
    // 获取数量组成的数组
    const numberLists=document.querySelectorAll('body input[type=number]');
    const numbersArr=Array.from(numberLists).map(item=> parseInt(item.value));
    console.log(priceArr, numbersArr);
  
    // 由于拿到的表单里的数据都是string类型的,所以需要先将其转换成int类型,因此需要使用`map()`方法操作一下
    let amountArr=[priceArr, numbersArr].reduce((prev, curr)=> prev.map((item, index)=> item * curr[index]));
    console.log(amountArr);
    const amountDOM=document.querySelectorAll('.amount');
    amountDOM.forEach((item, index)=> item.textContent=amountArr[index]);

    // 首先声明一个数组,用于存储被选中的商品的状态,如果被选中,值为1,未被选中,则为0
    let isChecked=[];
    checkItems.forEach(item=> isChecked.push(item.checked===true ? 1 : 0));
    console.log(isChecked);
    // 声明一个用于存储是商品数量的数组,该数组的作用是:如果商品处于被选中的状态,那么就存储它真实的数量值,
    // 如果没有被选中,那么数量就是0
    let checkedNumbers=[];
    numbersArr.forEach((item, index)=> checkedNumbers.push(item * isChecked[index]));
    console.log(checkedNumbers);
    // 此时,被选中的商品的总数为:
    let checkedSum=checkedNumbers.reduce((prev, curr)=> prev + curr);
    console.log(checkedSum);
    // 将获取的数量结果渲染到页面中
    document.querySelector('#sum').textContent=checkedSum;
    // 下面开始计算被选中的商品的总金额,该总金额等于上面所有被选中的商品的总金额之和。
    // 声明一个数组用于存储每一个被选中的商品的总金额
    let checkedPrice=[];
    checkedNumbers.forEach((item, index)=> checkedPrice.push(item * priceArr[index]));
    console.log(checkedPrice);
    // 计算被选中的商品总金额
    let totalAmount=checkedPrice.reduce((prev, curr)=> prev + curr);
    // 将选中的商品总金额渲染到页面中
    document.querySelector('#total-amount').textContent=totalAmount;
}

将代码封装后我们会发现,单个商品的总金额,商品总数以及总金额的值都没了,如下图:

封装代码后的效果

这是因为,代码在第一次加载的时候并没有执行封装后的函数,因此需要加一行代码:

// 页面第一次加载的时候自动执行一次。
window.onload=autoCalculate;

这样页面中的数据在第一次加载的时候就全部都正常了。

下面完成最后一个功能:调整商品的数量,会自动计算总数和金额。该功能还是通过change事件监听某个表单数据的变化来完成。效果图下图:

  • 代码实现:
// 监听某个控件的事件,首先需要拿到控件元素。
const numInput=document.querySelectorAll('body input[type=number]');
// 上面都用了onchange来监听,这里换个方法使用addEventListener。
numInput.forEach(item=> item.addEventListener('change', autoCalculate));

但是我们会发现这里有个小bug,就是如果勾选没有选中的商品,并不会自动计算商品数量和总价,原因很简单,我们在监听单个商品选中和全选的时候根本就没有执行自动计算函数,只需要在二者的事件监听中加上自动计算的函数即可。

checkAll.onchange=ev=> {
    checkItems.forEach(item=> item.checked=ev.target.checked);
    // 解决勾选全选框不会自动计算的bug
    autoCalculate();
};
checkItems.forEach(item=> item.onchange=ev=> {
    checkAll.checked=Array.from(checkItems).every(checkItem=> checkItem.checked);
    // 解决勾选全选框不会自动计算的bug
    autoCalculate();
});

写到这里,我们购物车的所有功能都已经完成了。购物车这个模块看似不难,其实这里面的坑也是不少的,例如:

  1. 在操作获取的元素节点时,我们有时候需要将其转换成一个数组才可以使用数组函数进行操作,因为我们通过document.querySelector获取的元素并不是一个真正的数组,而是一个类数组(NodeList);
  2. 案例中使用了多个数组函数,Array.from()、Array.reduce()、Array.every()等等,由此可见,熟练掌握JS常用的数组也是非常重要的;
  3. 掌握事件监听:addEventListener;
  4. 箭头函数的简写方法;
  5. 表单事件的监听,只能通过onchange方法,千万不要使用onclick。

以上就是我个人在写这个购物车功能的全部新的,由于本人也是新手,可能还有其他更简介方便的写法,如果有问题,请各位大佬批评指正,不胜感激。

如果有刚开始学习JS的同学,想要源码的各位亲,可以关注并私信回复“购物车”即可。

术用品对绘画者来说是必备的,青少年、职业成年人都有较高需求度,尤其是当今生活条件变好,各种用品种类非常多,家长们也愿意在孩子身上花更多的金钱。

因此对经营者来说,市场高需求下,只满足附近三公里客户不足以生意增长和扩大营收,还需要通过线上拓展更广的群体与订单。

而通过雨科网商城平台搭建美术用品小程序商城后又有什么效果呢?「链接」


1、商品管理、线上销售

美术用品种类和品牌众多,由于大多为短期消耗品,因此购买率相当可以。通过小程序可将所有产品规格参数上架管理,详细价格、介绍等信息呈现,商城内精美布局商品和页面设计制作,精美呈现形式更利于促进客户消费。

琳琅满目的线上购物场景,多流量渠道利于商家分享、也利于用户触达,包括商品分享、商城搜索、筛选等。

更可构建电脑手机商城网站+微信小程序商城联合打通多种购物环境,同城配送+到店自提+快递配送,客户坐在家里直接选择商品下单购物即可按照自己的方式获得商品。

线上销售更利于和同行竞争,构建私域渠道打造自己的美术电商平台

消息通知和订单管理发货备货,以及配套工具打单、小票、对接ERP、当面付等,轻松完成订单流程。


2、客户管理与持续生意增长

美术用品客户的复购率较高,客户在商城中注册会员信息留存,商家可随时查看并长期管理,短信发送等。

同时长期运营场景下,可通过会员积分、储值、会员卡、等级体系留存客户并长期复购,利于商城回笼资金和客户享受折扣优惠持续复购,会员也是商城经营重要方式之一。

同时还有分销,推广员、分销商、社区团长体系,让会员成为推广人员,利用自己的私域生态分享完成订单获得佣金收入,而商家则让商城获得更多曝光,更多新客与订单。

商家后台灵活管理,利于长期发展,动动手指,其他人帮你卖货。

当然雨科网商城还拥有多种营销功能,如优惠券、新人礼、积分商城、组合套餐、定金预售、短视频、互动游戏等,管理和设置方便,客户参与更加便捷,功能强大,利用营销模式可带动更多商品销售和裂变复购等。


3、多商户与商城后台

美术用品客群一半都是青少年,由于地区广泛,如果商家有多家门店,可以通过多商户自营体系,将所有分店上线,客户进入小程序可直接购物,也可选择附近分店下单配送或到店等,分店独立经营,总部统筹管理。


还有多商户进驻体系,邀请其他商家进入到商城里成为子商户,独立后台货品上新、发货、营收等。商城管理员后台管理商品审核、店铺呈现、评星、提现、资料等,构建完善的线上购物商圈。

后台多种功能控件模块,现成卖货小程序商城模板直接修改设计制作,轻松完成上线。


现在就注册账号进入商城后台搭建美术用品销售卖货小程序商城吧。「链接」


原文:https://www.zcdly.com/msypscxcx.html

TML编辑器粘贴word图片,web编辑器粘贴word图片,web富文本编辑器粘贴word,前端编辑器粘贴word内容,前端web编辑器粘贴word,支持快捷键操作(Ctrl+V),

粘贴后word图片自动上传到服务器中,然后自动将图片和文字HTML添加到编辑器中。

用户这边日常的编辑工作基本上都是在word中完成的,用户把内容编辑好后希望能够直接一键(通过快捷键)粘贴到网站后台新闻发布页面的编辑器中,这样能够节省不少时间。提高工作效率,信息发布效率。

用户发布新闻的时候是从word里面复制图片和文字,然后将word图文内容粘贴到web富文本编辑器中,希望能够将word的图片自动上传到服务器中,服务器地址能够自定义,后端的话需要支持任意开发语言,比如ASP,ASP.NET,JSP,PHP,PYTHON等。只要是基于标准HTTP协议的都要支持。如果能够不装控件最好,

实际上装不装都无所谓,只要好用。

1.下载示例:

http://www.ncmem.com/webapp/wordpaster/versions.aspx


2.复制WordPaster插件目录


3.引入插件文件

注意:不要重复引入jquery,如果您的项目已经引入了jq,则不用再引入jq-1.4


4.在工具栏中增加插件按钮


6.初始化控件

注意:

1.如果接口字段名称不是file,请配置FileFieldName。ueditor接口中使用的upfile字段


参考:http://www.ncmem.com/doc/view.aspx?id=c3ad06c2ae31454cb418ceb2b8da7c45

2.如果接口返回JSON,请配置ImageMatch


参考:http://www.ncmem.com/doc/view.aspx?id=07e3f323d22d4571ad213441ab8530d1

3.如果接口返回的图片地址没有域名,请配置ImageUrl


参考:http://www.ncmem.com/doc/view.aspx?id=704cd302ebd346b486adf39cf4553936

4.如果接口有权限验证(登陆验证,SESSION验证),请配置COOKIE。或取消权限验证。

参考:http://www.ncmem.com/doc/view.aspx?id=8602DDBF62374D189725BF17367125F3


效果