主要内容 - 几个实战:
- 背景换肤
- 表格背景随鼠标而动
- 作业:**购物车自动价格变化(随着是否选中商品),费老鼻子劲了,几点收获:
- 通过for循环给类数组numbers加上index方法
- 通过checkbox[number.index]进行checked判断,然后决定是返回0,还是正常的value。这样就在counts array形成前将数据整理好了。
- 一个listener绑定两个function,这个之前没有尝试过。一个function是用来检验checkAll的,一个用来autoCalculate的。这样才能在checkbox发生change的时候两个动作一并完成。
- 前面走的弯路:a - 在每个checkbox change那块琢磨;b-在autoCalculate那块琢磨。貌似很多时候都被counts = getCounts(numbers)截胡了,于是最后从numbers这块直接入手。**
1. 背景换肤
三个文件:html、css、js
换肤主要在js中实现。
准备图片放入到static下面的images中
- html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>换肤</title>
<link rel="stylesheet" href="static/css/change-skin.css" />
</head>
<body>
<div class="container">
<img src="static/images/1.jpg" alt="" />
<img src="static/images/2.jpg" alt="" />
<img src="static/images/3.jpg" alt="" />
</div>
<script src="static/js/change-skin.js"></script>
</body>
</html>
- css
.container {
width: 300px;
display: grid;
grid-template-columns: repeat(3, 1fr);
column-gap: 10px;
}
.container > img {
width: 100%;
border: 3px solid #fff;
opacity: 0.6;
}
.container > img:hover {
opacity: 1;
cursor: pointer;
width: 105%;
}
body {
background-image: url("../images/1.jpg");
background-repeat: no-repeat;
}
- js
// 思路:将当前图片的src赋值给body的背景
// 事件代理
document.querySelector(".container").addEventListener("click", setSkin, false);
function setSkin(ev) {
// ev.target: 事件触发者(img)
// ev.currentTarget: 事件绑定者(.container)
document.body.style.backgroundImage = "url(" + ev.target.src + ")";
}
2. 表格的隔行变色
- 同样是html、css、js三个文件
这块用js控制class的添加可以实现,也可以通过css中直接鼠标hover去实现。具体见代码
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>表格的隔行变色</title>
<link rel="stylesheet" href="static//css/change-line-color.css" />
</head>
<body>
<table>
<caption>
员工信息表
</caption>
<thead>
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>手机</th>
<th>邮箱</th>
<th>部门</th>
<th>职位</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>杨过</td>
<td>28</td>
<td>男</td>
<td>1890***655</td>
<td>123@qq.com</td>
<td>市场部</td>
<td>销售员</td>
</tr>
<tr>
<td>2</td>
<td>小龙女</td>
<td>28</td>
<td>女</td>
<td>1390***755</td>
<td>13323@qq.com</td>
<td>开发部</td>
<td>鼓励师</td>
</tr>
<tr>
<td>3</td>
<td>李莫愁</td>
<td>38</td>
<td>女</td>
<td>1359***222</td>
<td>1909023@qq.com</td>
<td>市场部</td>
<td>部长</td>
</tr>
<tr>
<td>4</td>
<td>尹志平</td>
<td>24</td>
<td>男</td>
<td>1889***882</td>
<td>3898023@qq.com</td>
<td>总经办</td>
<td>保洁</td>
</tr>
<tr>
<td>5</td>
<td>欧阳克</td>
<td>39</td>
<td>男</td>
<td>1399***882</td>
<td>4678933@qq.com</td>
<td>开发部</td>
<td>部长</td>
</tr>
</tbody>
</table>
<!-- <script src="static/js/change-line-color.js"></script> -->
</body>
</html>
- css
table {
border: 1px solid #000;
border-collapse: collapse;
margin: 30px auto;
text-align: center;
width: 90%;
}
table caption {
font-size: 1.2rem;
margin-bottom: 15px;
}
th,
td {
border: 1px solid #000;
padding: 5px;
}
table thead tr:first-of-type {
background-color: #ddd;
}
.active {
background-color: lightcyan;
}
/* 加点css也能实现,这样就可以不用下面的js来listener来实现了*/
table tbody tr:hover {
background-color: lightcyan;
}
- js
var tbody = document.querySelector("tbody");
// 鼠标移入行时添加背景
tbody.addEventListener("mousemove", addBgColor, false);
// 鼠标移出行时添加背景
tbody.addEventListener("mouseout", removeBgColor, false);
function addBgColor(ev) {
// ev.target: <td></td>
// console.log(ev.target);
ev.target.parentNode.classList.add("active");
}
function removeBgColor(ev) {
ev.target.parentNode.classList.remove("active");
}
3. 表格或购物篮全选
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>购物车全选</title>
<link rel="stylesheet" href="static/css/check-all.css" />
</head>
<body>
<table>
<caption>
购物车
</caption>
<thead>
<tr>
<th>
<input
type="checkbox"
name="checkAll"
id="check-all"
checked
/><label for="check-all">全选</label>
</th>
<th>ID</th>
<th>品名</th>
<th>单位</th>
<th>单价/元</th>
<th>数量</th>
<th>金额/元</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input type="checkbox" name="itemId" value="SN-1020" checked />
</td>
<td>SN-1010</td>
<td>MacBook Pro电脑</td>
<td>台</td>
<td>18999</td>
<td>1</td>
<td>18999</td>
</tr>
<tr>
<td>
<input type="checkbox" name="itemId" value="SN-1020" checked />
</td>
<td>SN-1020</td>
<td>iPhone手机</td>
<td>部</td>
<td>4999</td>
<td>2</td>
<td>9998</td>
</tr>
<tr>
<td>
<input type="checkbox" name="itemId" value="SN-1030" checked />
</td>
<td>SN-1030</td>
<td>智能AI音箱</td>
<td>只</td>
<td>399</td>
<td>5</td>
<td>1995</td>
</tr>
<tr>
<td>
<input type="checkbox" name="itemId" value="SN-1040" checked />
</td>
<td>SN-1040</td>
<td>SSD移动硬盘</td>
<td>个</td>
<td>888</td>
<td>2</td>
<td>1776</td>
</tr>
<tr>
<td>
<input type="checkbox" name="itemId" value="SN-1050" checked />
</td>
<td>SN-1050</td>
<td>黄山毛峰</td>
<td>斤</td>
<td>999</td>
<td>3</td>
<td>2997</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5">总计:</td>
<td>13</td>
<td>35765</td>
</tr>
</tfoot>
</table>
<div style="width: 90%; margin: 10px auto;">
<button style="float: right; width: 100px;">结算</button>
</div>
<script src="static/js/check-all.js"></script>
</body>
</html>
- 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: 1px solid;
padding: 5px;
}
table thead tr:first-of-type {
background-color: lightblue;
}
/* 隔行变色: 偶数行 */
table tbody tr:nth-of-type(even) {
background-color: lightcyan;
}
table input[type="checkbox"] {
width: 20px;
height: 20px;
}
button {
width: 150px;
height: 30px;
outline: none;
border: none;
background-color: seagreen;
color: white;
letter-spacing: 5px;
}
button:hover {
background-color: coral;
cursor: pointer;
}
- js
// 全选按钮
var checkAllBtn = document.querySelector("#check-all");
// 单个按钮
var checkItemBtns = document.getElementsByName("itemId");
// 给全选按钮添加事件
checkAllBtn.addEventListener("change", checkAll, false);
// checkAll()
function checkAll(ev) {
var checkStatus = ev.target.checked;
// 遍历下面的所有的单个按钮,根据当前全选按钮的状态来设置他们
checkItemBtns.forEach(function (btn) {
// btn.checked = checkStatus ? true : false;
//简化
btn.checked = checkStatus;
});
}
// 给下面每个独立的复选框添加事件
checkItemBtns.forEach(function (btn) {
// 根据每个复选框的状态,控制全选的状态
btn.addEventListener("change", checkAllStatus, false);
});
// checkAllStatus()
function checkAllStatus(ev) {
var counter = 0;
checkItemBtns.forEach(function (btn) {
if (btn.checked) counter++;
});
// 设置全选按钮的状态
// checkItemBtns.length === 5, 共5个商品
// counter: 当前选中的商品
// checkAllBtn.checked = counter === checkItemBtns.length ? true : false;
checkAllBtn.checked = counter === checkItemBtns.length;
}
4. 商品价格汇总
- 这块是在之前基础上改的,因此只有html和css。
- 将之前的数量input变成了可以修改的,另外增加了小记栏。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>购物车全选</title>
<link rel="stylesheet" href="static/css/check-all.css" />
</head>
<body>
<table>
<caption>
购物车
</caption>
<thead>
<tr>
<th>
<input
type="checkbox"
name="checkAll"
id="check-all"
checked
/><label for="check-all">全选</label>
</th>
<th>ID</th>
<th>品名</th>
<th>单位</th>
<th>单价/元</th>
<th>数量</th>
<th>金额/元</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input type="checkbox" name="itemId" value="SN-1020" checked />
</td>
<td>SN-1010</td>
<td>MacBook Pro电脑</td>
<td>台</td>
<td>18999</td>
<td>
<input type="number" name="counter" value="1" min="1" step="1" />
</td>
<td></td>
</tr>
<tr>
<td>
<input type="checkbox" name="itemId" value="SN-1020" checked />
</td>
<td>SN-1020</td>
<td>iPhone手机</td>
<td>部</td>
<td>4999</td>
<td>
<input type="number" name="counter" value="2" min="1" step="1" />
</td>
<td></td>
</tr>
<tr>
<td>
<input type="checkbox" name="itemId" value="SN-1030" checked />
</td>
<td>SN-1030</td>
<td>智能AI音箱</td>
<td>只</td>
<td>399</td>
<td>
<input type="number" name="counter" value="3" min="1" step="1" />
</td>
<td></td>
</tr>
<tr>
<td>
<input type="checkbox" name="itemId" value="SN-1040" checked />
</td>
<td>SN-1040</td>
<td>SSD移动硬盘</td>
<td>个</td>
<td>888</td>
<td>
<input type="number" name="counter" value="4" min="1" step="1" />
</td>
<td></td>
</tr>
<tr>
<td>
<input type="checkbox" name="itemId" value="SN-1050" checked />
</td>
<td>SN-1050</td>
<td>黄山毛峰</td>
<td>斤</td>
<td>999</td>
<td>
<input type="number" name="counter" value="5" min="1" step="1" />
</td>
<td></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5">总计:</td>
<td id="total-num"></td>
<td id="total-amount"></td>
</tr>
</tfoot>
</table>
<div style="width: 90%; margin: 10px auto;">
<button style="float: right; width: 100px;">结算</button>
</div>
<script src="static/js/check-all.js"></script>
<script src="static/js/auto-calculate.js"></script>
</body>
</html>
// 商品数量: 数组
var counts = [];
// 商品金额: 数组
var amounts = [];
// 商品单价: 数组
var unitPrices = [];
// 商品总数量
var totalNum = 0;
// 商品总金额
var totalAmount = 0;
// 获取商品数量控件<input:number>
var numbers = document.querySelectorAll("input[type=number]");
// 获取所有商品单价
var prices = document.querySelectorAll("tbody > tr > td:nth-of-type(5)");
// 1. 生成商品数量: 数组
counts = getCounts(numbers);
function getCounts(numbers) {
// Array.from(numbers): 将类数组,转为真正数组
// map()与forEach()功能相同, 只不过他返回一个新数组
return Array.from(numbers).map(function (item) {
return parseInt(item.value); // 转成数字
});
}
console.log(counts);
// 2. 商品单价: 数组
unitPrices = getUnitPrices(prices);
function getUnitPrices(prices) {
return Array.from(prices).map(function (item) {
return parseInt(item.innerText);
});
}
console.log(unitPrices);
// 3. 计算每个商品的金额
amounts = getEveryAmount(counts, unitPrices);
function getEveryAmount(counts, unitPrices) {
var result = [];
for (var i = 0; i < unitPrices.length; i++) {
// 金额 = 单价 * 数量
amount = unitPrices[i] * counts[i];
// 将这个商品金额添加到金额数组中
result.push(amount);
}
return result;
}
console.log(amounts);
// 将每个商品金额渲染到页面中
var subtotal = document.querySelectorAll("tbody > tr > td:last-of-type");
// forEach(function (value,[ key, array]))
subtotal.forEach(function (sub, index) {
sub.innerHTML = amounts[index];
});
// 4. 计算数量总和
totalNum = numTotal(counts);
// reduce()归并,最终将所有数组元素累加成一个值返回
function numTotal(counts) {
return counts.reduce(function (prev, next) {
return (prev += next);
}, 0);
}
console.log(totalNum);
// 将数量之和添加到页面中
document.getElementById("total-num").innerText = totalNum;
// 5 计算所有商品总额
totalAmount = getTotalAmount(amounts);
function getTotalAmount(amounts) {
return amounts.reduce(function (prev, next) {
return (prev += next);
}, 0);
}
console.log(totalAmount);
// 将总金额添加到页面中
document.getElementById("total-amount").innerText = totalAmount;
// 6. 给每个数量控件添加change事件
numbers.forEach(function (item) {
item.addEventListener("change", autoCalculate, false);
});
function autoCalculate(ev) {
// 更新总数量
counts = getCounts(numbers);
totalNum = numTotal(counts);
document.getElementById("total-num").innerText = totalNum;
// 更新每件商品的金额
var subtotal = document.querySelectorAll("tbody > tr > td:last-of-type");
subtotal.forEach(function (sub, index) {
sub.innerHTML = amounts[index];
});
amounts = getEveryAmount(counts, unitPrices);
// 更新总金额
totalAmount = getTotalAmount(amounts);
document.getElementById("total-amount").innerText = totalAmount;
}
5. 作业
- 一键换肤, 全选全不选,二选一完成
- 购物车自动计算,添加全选全不选,单独选择时也能自动计算功能
html部分没有懂,主要是js部分改了下。将两个js文件放到了一个文件中。
结果如下:
- my_calculate.js
// 单个商品数量: 数组
var counts = [];
// 单个商品单价: 数组
var unitPrices = [];
// 单个商品小计金额: 数组
var amounts = [];
// 总商品数量
var totalNum = 0;
// 总商品金额
var totalAmount = 0;
// 获取商品数量控件<input:number>
var numbers = document.querySelectorAll("input[type=number]");
for (var i = 0; i < numbers.length; i++) {
numbers[i].index = i;
}
// for是为了给numbers赋予index方法,这样后面就可以用numbers的index来选择对应的checkbox了。
// 见下面的counts计算部分。
// 获取所有商品单价
var prices = document.querySelectorAll("tbody > tr > td:nth-of-type(5)");
// 全选按钮
var checkAllBtn = document.querySelector("#check-all");
// 单个按钮
var checkItemBtns = document.getElementsByName("itemId");
// checkAllStatus()
counts = getCounts(numbers);
function getCounts(numbers) {
return Array.from(numbers).map(function (item) {
if (checkItemBtns[item.index].checked)
// 这块就用到了上面的index。false的判断是:.checked == false,一定要注意是双===
// 当然这个地方没用==,原因是== true就直接省略掉了。
return parseInt(item.value); // 转成数字
else return 0;
});
}
// 给全选按钮添加事件
checkAllBtn.addEventListener("change", checkAll, false);
checkAllBtn.addEventListener("change", autoCalculate, false);
// 一个事件添加多个function。下面的btn部分也有。
// checkAll()
function checkAll(ev) {
var checkStatus = ev.target.checked;
// 遍历下面的所有的单个按钮,根据当前全选按钮的状态来设置他们
checkItemBtns.forEach(function (btn) {
// btn.checked = checkStatus ? true : false;
//简化
btn.checked = checkStatus;
});
}
// 给下面每个独立的复选框添加事件
checkItemBtns.forEach(function (btn) {
// 根据每个复选框的状态,控制全选的状态
btn.addEventListener("change", checkAllStatus, false);
btn.addEventListener("change", autoCalculate, false);
});
function checkAllStatus(ev) {
var counter = 0;
checkItemBtns.forEach(function (btn) {
if (btn.checked) counter++;
})
// 设置全选按钮的状态
// checkItemBtns.length === 5, 共5个商品
// counter: 当前选中的商品
// checkAllBtn.checked = counter === checkItemBtns.length ? true : false;
// 下面的为简写
checkAllBtn.checked = counter === checkItemBtns.length;
}
// 1. 生成商品数量: 数组(这块放到前面去了,主要是为了将number的返回跟checkbox的检验结合起来)
// 这段很重要,需要先将类数组转化为真数组。
// counts = getCounts(numbers);
// function getCounts(numbers) {
// // Array.from(numbers): 将类数组,转为真正数组
// // map()与forEach()功能相同, 只不过他返回一个新数组
// return Array.from(numbers).map(function (item) {
// return parseInt(item.value); // 转成数字
// });
// }
// console.log(counts);
// 2. 商品单价: 数组
unitPrices = getUnitPrices(prices);
function getUnitPrices(prices) {
return Array.from(prices).map(function (item) {
return parseInt(item.innerText);
});
}
console.log(unitPrices);
// 3. 计算每个商品的金额
amounts = getEveryAmount(counts, unitPrices);
function getEveryAmount(counts, unitPrices) {
var result = [];
for (var i = 0; i < unitPrices.length; i++) {
// 金额 = 单价 * 数量
amount = unitPrices[i] * counts[i];
// 将这个商品金额添加到金额数组中
result.push(amount);
}
return result;
}
console.log(amounts);
// 将每个商品金额渲染到页面中
var subtotal = document.querySelectorAll("tbody > tr > td:last-of-type");
// forEach(function (value,[ key, array]))
subtotal.forEach(function (sub, index) {
sub.innerHTML = amounts[index];
});
// 4. 计算数量总和
totalNum = numTotal(counts);
// reduce()归并,最终将所有数组元素累加成一个值返回
function numTotal(counts) {
return counts.reduce(function (prev, next) {
return (prev += next); // 最终返回结果都累加到了prev中
}, 0);
}
console.log(totalNum);
// 将数量之和添加到页面中
document.getElementById("total-num").innerText = totalNum;
// 5 计算所有商品总额
totalAmount = getTotalAmount(amounts);
function getTotalAmount(amounts) {
return amounts.reduce(function (prev, next) {
return (prev += next);
}, 0);
}
console.log(totalAmount);
// 将总金额添加到页面中
document.getElementById("total-amount").innerText = totalAmount;
// 6. 给每个数量控件添加change事件,这样数量改变的时候小计及总数就会发生变化
numbers.forEach(function (item) {
item.addEventListener("change", autoCalculate, false);
});
function autoCalculate(ev) {
// 更新总数量
counts = getCounts(numbers);
totalNum = numTotal(counts);
document.getElementById("total-num").innerText = totalNum;
// 更新每件商品的金额
amounts = getEveryAmount(counts, unitPrices);
var subtotal = document.querySelectorAll("tbody > tr > td:last-of-type");
subtotal.forEach(function (sub, index) {
sub.innerHTML = amounts[index];
});
// 更新总金额
totalAmount = getTotalAmount(amounts);
document.getElementById("total-amount").innerText = totalAmount;
}