简介这是一份基于HTML品优购电商项目的完整前端源码与毕业设计资料面向网页前端初学者、电商模板设计者及需要完成课程设计或毕业设计的大学生。资源以纯静态HTML页面呈现涵盖首页、列表页、商品详情页、购物车、登录注册、订单等全套商城核心模块并配有CSS样式、JavaScript交互及Hbuilder开发说明可直接运行和二次修改。压缩包共74个文件包括32个png、13个jpg图片素材11个css样式表8个html页面2个js脚本以及字体图标等辅助文件整体大小约6.2MB目录结构清晰图片与代码分离方便快速部署演示。已有8001人学习浏览。资源附带完整设计文档包含绪论、项目介绍、需求分析、页面制作过程、结论与参考文献等章节既能作为毕业设计说明书参考也可作为前端页面设计实训的完整案例适合学习电商网页布局与开发流程。1. 品优购这个HTML电商项目是什么静态页面为什么还能撑起一份毕业设计品优购是一个用纯HTML、CSS和少量原生JavaScript搭建的PC端电商前端项目页面包含首页、列表页、详情页、登录页和购物车。你可能觉得静态页面撑不起一份毕业设计但真正动手后会发现简单和完整是两回事——这个项目把前端入门要碰的全部基础点都装进去了语义化结构、浮动布局、精灵图、字体图标、轮播图、放大镜、返回顶部。它适合前端方向或网络工程方向做课程设计和毕业设计也适合当成html网页综合项目实战来练手。做这套项目的关键不是能不能跑而是能不能在任何一台电脑上双击打开不报错、把每个交互的代码逻辑讲清楚。2. 把品优购的骨架搭起来页面规划、目录规范与公共样式html网页制作和写一段脚本不一样它先考规划。品优购这类电商项目页面多、模块多如果一上来就写首页写到一半一定会乱。我一般先花半小时把页面清单和目录定死再动手写代码后面基本不会返工。2.1 页面划分与目录结构先定页再写代码一个标准的品优购毕业设计核心页面是五张首页、列表页、详情页、登录页、购物车页。注册页可以并入登录页做成一个链路不单独占篇幅。每张页面配一个专属CSS公共的头部和底部单独抽一个common.css交互集中放到js目录。pinyougou/ ├── index.html # 首页轮播、秒杀、楼层 ├── list.html # 商品列表页筛选、排序 ├── detail.html # 商品详情页放大镜、参数表 ├── login.html # 登录页 ├── cart.html # 购物车页 ├── css/ │ ├── base.css # 全局初始化reset 公共类 │ ├── common.css # 公共头部、底部、侧边栏 │ ├── index.css # 首页专属样式 │ └── list.css # 列表页专属样式 ├── js/ │ ├── index.js # 轮播、tab、倒计时 │ └── detail.js # 放大镜、数量加减 └── images/ ├── logo.png ├── sprite.png # 精灵图 └── banner/ └── banner1.jpg页面文件放根目录css、js、images各自成目录这是绝大多数前端项目共同的习惯。文件名统一小写加连字符不要出现Index.HTML、index(1).html这种名字评审老师打开目录看到这种命名第一印象就不会太好。页面文件核心模块备注首页index.html轮播图、秒杀倒计时、楼层tab最重工作量占40%列表页list.html排序栏、筛选区、分页与详情页联动详情页detail.html放大镜、商品参数、推荐位交互最难登录页login.html表单校验、协议勾选可合并注册购物车cart.html数量加减、合计计算可选加分项这个顺序也是开发顺序先把base和common写好再写首页因为首页用到的公共模块最多写透了后面四张页面只是换内容。目录和页面定下来之后进入全局样式。2.2 全局初始化样式reset写对后面少踩一半坑浏览器给标签预设的默认样式各不一样ul有缩进和圆点h1有加粗和上下边距img底部会留几像素空隙。如果不统一同一个页面在Chrome和Edge里可能差出几十像素。常见的做法是写一份base.css第一件事就是reset。/* 清除默认内外边距并把盒模型统一为 border-box */ * { margin: 0; padding: 0; box-sizing: border-box; } /* 清除列表符号 */ ul, ol { list-style: none; } /* 图片块级化去掉底部间隙 */ img { display: block; border: 0; } /* 链接去掉下划线统一继承色 */ a { text-decoration: none; color: #666; } /* 版心宽度1200px水平居中 */ .w { width: 1200px; margin: 0 auto; } /* 清除浮动 */ .clearfix::after { content: ; display: block; clear: both; }几个容易被忽略的参数。box-sizing: border-box全局开启之后padding和border会算进元素宽度里列表页的排序栏、详情页的参数表这类要贴边的布局会好算很多img { display: block }是给图片去底线间隙的不写的话图片和边框之间会多出3像素左右的空隙版心宽度固定用1200px这是PC端电商的经典宽度20寸以上屏幕两侧留白刚刚好1920的屏幕铺满也不挤。clearfix那段建议直接抄进base.css后面的浮动布局全部依赖它。很多人写项目从来不清理浮动结果导航下面的banner背景整个消失排查半天发现是父容器高度塌了。这些都是血泪经验。2.3 首页头部与导航浮动布局的两个关键点首页的header结构很典型左logo、中间搜索框、右购物车下面再跟一条nav导航。大多数人在这一步就开始写样式表了我建议先把HTML结构摆出来再考虑怎么排。!-- 首页头部logo 搜索 购物车 -- header classheader div classw clearfix div classlogo h1a hrefindex.html title品优购 img srcimages/logo.png alt品优购 /a/h1 /div div classsearch input typetext placeholder搜索商品 button搜索/button /div div classcart a hrefcart.html我的购物车/a /div /div /header结构里有两个容易被忽略的设计。logo用h1包a而不是直接放一个divh1在语义上代表页面最重要的内容对搜索引擎和设备读屏都友好列表页和详情页的logo同理input和button是inline-block元素中间会有默认的空白字符间距常见做法是在样式里把它们设置成display: block配合float: left或者直接在父容器上用flex去掉那点间距。浮动是这个项目里用得最多的布局手段。三块内容分别设置浮动之后整块区域的高度会依赖下面的导航撑起来所以父容器要加clearfix不然导航的margin-top会被吞掉。图标的定位、购物车上的角标数字则放到下一节用精灵图处理。头部骨架出来之后列表页和详情页就可以复用这套结构只需要换专属class。3. 列表页与详情页的交互细节精灵图定位、放大镜与返回顶部的坐标换算品优购项目的护城河在列表页和详情页。首页大多是展示这两张页面才有真正的几何计算。这一章处理三件事排序栏布局、精灵图坐标、放大镜的坐标换算。做完这一章html、css、js基础语法里的重点也就过了一遍。3.1 列表页排序栏边框合并与筛选区的布局列表页最上面的排序栏是综合 / 销量 / 价格 / 评论数四个tab经典做法是浮动列表。div classsort-bar ul classclearfix li classsort-active>.sort-bar ul li { float: left; padding: 8px 24px; border-right: 1px solid #ccc; cursor: pointer; font-size: 14px; } .sort-bar ul li.sort-active { color: #e33333; } .sort-bar ul li:last-child { border-right: 0; }这里有一个经典的1px坑每个li都设了border-right最后一个的右边框会多出来解决方式是用:last-child去掉边框。如果中间某个tab要加边框又不想影响宽度可以给li加margin-left: -1px让相邻边框重叠。这一页的筛选区边框经常出现双线就是没做这步处理。价格tab如果需要点击切换升降序可以在JS里维护一个sortOrder变量点击时取反再重排商品数组这是列表页比较出彩的扩展点。3.2 精灵图background-position的坐标换算方法精灵图CSS Sprite是品优购这类老牌项目必用的技术把一堆小图标拼到一张大图上减少HTTP请求。到今天虽然被iconfont替代了很多但精灵图仍然是展示基本功的好素材。/* 图标尺寸20x20在 sprite.png 中的坐标是 (0, -40px) */ .icon-search { width: 20px; height: 20px; background: url(../images/sprite.png) no-repeat 0 -40px; } /* 购物车图标在 (-60px, -40px) */ .icon-cart { width: 20px; height: 20px; background: url(../images/sprite.png) no-repeat -60px -40px; }坐标换算的规则只有一条background-position是背景图相对于元素左上角的偏移往右往下是正往左往上是负。元素要显示图标里某个区域就把背景图往左上挪。实际操作中先在PS或浏览器开发者工具里量出目标图标的宽、高、离精灵图左上角的x、y这四个值。宽高填进元素的width/heightx和y加负号填进background-position。x和y的数值偶尔会差1到2像素看起来会露出半个邻图这种对不齐最玄学其实就是测量基准没统一重测一次就行。精灵图的命名不要用sprites.png这种笼统的改成icon-common.png之类配合上面的icon-前缀类名代码可读性会好很多答辩时老师问起来也好讲。3.3 详情页放大镜两张图的坐标换算放大镜是详情页最核心的交互也是很多毕业设计的加分项。它本质上是在算三个坐标鼠标在容器里的位置、遮罩层的位置、大图的偏移。// 详情页放大镜detail.js var wrap document.getElementById(img-wrap); // 小图容器 var mask document.getElementById(mask); // 半透明遮罩 var big document.getElementById(big-img); // 大图尺寸为小图的2倍 wrap.addEventListener(mousemove, function (e) { // 1. 鼠标在容器内的坐标事件坐标 - 容器左上角视口坐标 var x e.clientX - wrap.getBoundingClientRect().left; var y e.clientY - wrap.getBoundingClientRect().top; // 2. 遮罩居中跟随减去遮罩自身一半尺寸 var maskW mask.offsetWidth / 2; var maskH mask.offsetHeight / 2; var targetX x - maskW; var targetY y - maskH; // 3. 边界限制遮罩不能超出容器 var maxX wrap.offsetWidth - mask.offsetWidth; var maxY wrap.offsetHeight - mask.offsetHeight; targetX Math.min(Math.max(0, targetX), maxX); targetY Math.min(Math.max(0, targetY), maxY); // 4. 让遮罩移动 mask.style.left targetX px; mask.style.top targetY px; // 5. 大图反向移动偏移量乘以大小比例 var scale big.offsetWidth / mask.offsetWidth; big.style.left -targetX * scale px; big.style.top -targetY * scale px; });拆开看这五步。第一步用getBoundingClientRect().left而不是offsetLeft是因为mousemove的clientX是相对视口的offsetLeft是相对定位父元素的两者混用会导致遮罩偏移越来越大这里用视口坐标相减最稳定。第三步的Math.min(Math.max(0, targetX), maxX)是标准夹紧写法小于0取0大于最大值取最大值。第五步的大图偏移用负值因为大图要往鼠标移动的反方向走遮罩往右移大图往左移。这里有个参数要特别注意大图和小图的关系业务上通常是2倍或3倍。大图的实际尺寸是800px小图容器是400px遮罩假设是200px那scale800/2004即遮罩移动1px大图移动4px。这个倍率决定了放大镜的灵敏度倍率越大移动越快也越容易眼睛跟不上一般放在3到4之间。3.4 返回顶部html一键返回顶部算法的两种写法商城页面很长返回顶部是标配交互。常见做法有两种一种是锚点一种是JS平滑滚动。锚点写法简单但会瞬移体验生硬平滑滚动需要自己算每一帧的位置。// 方式一锚点跳转适合内容短、不追求体验的页面 document.getElementById(backtop).addEventListener(click, function () { window.location.hash #top; }); // 方式二requestAnimationFrame 平滑滚动推荐使用 document.getElementById(backtop).addEventListener(click, function () { // 记录起始位置每次帧回调滚动到起点和终点之间的某个插值 var scrollTop window.pageYOffset || document.documentElement.scrollTop; var step 0; function go() { // 每次前进剩余距离的10%越滚越慢 scrollTop - (scrollTop - 0) * 0.1; window.scrollTo(0, scrollTop); if (scrollTop 1) { requestAnimationFrame(go); } else { window.scrollTo(0, 0); } } requestAnimationFrame(go); });第二种写法的核心是每次滚动剩余距离的10%第一次滚90第二次滚81理论上永远到不了0所以额外加一个scrollTop 1的判断小于1像素时直接归零。window.pageYOffset是标准属性老浏览器需要兼容document.documentElement.scrollTop两个取一个。如果页面是滚动容器而不是window滚动比如某个div设置了overflow:auto那要把window.scrollTo换成container.scrollTop value这个坑在购物车页面尤其常见。4. 给首页加交互轮播图、tab切换与倒计时的原生JS写法首页如果只有静态布局毕业设计的设计含量会打折扣。用原生JS写轮播图、tab切换、秒杀倒计时这三个交互代码量不大但足以覆盖事件绑定、定时器、DOM操作三类基本功。这里把html、css、js知识梳理一遍相当于把整个项目的交互层打通了。4.1 轮播图位移式切图与边界处理轮播图常见两种方案位移式和淡入淡出式。位移式是把所有banner横着排成一行通过移动ul的left来切换淡入淡出是叠放在同一位置切换透明度。品优购首页通常用位移式更适合展示完整大图。// 轮播图index.js var banner document.getElementById(banner); // 外层容器宽度等于一张图 var bannerWrap banner.querySelector(.banner-wrap); // ul宽度为N张图之和 var prevBtn document.getElementById(js-prev); var nextBtn document.getElementById(js-next); var index 0; var timer null; // 切换到指定下标 function goTo(i) { var maxIndex bannerWrap.children.length - 1; if (i maxIndex) i 0; if (i 0) i maxIndex; index i; bannerWrap.style.left -index * banner.offsetWidth px; } nextBtn.addEventListener(click, function () { goTo(index 1); }); prevBtn.addEventListener(click, function () { goTo(index - 1); }); // 自动播放每3秒切一张悬停暂停 timer setInterval(function () { goTo(index 1); }, 3000); banner.addEventListener(mouseenter, function () { clearInterval(timer); }); banner.addEventListener(mouseleave, function () { clearInterval(timer); timer setInterval(function () { goTo(index 1); }, 3000); });两个参数说明。banner.offsetWidth是单张图宽度ul的left每次移动一个整幅宽度所以要求所有banner图尺寸一致这是轮播图最容易翻车的前提条件图不是等宽的话切到一半就露馅。另外bannerWrap要有position: relative或absolute定位left属性才能生效。setInterval的3000毫秒是自动播放间隔如果调试的时候觉得太慢可以临时改成1000但交上去记得改回正常值。鼠标悬停暂停这里有个坑mouseleave里必须先clearInterval再重新setInterval如果只重新设置旧的定时器还在跑会出现切图越来越快的鬼畜现象这个在面试里也是高频考点。4.2 tab切换事件委托与data-index首页楼层和详情页参数区都有tab切换。最省事的写法是给每个tab单独绑click但代码冗余用事件委托只绑父容器一次。var tabNav document.getElementById(tab-nav); var tabPanes document.querySelectorAll(.tab-pane); tabNav.addEventListener(click, function (e) { var li e.target.closest(li); if (!li) return; // 切换高亮 tabNav.querySelectorAll(li).forEach(function (item) { item.classList.remove(active); }); li.classList.add(active); // 切换面板通过>// 秒杀倒计时以当天23:59:59为活动结束点 var endTime new Date(); endTime.setHours(23, 59, 59, 0); var hoursEl document.getElementById(hours); var minsEl document.getElementById(minutes); var secsEl document.getElementById(seconds); function tick() { var now Date.now(); var diff endTime - now; if (diff 0) { hoursEl.textContent 00; minsEl.textContent 00; secsEl.textContent 00; return; } // 分别取整小时、分钟、秒 var hours Math.floor(diff / (1000 * 60 * 60)); var minutes Math.floor(diff % (1000 * 60 * 60) / (1000 * 60)); var seconds Math.floor(diff % (1000 * 60) / 1000); hoursEl.textContent hours 10 ? 0 hours : hours ; minsEl.textContent minutes 10 ? 0 minutes : minutes ; secsEl.textContent seconds 10 ? 0 seconds : seconds ; } setInterval(tick, 1000);计算逻辑里Math.floor是关键diff是毫秒数先除以1000得到秒再分别除以3600和60取整。取模顺序是从大到小秒的取模是(1000*60)分钟的取模是(1000*60*60)注意不要写反。补零用三元表达式少于10的前面加0。Date.now()比new Date().getTime()少写几个字效果一样。最后说一个setInterval的漂移问题如果页面切到后台浏览器的定时器会被降频甚至暂停回来的时候倒计时会慢几秒这是浏览器共性的现象毕业设计里不用处理但如果答辩老师问到答出前端倒计时只是展示以服务器时间为准就算过关。5. 品优购项目避坑清单路径、滚动、兼容三类高频问题排查这一章是踩坑集中营。做这个项目的时候至少被五个问题卡过超过半小时而且每个问题的原因说出来都很简单。按现象→原因→解决整理出来能帮你少走大半弯路。5.1 五个必踩的坑现象、原因与修复写法坑一图片全部裂开CSS完全没生效。现象双击index.html页面是竖着的纯文字图片区域全是破图图标样式一点都没加载。原因CSS文件里写的背景图路径是url(images/...而CSS文件在css/目录下相对路径应该是url(../images/...页面里的img标签在根目录路径没问题但CSS里的路径错了整张样式表可能都加载不出来。解决统一检查所有url()开头的路径CSS里一律以CSS文件所在目录为基准往上一级用../。打开浏览器F12Network面板里404红色的文件就是路径出错的那个。坑二导航下面的banner背景消失内容挤到一堆。现象header下方的nav背景色没了或者banner被导航压住一部分。原因header或者nav里的子元素全部float了父容器高度塌成0背景和间距都跟着没了。解决在浮动子元素的父容器上加clearfix类就是2.2节写的那套::after伪元素清浮动。不要用给父容器写死height的方式因为内容一变高度就崩。坑三精灵图图标露出半个别的小图。现象搜索按钮的放大镜图标旁边多出半截购物车图标或者图标显示成一块花屏。原因background-position的坐标不对或者元素的宽高和精灵图中原图标尺寸不一致。解决先在PS里量出目标图标的x、y、宽、高元素宽高必须和原图标一致再让background-position等于负的x、负的y。多测一次差1像素的情况以实际显示为准不要用眼睛猜。坑四轮播点到最后一张再点下一张直接闪回第一张。现象切到第4张最后一张后点下一张画面直接切回第一张没有任何过渡。原因index1越过最大下标ul的left算出一个超大负值显示空白代码里又把index重置成了0。解决在切换函数里做边界判断if (i maxIndex) i 0。这行判断要写在赋值之前否则ul已经移动到错误位置了。坑五在教室电脑上样式全部乱套。现象自己电脑Chrome打开好好的交到教室电脑上布局错位、颜色不对、圆角全变直角。原因教室电脑的浏览器版本较旧不支持较新的CSS特性比如flex布局、rgba()颜色、position: sticky。解决项目里尽量用float布局做主结构颜色用十六进制需要半透明效果就单独做一张透明PNG。如果用了flex在文档开头写明推荐使用Chrome 80以上版本浏览。这一条不是代码问题是交付问题但比代码问题更影响成绩。5.2 一套快速排查流程按控制台和视觉异常反推碰到问题先别改代码按顺序做三件事。打开F12切到Console面板红色报错里会直接告诉你哪个变量未定义、哪个元素是null90%的JS问题在这一步就暴露了Console没有报错再去Network面板看CSS和JS文件有没有404有404就是路径问题前两步都没问题才轮到Elements面板选中出错的元素看右侧样式被划掉的样式就是被覆盖或者未命中的。这一步能解决绝大多数看起来是玄学的问题。前端调试最大的黑匣子是样式被覆盖比如写了一个.header { height: 80px; }但页面里header的高度不是80打开Elements面板会发现另一条.header { height: 100px; }把它划掉了这通常是后引入的CSS文件优先级更高或者选择器的权重更高。解决办法是按后写的优先、class优先于标签去调整而不是在那条样式后面加!important硬刚。排查完这三个面板还没解决用二分注释法把js文件里一半的代码注释掉看问题是否消失。如果消失了说明问题在被注释的那一半里再缩小范围继续试。这个方法在处理轮播图鬼畜、倒计时不走这类交互问题时特别快比一行行读代码高效得多。6. 毕业设计交付前按这个清单自检十分钟页面写完不等于项目完了。品优购这类前端毕设最终交付的是一套能走通、能讲清、能复现的源码。我建议交付前做一张自检表一项一项过检查项检查方法合格标准页面完整性逐个打开index、list、detail、login、cart无404、无破图、无样式错位路径健壮性把整个项目复制到另一个层级更深的目录再打开所有资源正常加载交互可用性轮播下一张/上一张、返回顶部、放大镜逐一操作无报错、边界不越界代码可读性抽查js目录看是否有注释、命名是否统一每个函数能说清作用文档配套检查是否有readme或设计说明写清运行方式换台电脑能按说明跑起来运行方式在文档里只写双击index.html还不够最好补一句如果页面显示异常用本地HTTP服务运行然后写一行python -m http.server 8080。见过太多人因为直接双击打不开而以为是源码坏了其实只是某些浏览器对本地file协议有限制。打包多个html文件时尤其注意保持目录结构完整只拷html不拷images是交作业前最常见的低级失误。演示路径我建议固定成一条线首页轮播→秒杀倒计时→列表页排序→详情页放大镜→登录页表单→购物车加减合计。这条线把项目里的每个技术点都覆盖到了老师问什么你都有东西指。演示的时候主动说清楚这里的放大镜用到了坐标换算这里的返回顶部用了requestAnimationFrame比等老师提问效果要好得多。最后说一个我自己的教训。当年我做类似项目时tab切换的代码写了一大坨重复绑定答辩老师问如果再加两个tab要改多少行我说要加两段事件绑定老师当场指出可以用事件委托。从那次之后我养成了一个习惯任何交互功能写完先检查一遍这段逻辑能不能在结构变化后不修改。GitHub上确实能找到大量现成的电商前端项目但拿来用的前提是你讲得清楚每一行关键代码在干什么。自己把品优购从头做一遍把轮播、放大镜、倒计时这三个硬骨头啃下来比直接移植高大上框架要实在得多。希望这份落地清单对你有帮助按这个思路走一遍你的项目也能在演示的时候做到心里有底。本文还有配套的精品资源点击获取