小帽商城
第十三章 放大镜缩略图数据动态渲染
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小帽商城项目详情页面</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<!-- 最外层的包裹元素 -->
<div id="wrapper">
<!-- 头部开始 -->
<header id="header">
<!-- 上面部分 -->
<div class="headTop">
<!-- 版心元素 -->
<div class="headTopMain">
<!-- 左侧 -->
<div class="left">
<h5>欢迎来到小帽商城!请</h5>
<p>
<a href="javasvript:;">登录</a>
<a href="javasvript:;">注册</a>
</p>
</div>
<!-- 右侧 -->
<div class="right">
<nav>
<a href="javascript:;">我的订单</a>
<a href="javascript:;">我的购物车</a>
<a href="javascript:;">我的小帽商城</a>
<a href="javascript:;">小帽商城会员</a>
<a href="javascript:;">企业采购</a>
<a href="javascript:;">关注小帽商城</a>
<a href="javascript:;">合作招商</a>
<a href="javascript:;">商家后台</a>
</nav>
</div>
</div>
</div>
<!-- 下面部分 -->
<div class="headBottom">
<!-- 版心元素 -->
<div class="headBottomMain">
<!-- logo -->
<h1 class="logo">
<a href="javascript:;">
<img src="image/lemonmall.png" alt="">
</a>
</h1>
<!-- 搜索框 -->
<div class="search">
<input type="text" placeholder="请输入搜索内容">
<input type="submit" value="搜索">
</div>
</div>
</div>
</header>
<!-- 头部结束 -->
<!-- 分类导航开始 -->
<div id="navWrap">
<!-- 版心元素 -->
<div class="navWrapMain">
<a href="javascript:;">全部商品分类</a>
<a href="javascript:;">服装城</a>
<a href="javascript:;">美妆馆</a>
<a href="javascript:;">小帽超市</a>
<a href="javascript:;">全球购</a>
<a href="javascript:;">闪购</a>
<a href="javascript:;">团购</a>
<a href="javascript:;">有趣</a>
<a href="javascript:;">秒杀</a>
</div>
</div>
<!-- 分类导航结束 -->
<!-- 内容区域开始 -->
<div id="content">
<!-- 版心元素 -->
<div class="contentMain">
<!-- 路径导航开始 -->
<div id="navPath">
</div>
<!-- 路径导航结束 -->
<!-- 中间区域开始 -->
<div id="center">
<!-- 左侧放大镜开始 -->
<div id="left">
<!-- 上边 -->
<div id="leftTop">
<!-- 小图框 -->
<div id="smallPic">
<!-- 小图片 -->
<img src="images/s1.png" alt="">
<!-- 蒙版元素 -->
</div>
<!-- 大图框 -->
</div>
<!-- 下边 -->
<div id="leftBottom">
<a href="javascript:;">< </a>
<div id="piclist">
<ul></ul>
</div>
<a href="javascript:;"> > </a>
</div>
</div>
<!-- 左侧放大镜结束 -->
<!-- 右侧商品详情区域开始 -->
<!-- 右侧商品详情区域结束 -->
</div>
<!-- 中间区域结束 -->
</div>
</div>
<!-- 内容区域结束 -->
</div>
<script src="js/data.js"></script>
<script src="js/index.js"></script>
</body>
</html>
// js\index.js
// 作用:需要将所有的DOM元素对象以及相关的资源全部都加载完毕之后,再来实现的事件函数
window.onload = function(){
// 路径导航的数据渲染
navPathDataBind();
function navPathDataBind() {
...
}
// 放大镜的移入、移出效果
bigClassBind();
function bigClassBind() {
...
}
// 动态渲染放大镜缩略图的数据
thunbnailData();
function thunbnailData() {
/**
* 思路:
* 1.先获取piclist元素下的ul
* 2.再获取data.js文件下的goodData->imagessrc
* 3.遍历数组,根据数组的长度来创建li元素
* 4.让ul遍历追加li元素
*/
// 1. 获取piclist下的ul
var ul = document.querySelector('#wrapper #content .contentMain #center #left #leftBottom #piclist ul');
// 2. 获取imagessrc数据
var imagessrc = goodData.imagessrc;
// 3. 遍历数组
for(var i = 0; i < imagessrc.length; i++) {
// 4. 创建li元素
var newLi = document.createElement('li');
// 5. 创建img元素
var newImg = document.createElement('img');
newImg.src = imagessrc[i].s;
// 6. 让li追加img元素
newLi.appendChild(newImg);
// 7. 让ul追加li元素
ul.appendChild(newLi);
}
}
}
第十四章 点击缩略图实现换小图以及大图效果
// js\index.js
// 作用:需要将所有的DOM元素对象以及相关的资源全部都加载完毕之后,再来实现的事件函数
window.onload = function(){
// 声明一个记录点击的缩略图下标
var bigimgIndex = 0;
// 路径导航的数据渲染
navPathDataBind();
function navPathDataBind() {
...
}
// 放大镜的移入、移出效果
bigClassBind();
function bigClassBind() {
/**
* 思路:
* 1.获取小图框元素对象,并且设置移入事件(onmouseenter)
* 2.动态的创建蒙版元素以及大图框和大图片元素
* 3.移出时(onmouseleave)需要移除蒙版元素和大图框
*/
// 1. 获取小图框元素
var smallPic = document.querySelector('#wrapper #content .contentMain #center #left #leftTop #smallPic')
// 获取leftTop元素
var leftTop = document.querySelector('#wrapper #content .contentMain #center #left #leftTop');
// 获取数据
var imagessrc = goodData.imagessrc;
// 2. 设置移入事件
smallPic.onmouseenter = function() {
// 3. 创建蒙版元素
var maskDiv = document.createElement('div');
maskDiv.className = "mask";
// 4. 创建大图框元素
var BigPic = document.createElement('div');
BigPic.id = "bigPic";
// 5. 创建大图片元素
var BigImg = document.createElement('img');
BigImg.src = imagessrc[bigimgIndex].b;
// 6. 大图框追加大图片
BigPic.appendChild(BigImg);
// 7. 让小图框来追加蒙版元素
smallPic.appendChild(maskDiv);
// 8. 让LeftTop元素追加大图框
leftTop.appendChild(BigPic);
// 设置移动事件
smallPic.onmousemove = function(event) {
// event.clientX:鼠标点距离浏览器左侧X轴的值
// getBoundingClientRect().left:小图框元素距离浏览器左侧可视left值
// offsetWidth:为元素的占位宽度
var left = event.clientX - smallPic.getBoundingClientRect().left - maskDiv.offsetWidth / 2;
var top = event.clientY - smallPic.getBoundingClientRect().top - maskDiv.offsetHeight / 2;
// 判断
// 让蒙版元素只能在小图框里移动
if(left < 0) {
left = 0;
}else if(left > smallPic.clientWidth - maskDiv.offsetWidth){
left = smallPic.clientWidth - maskDiv.offsetWidth
}
if(top < 0) {
top = 0;
}else if(top > smallPic.clientHeight - maskDiv.offsetHeight){
top = smallPic.clientHeight - maskDiv.offsetHeight
}
// 设置left和top属性
maskDiv.style.left = left + "px";
maskDiv.style.top = top + "px";
// 移动的比例关系 = 蒙版元素移动的距离 / 大图片元素移动的距离
// 蒙版元素移动的距离 = 小图框宽度 - 蒙版元素的宽度
// 大图片元素移动的距离 = 大图片宽度 - 大图框元素的宽度
var scale = (smallPic.clientWidth - maskDiv.offsetWidth) / (BigImg.offsetWidth - BigPic.clientWidth);
BigImg.style.left = -left / scale + "px";
BigImg.style.top = -top / scale + "px";
}
// 设置移除事件
smallPic.onmouseleave = function() {
// 让小图框移除蒙版元素
smallPic.removeChild(maskDiv);
// 让LeftTop元素移除大图框
leftTop.removeChild(BigPic);
}
}
}
// 动态渲染放大镜缩略图的数据
thunbnailData();
function thunbnailData() {
/**
* 思路:
* 1.先获取piclist元素下的ul
* 2.再获取data.js文件下的goodData->imagessrc
* 3.遍历数组,根据数组的长度来创建li元素
* 4.让ul遍历追加li元素
*/
// 1. 获取piclist下的ul
var ul = document.querySelector('#wrapper #content .contentMain #center #left #leftBottom #piclist ul');
// 2. 获取imagessrc数据
var imagessrc = goodData.imagessrc;
// 3. 遍历数组
for(var i = 0; i < imagessrc.length; i++) {
// 4. 创建li元素
var newLi = document.createElement('li');
// 5. 创建img元素
var newImg = document.createElement('img');
newImg.src = imagessrc[i].s;
// 6. 让li追加img元素
newLi.appendChild(newImg);
// 7. 让ul追加li元素
ul.appendChild(newLi);
}
}
// 点击缩略图的效果
thumbnailClick();
function thumbnailClick() {
/**
* 思路:
* 1.获取所有的li元素,并且循环发生点击事件
* 2.点击缩略图需要确定其下标位置来找到对应小图路径和大图路径替换现有src的值
*/
// 1. 获取所有的li元素
var liNodes = document.querySelectorAll('#wrapper #content .contentMain #center #left #leftBottom #piclist ul li');
var smallPic_img = document.querySelector('#wrapper #content .contentMain #center #left #leftTop #smallPic img')
var imagessrc = goodData.imagessrc;
// 小图路径需要默认和imagessrc的第一个元素小图的路径是一致的
smallPic_img.src = imagessrc[0].s;
// 2. 循环点击这些li元素
for(var i = 0; i < liNodes.length; i++) {
// 在点击事件之前,给每一个元素都添加上自定义下标
liNodes[i].index = i; /** 还可以通过setAttribute('index', i) */
liNodes[i].onclick = function() {
var idx = this.index; /** 事件函数中的this永远指向的是实际发生事件的目标源对象 */
bigimgIndex = idx;
// 变换小图路径
smallPic_img.src = imagessrc[idx].s;
}
}
}
}
第十五章 计算每一次图片移动的距离以及ul移动的距离
// js\index.js
// 作用:需要将所有的DOM元素对象以及相关的资源全部都加载完毕之后,再来实现的事件函数
window.onload = function(){
...
thumbnailLeftRightClick();
// 点击缩略图左右箭头的效果
function thumbnailLeftRightClick() {
/**
* 思路:
* 1.先获取左右两端的箭头按钮
* 2.在获取可视的div以及ul元素和所有的li元素
* 3.计算(发生起点、步长、总体运动的距离值)
* 3。然后再发生点击事件
*/
// 1. 获取箭头元素
var prev = document.querySelector('#wrapper #content .contentMain #center #left #leftBottom a.prev');
var next = document.querySelector('#wrapper #content .contentMain #center #left #leftBottom a.next');
// 2.获取可视的div以及ul元素和所有的li元素
var ul = document.querySelector('#wrapper #content .contentMain #center #left #leftBottom #piclist ul');
var liNodes = document.querySelectorAll('#wrapper #content .contentMain #center #left #leftBottom #piclist ul li');
// 3.计算
// 发生起点
var start = 0;
// 步长
var step = (liNodes[0].offsetWidth + 20) * 2;
// 总体运动的距离值 = ul的宽度 - div框的宽度 = (图片的总数 - div中显示的数量) * (li的宽度 + 20)
var endPosition = (liNodes.length - 5) * (liNodes[0].offsetWidth + 20);
// 4.发生事件
prev.onclick = function() {
start -= step;
if(start < 0) {
start = 0;
}
ul.style.left = -start + "px";
}
next.onclick = function() {
start += step;
if(start > endPosition) {
start = endPosition;
}
ul.style.left = -start + "px";
}
}
}
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小帽商城项目详情页面</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<!-- 最外层的包裹元素 -->
<div id="wrapper">
...
<!-- 内容区域开始 -->
<div id="content">
<!-- 版心元素 -->
<div class="contentMain">
<!-- 路径导航开始 -->
<div id="navPath">
</div>
<!-- 路径导航结束 -->
<!-- 中间区域开始 -->
<div id="center">
<!-- 左侧放大镜开始 -->
<div id="left">
<!-- 上边 -->
<div id="leftTop">
<!-- 小图框 -->
<div id="smallPic">
<!-- 小图片 -->
<img src="images/s1.png" alt="">
<!-- 蒙版元素 -->
</div>
<!-- 大图框 -->
</div>
<!-- 下边 -->
<div id="leftBottom">
<a href="javascript:;" class="prev">< </a>
<div id="piclist">
<ul></ul>
</div>
<a href="javascript:;" class="next"> > </a>
</div>
</div>
<!-- 左侧放大镜结束 -->
<!-- 右侧商品详情区域开始 -->
<!-- 右侧商品详情区域结束 -->
</div>
<!-- 中间区域结束 -->
</div>
</div>
<!-- 内容区域结束 -->
</div>
<script src="js/data.js"></script>
<script src="js/index.js"></script>
</body>
</html>
// css\index.less
@import 'mixins/clear.less';
// 最外层的包裹元素
#wrapper{
...
// 内容区域开始
#content{
// 版心元素
.contentMain{
width: 1200px;
margin: 15px auto 0 auto;
font-size: 0px;
// 路径导航开始
#navPath{
padding: 9px 15px 9px 0;
// font-size: 0px;
a{
// 行标签和行标签之间会有小缝隙
// 处理方式就是给它们的直接父元素上面添加一个font-size为0
// 还得添加一下它们原本的字体大小
font-size: 12px;
}
i{
padding: 0 5px;
font-size: 12px;
}
}
// 路径导航结束
// 中间区域开始
#center{
margin: 5px 0 15px;
// 左侧放大镜开始
#left{
width: 400px;
float: left;
// 上边
#leftTop{
width: 400px;
position: relative;
// 小图框
#smallPic{
width: 400px;
height: 400px;
border: 1px solid #dfdfdf;
position: relative;
img{}
// 蒙版元素
.mask{
width: 200px;
height: 200px;
background: rgba(255, 255, 255, .5);
border: 1px solid #ddd;
position: absolute;
left: 0px;
top: 0px;
}
}
// 大图框
#bigPic{
width: 400px;
height: 400px;
border: 1px solid #ddd;
left: 420px;
top: 0px;
position: absolute;
// 原图太大,溢出隐藏
overflow: hidden;
// 大图片
img{
width: 800px;
height: 800px;
position: absolute;
left: 0px;
top: 0px;
}
}
}
// 下边
#leftBottom{
width: 400px;
margin-top: 5px;
.clearfix();
a{
width: 10px;
height: 54px;
border: 1px solid #ccc;
background: #ebebeb;
text-align: center;
line-height: 54px;
float: left;
&:first-child {
margin-right: 4px;
}
}
#piclist{
width: 372px;
height: 56px;
float: left;
overflow: hidden;
position: relative;
ul{
// 强制不换行 ☆
white-space: nowrap;
position: absolute;
left: 0px;
transition: 0.5s;
// font-size: 0px;
li{
width: 50px;
height: 50px;
border: 1px solid #ccc;
padding: 2px;
margin-right: 20px;
display: inline-block;
img{
width: 50px;
height: 50px;
}
}
}
}
}
}
}
}
}
// 内容区域结束
}
第十六章 右侧商品上半部详情介绍的布局搭建
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小帽商城项目详情页面</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<!-- 最外层的包裹元素 -->
<div id="wrapper">
...
<!-- 内容区域开始 -->
<div id="content">
<!-- 版心元素 -->
<div class="contentMain">
<!-- 路径导航开始 -->
<div id="navPath">
</div>
<!-- 路径导航结束 -->
<!-- 中间区域开始 -->
<div id="center">
<!-- 左侧放大镜开始 -->
...
<!-- 左侧放大镜结束 -->
<!-- 右侧商品详情区域开始 -->
<div class="right">
<!-- 商品详情数据结构开始 -->
<div class="rightTop">
<h3>Apple iPhone 13 Pro Max (A2644) 128GB 远峰蓝色 支持移动联通电信5G 双卡双待手机</h3>
<p>推荐选择下方[移动优惠购],手机套餐齐搞定,不用换号,每月还有花费返</p>
<div class="priceWrap">
<div class="priceTop">
<span>价 格</span>
<div class="price">
<span>¥</span>
<p>5299</p>
<i>降价通知</i>
</div>
<p>
<span>累计评价</span>
<span>670000</span>
</p>
</div>
<div class="priceBottom">
<span>促 销</span>
<p>
<span>加价购</span>
<span>满999.00另加20.00元,或满1999.00另加30.00元,或满2999.00另加40.00元,即可在购物车换购热销商品</span>
</p>
</div>
</div>
<div class="support">
<span>支 持</span>
<p>以旧换新,闲置手机回收 5G套餐超值抢 礼品购</p>
</div>
<div class="address">
<span>配 送 至</span>
<p>广东省 广州市 天河区</p>
</div>
</div>
<!-- 商品详情数据结构结束 -->
<!-- 商品参数数据结构开始 -->
<div class="rightBottom"></div>
</div>
<!-- 右侧商品详情区域结束 -->
</div>
<!-- 中间区域结束 -->
</div>
</div>
<!-- 内容区域结束 -->
</div>
<script src="js/data.js"></script>
<script src="js/index.js"></script>
</body>
</html>
// css\index.less
@import 'mixins/clear.less';
// 最外层的包裹元素
#wrapper{
// 头部开始
...
// 头部结束
// 分类导航开始
...
// 分类导航结束
// 内容区域开始
#content{
// 版心元素
.contentMain{
width: 1200px;
margin: 15px auto 0 auto;
// 路径导航开始
...
// 路径导航结束
// 中间区域开始
#center{
margin: 5px 0 15px;
.clearfix();
// 左侧放大镜开始
#left{
...
}
// 右侧商品详情区域开始
.right{
width: 700px;
float: right;
// 商品详情数据结构开始
.rightTop{
h3{
font-size: 14px;
line-height: 21px;
margin-top: 15px;
}
> p{
color: #FF8C00;
margin-top: 15px;
}
.priceWrap{
margin-top: 10px;
line-height: 28px;
background: #FFF5EE;
padding: 7px;
.priceTop{
.clearfix();
// 价格
> span {
margin-right: 15px;
float: left;
}
// 中间
.price {
float: left;
color: #cc1122;
> span {
font-size: 16px;
float: left;
}
p{
font-size: 24px;
float: left;
font-weight: bold;
}
i{
font-size: 12px;
color: #cc1122;
float: left;
}
}
// 累积评价
> p {
float: right;
> span{}
}
}
.priceBottom{
.clearfix();
// 促销
> span {
float: left;
margin-right: 15px;
}
// 加价购
p {
width: 520px;
line-height: 28px;
float: left;
> span {
color: #999;
// 加价购
&:first-child{
background: #FFA500;
padding: 3px;
color: #fff;
}
}
}
}
}
.support{
margin-top: 10px;
line-height: 28px;
.clearfix();
// > 代表直接的子节点
> span{
margin-right: 15px;
float: left;
}
> p{
float: left;
color: #999;
}
}
.address {
border-bottom: 1px solid #ededed;
padding-bottom: 5px;
margin-top: 10px;
line-height: 28px;
.clearfix();
> span{
margin-right: 15px;
float: left;
}
> p{
float: left;
color: #999;
}
}
}
}
}
}
}
// 内容区域结束
}