这里主要是作为自己学习用的
这里纯JS原生,实现的动态效果有:放大镜 ,缩略图,选中商品属性 ,点击切换高亮的功能.点击叉号删除
//封装一个函数 处理路径导航的效果
function createBreadcrumb() {
//获取路径导航的数据
var path = goodsData.path;
//获取路径导航的容器元素
var breadcrumb = document.querySelector('#root #content .container .breadcrumb');
//遍历数组
for (var i = 0; i < path.length; i++) {
//创建 a 元素
var a = document.createElement('a');
//设置标签文本
a.innerHTML = path[i].title;
//设置 a 元素的 href 属性
a.href = path[i].url;
//将 a 元素插入到容器中
breadcrumb.appendChild(a);
//检测是否为数组的最后一个元素
if (i !== path.length - 1) {
//创建 span 元素
var span = document.createElement('span');
//设置 span 的文本
span.innerHTML = '/';
//将 span 插入到容器中
breadcrumb.appendChild(span);
}
}
}
createBreadcrumb();
//遍历渲染缩略图元素
function renderThumbnails() {
//获取所有的图片
var images = goodsData.imagessrc;
//获取 ul 元素
var ul = document.querySelector('#root #content .container .goods-intro-section .left .thumbnails-section .thumbnails ul')
//获取小图
var smallImg = document.querySelector('#root #content .container .goods-intro-section .left .small-img > img');
var bigImg = document.querySelector('#root #content .container .goods-intro-section .left .small-img .big-img img');
//遍历图片数组
images.forEach(function (item, index) {
//创建 li 元素
var li = document.createElement('li');
//为当前元素添加数字下标
li.index = index;
// li.setAttribute('index', index); // 可以为标签设置属性, 方便事件中获取
// li.dataset.index = index;// dataset //也可以通过 dataset 特性设置标签属性
// li.dataset.abc = 'iloveyou';
//创建 img 元素
var img = document.createElement('img');
//设置图片的 src 属性
img.setAttribute('src', item.s);
//将 img 元素插入到 li 中
li.append(img);
//将 li 插入到 ul 中
ul.append(li);
//判断是否为第一个元素
if (index === 0) {
//将小图和大图的 src 设置为当前的值
//设置小图的 src
smallImg.src = item['s'];
//设置大图的 src
bigImg.src = item.b;
//设置当前 li 的类名为 active
li.className = 'active';
}
//为 li 元素绑定单击事件
li.onclick = function () {
//同辈元素移除 active 类名
this.parentNode.querySelectorAll('li').forEach(function (item) {
item.className = '';
})
//为当前元素添加 active 类
this.className = 'active';
//获取当前元素在同辈元素中的下标
var i = this.index;
// console.log(this.index);
// console.log(this.getAttribute('index'));
// console.log(this.dataset.index);
//获取当前下标对应的图片
var images = goodsData.imagessrc[i];
//修改小图和大图的路径
smallImg.src = images.s;
bigImg.src = images.b;
}
});
}
renderThumbnails();
//实现放大镜效果
function magnifier() {
//获取 small-img 元素
var smallImgDiv = document.querySelector('#root #content .container .goods-intro-section .left .small-img');
//获取 mask 元素
var mask = document.querySelector('#root #content .container .goods-intro-section .left .small-img .mask')
//获取大图
var bigImg = document.querySelector('#root #content .container .goods-intro-section .left .small-img .big-img img')
//绑定鼠标移动事件
smallImgDiv.onmousemove = function (e) {
//获取鼠标距离左侧的偏移量
var x = e.clientX;
var y = e.clientY;
//获取遮罩层元素宽度的一半
var w = mask.offsetWidth / 2;
var h = mask.offsetHeight / 2;
//获取 small-img 距离窗口左侧的距离
var l = smallImgDiv.getBoundingClientRect().left;
var t = smallImgDiv.getBoundingClientRect().top;
//计算 mask 元素的 left 值
var newLeft = x - w - l;
var newTop = y - h - t;
//左侧边界判断
if (newLeft < 0) {
newLeft = 0;
}
//计算最大的 left 值
var maxLeft = smallImgDiv.clientWidth - mask.offsetWidth;
//右侧边界判断
if (newLeft > maxLeft) {
newLeft = maxLeft;
}
//上方边界检测
if (newTop < 0) {
newTop = 0;
}
//计算最大的 top 值
var maxTop = smallImgDiv.clientHeight - mask.offsetHeight;
//下方边界检测
if (newTop > maxTop) {
newTop = maxTop;
}
//设置 mask 元素的 left
mask.style.left = newLeft + 'px';
//设置 mask 元素的 top
mask.style.top = newTop + 'px';
//控制右侧大图的位移
// 获取小图 div 的宽度
var sw = smallImgDiv.clientWidth;
var sh = smallImgDiv.clientHeight;
// var s
//获取大图的宽度
var bigImgWidth = bigImg.offsetWidth;
var bigNewLeft = newLeft / sw * bigImgWidth;
var bigImgHeight = bigImg.offsetHeight;
var bigNewTop = newTop / sh * bigImgHeight;
//设置大图的 left 值
bigImg.style.left = -bigNewLeft + 'px';
bigImg.style.top = -bigNewTop + 'px';
}
}
magnifier();
//缩略图中上一个和下一个的效果实现
function nextAndPrev() {
//获取下一个的按钮
var nextBtn = document.querySelector('#root #content .container .goods-intro-section .left .thumbnails-section .next')
var prevBtn = document.querySelector('#root #content .container .goods-intro-section .left .thumbnails-section .prev')
//缩略图的容器
var thumbnail = document.querySelector('#root #content .container .goods-intro-section .left .thumbnails-section .thumbnails')
//获取 ul
var thumbUL = document.querySelector('#root #content .container .goods-intro-section .left .thumbnails-section .thumbnails ul')
//获取缩略图中单个 li 的宽度
var thumbLi = document.querySelector('#root #content .container .goods-intro-section .left .thumbnails-section .thumbnails ul li');
var w = thumbLi.offsetWidth + 20;
//绑定事件
// //过addEventListener(添加点击事件监听器)形式的绑定事件不会互相抵消,从而实现一个按钮控制多个事件
nextBtn.addEventListener('click', function () {
//获取 ul 的左侧的偏移量
var left = thumbUL.offsetLeft;
//减少 ul 的 left 值
var newLeft = left - w * 2;
//计算最大的 left 绝对值
var maxLeft = thumbUL.offsetWidth - thumbnail.offsetWidth - 12;
//边界检测
if (newLeft < -maxLeft) {
newLeft = -maxLeft;
}
//设置 ul 新的 left 值
// element.style //行内样式操作 适用于要修改的不多
thumbUL.style.left = newLeft + 'px';
});
//点击上一个
// 给 prevBtn添加函数监听事件
prevBtn.addEventListener('click', function () {
//获取 ul 的左侧的偏移量
//offsetLeft获取的是相对于父对象的左边距
var left = thumbUL.offsetLeft;
//减少 ul 的 left 值
var newLeft = left + w * 2;
//边界检测
//if(条件表达式){console.log("a")};//如果条件为真,执行该处代码
if (newLeft > 0) {
newLeft = 0
}
//设置 ul 新的 left 值
//left获取或设置相对于具有定位属性(position定义为relative)的父对象的左边距
thumbUL.style.left = newLeft + 'px';
})
}
// 结尾要写调用 函数才会生效
nextAndPrev();
//设置商品的基本信息
function setGoodsBasicInfo() {
//获取商品的详细信息
//var 定义的变量的作用域是函数作用域(补充: var 声明的变量具有声明提升。)
var goodsDetail = goodsData.goodsDetail;
//获取商品基本信息的容器元素
// 声明一个变量,变量的作用域范围=获取文本翁电脑中 root下面basic-info-section类名的元素.
//document.querySelector 获取文档中的元素
var goodsDetailContainer = document.querySelector('#root #content .container .goods-intro-section .right .basic-info-section')
//商品字符串
// JavaScript 中,使用字符串连接有 几 种方式:连接符(+)、反引号(`)、join()、concat()。
var goodsStr = `<!-- 商品标题 -->
<h3>` + goodsDetail.title + `</h3>
<!-- 优惠提示 -->
<p>` + goodsDetail.recommend + `</p>
<!-- 价格与促销 -->
<div class="price-sale-section">
<!-- 价格 -->
<div class="price-section">
<!-- 属性 -->
<div class="attr">价 格</div>
<!-- 价格 -->
<div class="value">
<span>¥</span>
<span>${goodsDetail.price}</span>
<span>降价通知</span>
</div>
<!-- 评价数量 -->
<div class="eval-total">
累计评价 ${goodsDetail.evaluateNum}
</div>
</div>
<!-- 促销 -->
<div class="sale-section">
<div class="attr">
促 销
</div>
<div class="value">
<span>${goodsDetail.promoteSales.type}</span> ${goodsDetail.promoteSales.content}
</div>
</div>
</div>
<!-- 支持 -->
<div class="support">
<div class="attr">
支 持
</div>
<div class="value">
${goodsDetail.support}
</div>
</div>
<!-- 地址 -->
<div class="address">
<div class="attr">
配 送 至
</div>
<div class="value">
${goodsDetail.address}
</div>
</div>`; // 声明字符串的另外一种语法 `djslfajlewaof`
//设置容器的 HTML 内容
goodsDetailContainer.innerHTML = goodsStr;
}
setGoodsBasicInfo();
//渲染商品属性相关的结构
function renderGoodsAttrs() {
//获取商品属性的数据
var data = goodsData.goodsDetail.crumbData;
//商品属性容器
var goodsAttrContainer = document.querySelector('#root #content .container .goods-intro-section .right .choose-section');
//遍历 data 数组
data.forEach(function (item, index) {
//创建 dl 元素
var dl = document.createElement('dl');
//为 dl 设置下标
dl.index = index;
//创建 dt 元素
var dt = document.createElement('dt');
//设置 dt 的文本内容
//“innerHTML”:获取的是该标签的所有内容,包括其子标签,
//“innerText”和“textContent”是无法把html标签转化成标签的,而是当做纯文本内容显示出来,而“innerHTML”则可把内容中的标签转化成html标签.
dt.innerHTML = item.title;
//组装
//ppendChild() 方法可向节点的子节点列表的末尾添加新的子节点。dl的子节点添加dt节点
dl.appendChild(dt);
//循环创建 dd
//forEach内联回调函数 forEach(function(value) { /* … */ })
item.data.forEach(function (value, index) {
//创建 dd 元素
var dd = document.createElement('dd');
//判断是否为第一个元素
if (index === 0) {
dd.classList.add('active');
}
//设置 dd 元素的文本
dd.innerHTML = value.type;
//将属性存储到标签身上
dd.setAttribute('change', value.changePrice);
//将 dd 插入到 dl 中
dl.appendChild(dd);
//为 dd 元素绑定单击事件
dd.onclick = function () {
//同辈元素移除 active 类
this.parentNode.querySelectorAll('dd').forEach(function (v) {
v.classList.remove('active');
});
//自身添加 active
this.classList.add('active');
}
});
//将 dl 插入到容器中
goodsAttrContainer.appendChild(dl);
})
}
renderGoodsAttrs();
//点击创建属性标签
function handleGoodsAttrTag() {
//获取 choosed-section 元素
var choosedSection = document.querySelector('#root #content .container .goods-intro-section .right .choosed-section');
//获取所有的 dd
var dds = document.querySelectorAll('dd');
//获取商品属性
var data = goodsData.goodsDetail.crumbData;
//[undefined, undefined, undefined, undefined];
//声明一个数组
var arr = new Array(data.length);
//绑定单击事件
dds.forEach(function (item) {
item.addEventListener('click', function () {
//获取当前行在同辈中的下标
var index = this.parentNode.index;
//为数组中添加元素
arr[index] = this.innerHTML;
//清空原来的 mark 元素
choosedSection.innerHTML = '';
//遍历 arr
arr.forEach(function (item, i) {
//判断是否为 undefined
if (item === undefined) return;
//创建 mark 元素
var mark = document.createElement('div');
//为 mark 创建下标属性
mark.dataset.index = i;
mark.classList.add('mark');
//创建
var span1 = document.createElement('span');
//设置第一个 span 的文本
span1.innerHTML = item;
var span2 = document.createElement('span');
//设置第二个 span 的文本 X
span2.innerHTML = 'X';
//为 span2 元素绑定单击事件
span2.onclick = function () {
//删除当前的 mark 元素
// this.parentNode.removeChild(this);
this.parentNode.remove();
//
//获取当前标签对应的下标
var i = this.parentNode.dataset.index;
//删除数组中的元素的值
arr[i] = undefined;
//获取 dl
var dls = document.querySelectorAll('#root #content .container .goods-intro-section .right .choose-section dl');
//清除同辈元素的 active
dls[i].querySelectorAll('dd').forEach(function (item) {
item.classList.remove('active');
})
//删除完成之后 要将对应行的选中状态
//querySelectorAll返回一个静态的NodeList(深克隆),静态:是指选出的所有元素的数组,不会随着文档操作而改变
dls[i].querySelectorAll('dd')[0].classList.add('active');
}
//组装
mark.appendChild(span1);
mark.appendChild(span2);
//将 mark 元素插入到 choosed-section
//appendChild插入节点
choosedSection.appendChild(mark);
});
});
});
}
handleGoodsAttrTag();