s實現淘寶購物車類似功能:
主要有添加商品
增加和減少商品數量
根據增加、減少或選擇的商品獲取金額
實現商品價格的計算
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>購物車</title>
</head>
<style type="text/css">
h1{
text-align: center;
}
table{
margin: 0 auto;
}
body{
font-size: larger;color: crimson;
background-image: url(img/2.jpg);
background-repeat: no-repeat;
background-size: 100%;
}
table th,table td{
}
</style>
<body >
<h1>購物車:真劃算</h1>
<table border="1" >
<tr>
<!--文本th-->
<th>商品</th>
<th >單價</th>
<th>顏色</th>
<th>庫存</th>
<th>好評率</th>
<th>操作</th>
</tr>
<tr>
<td>面膜</td>
<td >150</td>
<td>白色</td>
<td>100</td>
<td>88%</td>
<td align="center">
<input type="button" value="加入購物車" onclick="add_shoppingcar(this)"/>
</td>
</tr>
<tr>
<td>口紅</td>
<td >350</td>
<td>白色</td>
<td>166</td>
<td>82%</td>
<td align="center">
<input type="button" value="加入購物車" onclick="add_shoppingcar(this)"/>
</td>
</tr>
<tr>
<td>鼠標</td>
<td >150</td>
<td>黑色</td>
<td>99</td>
<td>75%</td>
<td align="center">
<input type="button" value="加入購物車" onclick="add_shoppingcar(this)"/>
</td>
</tr>
<tr>
<td>鍵盤</td>
<td >120</td>
<td>黑色</td>
<td>50</td>
<td>80%</td>
<td align="center">
<input type="button" value="加入購物車" onclick="add_shoppingcar(this)"/>
</td>
</tr>
</table>
<h1> 購物車</h1>
<table border="1">
<thead>
<tr>
<th>商品</th>
<th >單價</th>
<th>數量</th>
<th>金額</th>
<th>刪除</th>
</tr>
</thead>
<tbody id="goods">
<!--<tr>
<td>面膜</td>
<td>150</td>
<td align="center">
<input type="button" value="-" id="jian" onclick="change(this,-1);"/>-->
<!--readonly規定輸入字段為只讀-->
<!--<input id="text" type="text" size="1" value="1" readonly="readonly" />
<input type="button" value="+" id="add" onclick="change(this,1);"/>
</td>
<td> <input id="money" size="1" value="80"></input></td>
<td align="center">
<input type="button" value="X" onclick="del(this)" />
</td>
</tr>-->
</tbody>
<tfoot>
<tr>
<td colspan="3" align="center" >總計</td>
<td id="total"></td>
<td>元</td>
</tr>
</tfoot>
</table>
</body>
<script type="text/javascript">
//this js中指當前對象
function add_shoppingcar(btn){
var tr=btn.parentNode.parentNode;
var tds=tr.getElementsByTagName("td");
var name=tds[0].innerHTML;
var price=tds[1].innerHTML;
var tbody=document.getElementById("goods");
var row=tbody.insertRow();//insertRow表格開頭插入新行
row.innerHTML="<td>"+name+"</td>"+
"<td>"+price+"</td>"+
"<td align='center'>"+
"<input type='button' value='-' id='jian' onclick='change(this,-1)' />"+
"<input id='text' type='text' size='1' value='1' readonly='readonly' />"+
"<input type='button' value='+' id='add' onclick='change(this,1)' />"+
"</td>"+
"<td>"+price+"</td>"+
"<td align='center'>"+
"<input type='button' value='X' onclick='del(this)'/>"+
"</td>"+
"</tr>"
total();
}
//增加減少數量,用n正負1來表示點擊了加減按鈕
function change(btn,n){
//獲取數量的三個input對象
var inputs = btn.parentNode.getElementsByTagName("input");
//獲取原來的數量
var amount = parseInt(inputs[1].value);
//當amount=1時不能再點擊"-"符號
//用n<0來表示點擊了減button
if(amount<=1 && n<0){
return;
}
//根據加減來改變數量
inputs[1].value = amount + n;
實現效果:
著過年放假在家復習了之前學的JS知識,用原生擼了一個購物車模塊,下面我來整理一下我的思路分享給大家。
1.1 廢話不多說,首先上個效果圖,如下:
購物車功能效果圖
1.2 功能介紹:
功能介紹完畢,下面開始介紹我寫這個購物車的步驟。
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();
});
寫到這里,我們購物車的所有功能都已經完成了。購物車這個模塊看似不難,其實這里面的坑也是不少的,例如:
以上就是我個人在寫這個購物車功能的全部新的,由于本人也是新手,可能還有其他更簡介方便的寫法,如果有問題,請各位大佬批評指正,不勝感激。
如果有剛開始學習JS的同學,想要源碼的各位親,可以關注并私信回復“購物車”即可。
單購物車展示
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>購物車</title>
<style type="text/css">
table{
width: 80%;
border: #000000 solid 1px;
border-collapse: collapse; /* 為表格設置合并邊框模型 */
}
th{
border: #000000 solid 1px;
}
tr{
border: #000000 solid 1px;
}
</style>
</head>
<body>
<div id="app" >
<table v-if="book.length">
<tr>
<th></th>
<th>書籍名稱</th>
<th>出版日期</th>
<th>價格</th>
<th>購買數量</th>
<th>操作</th>
</tr>
<tr v-for="(i,index) in book">
<th>{{i.id}}</th>
<th>{{i.name}}</th>
<th>{{i.date}}</th>
<th>{{i.price}}</th>
<th> <!-- :disabled="i.count <=1"數量小于等于1的時候點擊失效 -->
<button @click="jian(index)" :disabled="i.count <=1">-</button>
{{i.count}}
<button @click="jia(index)">+</button>
</th>
<th><button @click="shanchu(index)">移除</button></th>
</tr>
<tr>
<th>總價格:</th>
<th>{{zongjiage | guolv}}</th><!-- 使用過濾器把總價格過濾成我們想要的樣式 -->
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</table>
<h1 v-else>購物車里啥都沒有了</h1>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data:{
book:[
{
id: 1,
name: '《算法導論》',
date: '2006-9',
price: 85.00,
count: 1
},
{
id: 2,
name: '《UNIX編程藝術》',
date: '2006-2',
price: 59.00,
count: 1
},
{
id: 3,
name: '《編程珠璣》',
date: '2008-10',
price: 39.00,
count: 1
},
{
id: 4,
name: '《代碼大全》',
date: '2006-3',
price: 128.00,
count: 1
},
]
},
methods:{
jian(index){
this.book[index].count--
},
jia(index){
this.book[index].count++
},
shanchu(index){ // 點擊的哪個就把哪個的下標傳過來
this.book.splice(index, 1) // 因為所點擊的這行比下標多1個數,所以刪除傳過來的下標這一行的下一行
}
},
computed:{
zongjiage(){
let zong = 0;
for(let i=0; i<this.book.length; i++){
zong += this.book[i].price * this.book[i].count;
}
return zong;
}
},
filters:{ // 定義一個過濾器
guolv(price){ // 過濾函數 參數是價格
return '¥:' + price.toFixed(2) + '元' // toFixed(2)是保留2位小數
}
}
})
</script>
</body>
</html>
所有圖片連在一起就是本文的所有代碼
*請認真填寫需求信息,我們會在24小時內與您取得聯系。