批改状态:合格
老师批语:class是function的语法糖,封装的很不错
<div class="container"><!-- 1. 图片组 --><div class="img-group"></div><!-- 2. 图片中下部的小按钮 --><div class="btn-group"></div><!-- 3. 翻页 --><div class="skip"><a class="prev"><</a><a class="next">></a></div></div>
/* 初始化 */* {margin: 0;padding: 0;box-sizing: border-box;}a {text-decoration: none;}/* 轮播图的容器 */.container {width: 62.5em;height: 22em;margin: 1em auto;/* 转为定位元素/定位父级 */position: relative;}.container:hover {cursor: pointer;}/* 图片组 */.container > .img-group img {width: 100%;height: 100%;border-radius: 0.6em;/* 默认全部隐藏 */display: none;/* 将所有的图片进行绝对定位,确保每一次只看到一张,所有图片共享这个容器 */position: absolute;left: 0;top: 0;}/* 设置默认显示的图片(第一张) */.container > .img-group img.active {display: block;}/* 按钮组(独立按钮) */.container > .btn-group {position: absolute;left: 0;right: 0;bottom: 1rem;/* 水平居中 */text-align: center;}.container > .btn-group span {/* 转成行内块元素: 即能水平排列,双支持宽度设置 */display: inline-block;padding: 0.5em;margin: 0 0.2em;background-color: #fff;border-radius: 50%;}.container > .btn-group span:hover {cursor: pointer;}.container > .btn-group .active {background-color: #10d1f3;}/* 翻页按钮 */.container .skip a {position: absolute;width: 2.5rem;height: 2.5rem;line-height: 2.5rem;border-radius: 50%;text-align: center;opacity: 0.3;top: 9rem;font-weight: lighter;font-size: 2rem;background-color: #787373;}.container .skip .prev {left: 1rem;}.container .skip .next {right: 1rem;}.container .skip *:hover {opacity: 0.6;color: #666;}
class Swiper {constructor(imgs, code, imgcode, btncode) {this.imgs = imgs;this.code = code;this.imgcode = imgcode;this.btncode = btncode;this.next = null;this.prev = null;this.timer = null;this.clickEvent = new Event("click");}init() {this.next = document.querySelector(".skip .next");this.prev = document.querySelector(".skip .prev");this.next.addEventListener('click', ()=>this.nextImg());this.prev.addEventListener('click', ()=>this.prevImg());// 1. 生成轮播图所有图片this.createImgs(this.imgcode, this.imgs.length);// 2. 生成与轮播图数量对应的小按钮this.createBtns(this.btncode, this.imgs.length);this.autoPlay();// 鼠标移入时停止自动播放,移出时启动自动播放this.code.addEventListener("mouseover", ()=>this.stopPlay());this.code.addEventListener("mouseout", ()=>this.autoPlay());}// 生成图片createImgs(parent, length) {// 正确的做法, 应该是将所有图片,先在内存中创建,然后再统一的插入到页面中, 这样就只需要渲染一次dom一次// 文档片断元素const frag = document.createDocumentFragment();for (let i = 0; i < length; i++) {const img = document.createElement("img");img.src = this.imgs[i];img.alt = `banner${i + 1}`;// 为每一张图片添加一个自定义属性"data-index", 用它与小按钮进行绑定img.dataset.index = `${i + 1}`;if (i === 0) img.classList.add("active");// 内存中执行了四次frag.append(img);}// 页面中只渲染了一次,效率杠杠的parent.append(frag);}// 生成按钮createBtns(parent, length) {const frag = document.createDocumentFragment();for (let i = 0; i < length; i++) {const span = document.createElement("span");span.dataset.index = `${i + 1}`;if (i === 0) span.classList.add("active");// 给新生成的按钮,添加点击事件,用来切换图片span.onclick = ev => this.showImgs(ev);frag.append(span);}parent.append(frag);}// 按钮事件showImgs(ev) {// 1. 获取所有图片和按钮const imgArr = this.imgcode.querySelectorAll("img");const btnArr = this.btncode.querySelectorAll("span");// 2. 因为我们要根据用户的点击确定当前应该显示哪一个,所以应该将之前的激活全部取消掉// 但是我们又不知道当前是哪个处于激活状态, 全部过一遍// btnArr.forEach(item => {// if (item.classList.contains("active")) item.classList.remove("active");// });// imgArr.forEach(item => {// if (item.classList.contains("active")) item.classList.remove("active");// });// 将上面二段代码合并[btnArr, imgArr].forEach(items => {items.forEach(item => {if (item.classList.contains("active")) item.classList.remove("active");});// 3. 再给当前正在点击的按钮添加激活,然后再根据当前激活的按钮确定应该显示哪一张图片ev.target.classList.add("active");imgArr.forEach(img => {// 这张应该显示的图片的data-index应该与按钮 的data-index相等,就显示出来if (ev.target.dataset.index === img.dataset.index) img.classList.add("active");});});}// 翻页事件// 向前翻页prevImg() {//1. 当前图片和当前的按钮const currentImg = this.imgcode.querySelector("img.active");const currentBtn = this.btncode.querySelector("span.active");// 2. 去掉当前图片和按钮的激活样式currentImg.classList.remove("active");currentBtn.classList.remove("active");// 3. 获取当前图片和按钮的前一个兄弟元素const prevImg = currentImg.previousElementSibling;const prevBtn = currentBtn.previousElementSibling;// 4. 判断,如果存在前一张图片,就设置为激活if (prevImg !== null && prevBtn !== null) {prevImg.classList.add("active");prevBtn.classList.add("active");} else {// 将最后一个图片设置为激活显示,实现循环显示this.imgcode.lastElementChild.classList.add("active");this.btncode.lastElementChild.classList.add("active");}}// 向后翻页nextImg() {//1. 当前图片和当前的按钮const currentImg = this.imgcode.querySelector("img.active");const currentBtn = this.btncode.querySelector("span.active");// 2. 去掉当前图片和按钮的激活样式currentImg.classList.remove("active");currentBtn.classList.remove("active");// 3. 获取当前图片和按钮的前一个兄弟元素const nextImg = currentImg.nextElementSibling;const nextBtn = currentBtn.nextElementSibling;// 4. 判断,如果存在前一张图片,就设置为激活if (nextImg !== null && nextBtn !== null) {nextImg.classList.add("active");nextBtn.classList.add("active");} else {// 将最后一个图片设置为激活显示,实现循环显示this.imgcode.firstElementChild.classList.add("active");this.btncode.firstElementChild.classList.add("active");}}// 自动播放autoPlay() {const self = this;// ev: 事件对象,在方法总是有效的this.timer = setInterval(() => {// console.log(this.next);this.next.dispatchEvent(this.clickEvent, self.nextImg);}, 2000);}// 自动停止stopPlay() {clearInterval(this.timer);}}const imgs = ["images/banner_1.jpg", "images/banner_2.jpg", "images/banner_3.jpg", "images/banner_4.jpg"];const container = document.querySelector(".container");// 图片组const imgGroup = document.querySelector(".container > .img-group");// 按钮组const btnGroup = document.querySelector(".container > .btn-group");// 提供4个参数: 图片数组、轮播图盒子节点元素、图片组盒子节点元素、轮播图底部按钮节点const swiper = new Swiper(imgs, container, imgGroup, btnGroup);window.onload = () => swiper.init();

<table><caption>我的购物车</caption><thead><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></thead><tbody><tr><td><input type="checkbox" name="item" class="item" value="SN-1020" checked /></td><td><a href=""><img src="images/p1.png" alt="" /></a></td><td>JavaScript权威指南(第七版)</td><td>本</td><td class="price">100</td><td><input type="number" min="1" value="1" /></td><td class="amount">0</td></tr><tr><td><input type="checkbox" name="item" class="item" value="SN-1020" checked /></td><td><a href=""><img src="images/p2.png" alt="" /></a></td><td>JavaScript高级程序设计(第四版)</td><td>本</td><td class="price">129</td><td><input type="number" min="1" value="1" /></td><td class="amount">0</td></tr><tr><td><input type="checkbox" name="item" class="item" value="SN-1030" checked /></td><td><a href=""><img src="images/p3.png" alt="" /></a></td><td>JavaScript忍者秘籍(第二版)</td><td>台</td><td class="price">99</td><td><input type="number" min="1" value="1" /></td><td class="amount">0</td></tr><tr><td><input type="checkbox" name="item" class="item" value="SN-1040" checked /></td><td><a href=""><img src="images/p4.png" alt="" /></a></td><td>ThinkPad X1 Carbon 2021</td><td>台</td><td class="price">12999</td><td><input type="number" min="1" value="1" /></td><td class="amount">0</td></tr><tr><td><input type="checkbox" name="item" class="item" value="SN-1050" checked /></td><td><a href=""><img src="images/p5.png" alt="" /></a></td><td>MacBook Pro 16 10代i7 16G 512G</td><td>台</td><td class="price">23800</td><td><input type="number" min="1" value="1" /></td><td class="amount">0</td></tr></tbody><tfoot><tr><td colspan="5">总计:</td><td id="sum">0</td><td id="total-amount">0</td></tr></tfoot></table>
* {margin: 0;padding: 0;box-sizing: border-box;}html {font-size: 10px;}box {font-size: 1.6rem;}table {border-collapse: collapse;width: 90%;text-align: center;margin: 1rem auto;color: #666;}table caption {margin-bottom: 1rem;font-size: 2rem;}table th,table td {padding: 0.5rem;font-weight: normal;}table thead tr:first-of-type {background-color: rgb(26, 187, 187);height: 3rem;color: white;}table thead tr:first-of-type:hover {opacity: 0.8;cursor: pointer;}table input[type="checkbox"] {width: 1rem;height: 1rem;}/* table tr:nth-of-type(even) {background-color: #eee;} */table tbody tr:hover {background-color: lightcyan;transition: 0.5s;cursor: pointer;}table input[type="number"] {height: 2em;width: 4em;border: none;border-bottom: 1px solid;outline: none;text-align: center;}/* table input[type="number"]:focus {background-color: rgb(26, 187, 187);} */tbody img {width: 3em;transition: all 0.6s;cursor: pointer;}tbody img:hover {transform: scale(4);}tfoot tr {height: 3rem;color: coral;background-color: lightcyan;}button {width: 15rem;height: 2rem;outline: none;border: none;background-color: rgb(26, 187, 187);color: white;letter-spacing: 5px;}button:hover {background-color: coral;transition: 0.2s;cursor: pointer;}@media screen and (min-width: 400px) {html {font-size: 12px;}}@media screen and (min-width: 600px) {html {font-size: 14px;}}@media screen and (min-width: 800px) {html {font-size: 16px;}}
// 功能一: 完成全选和全不选功能// 1. 全选复选框const checkAll = document.querySelector("#check-all");// 2. 每个商品的复选框const checkItems = document.getElementsByName("item");// ==========================================================// 功能二: 自动计算// 分析: 所有的计算,都是基于"数量的变化", 第一步就要获取到所有商品数量控件const numInput = document.querySelectorAll('input[type="number"]');// 给每一个数量控件绑定一个change事件,进行监听它的变量// 当控件的值发生变化时, 自动进行重新 计算numInput.forEach(input => (input.onchange = autoTotal));// 当页面加载完成时,应该将自动计算函数执行一次(初始化)window.onload = autoCalculate;function autoCalculate() {// 1. 获取每个商品的金额, 金额 = 数量 * 单价// 数量, 当前有多个商品,所以应该返回一个由数量组成的集合/数组const numbers = document.querySelectorAll('input[type="number"]');// console.log(numbers);// [...numbers].forEach(num => console.log(typeof parseInt(num.value)));// [...numbers].forEach(num => console.log(num.value * 1));//map()代替forEach: 因为forEach()没有返回值,map()功能与forEach一样的,但是有一个数组返回值const numArr = [...numbers].map(num => num.value * 1);// 获取单价组成的数组const prices = document.querySelectorAll("tbody .price");// console.log(prices);const priceArr = [...prices].map(price => price.textContent * 1);// console.log(numArr, priceArr);// 每一个商品与单价的乘积是它的金额,有多个商品,所以应该返回 一个由"金额"组成的数组// reduce()const amountArr = [priceArr, numArr].reduce((prev, curr) => prev.map((item, key) => item * curr[key]));// console.log(amountArr);// 2. 商品总数let sum = numArr.reduce((prev, curr) => prev + curr);// 3. 所有商品总金额let total = amountArr.reduce((prev, curr) => prev + curr);// 4. 将以上的计算结果,渲染到页面中// forEach(function(正在遍历的元素,该元素的索引,数组))document.querySelectorAll(".amount").forEach((item, index) => (item.textContent = amountArr[index]));document.querySelector("#sum").textContent = sum;document.querySelector("#total-amount").textContent = total;}// 全选时checkAll.onchange = (ev) => {checkItems.forEach(item => (item.checked = ev.target.checked));if (!ev.target.checked) {document.querySelector("#sum").textContent = 0;document.querySelector("#total-amount").textContent = 0;} else {autoCalculate()}}// 选择某个商品时, 数量,总金额实时更新function autoTotal() {// 1. 获取每个商品的金额, 金额 = 数量 * 单价// 数量, 当前有多个商品,所以应该返回一个由数量组成的集合/数组const numbers = document.querySelectorAll('input[type="number"]');const checkeds = [...checkItems].filter((item, idx) => {if (item.checked) {item.dataset.checkidx = idx;return true;}return false;}).map((item) => item.dataset.checkidx);const numArr = [...numbers].filter((v, idx) => checkeds.includes(`${idx}`)).map(num => num.value * 1);console.log([...numbers].filter((v, idx) => checkeds.includes(`${idx}`)));// 获取单价组成的数组const prices = document.querySelectorAll("tbody .price");const priceArr = [...prices].filter((v, idx) => checkeds.includes(`${idx}`)).map(price => price.textContent * 1);const amountArr = [priceArr, numArr].reduce((prev, curr) => prev.map((item, key) => item * curr[key]));// 2. 商品总数let sum = numArr.reduce((prev, curr) => prev + curr);// 3. 所有商品总金额let total = amountArr.reduce((prev, curr) => prev + curr);// 4. 将以上的计算结果,渲染到页面中document.querySelector("#sum").textContent = sum;document.querySelector("#total-amount").textContent = total;}checkItems.forEach((item)=> item.onchange = ()=>{// 全选复选框选中状态根据所有商品的复选框状态更改checkAll.checked = [...checkItems].every(item => item.checked);autoTotal();});

```
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号