当前位置: 首页 > news >正文

商品列表及商品详情展示

前言

本文将展示一段结合 HTML、CSS 和 JavaScript 的代码,实现了一个简单的商品展示页面及商品详情,涵盖数据获取、渲染、搜索及排序等功能。

效果展示

点击不同的商品会展示对应的商品详情。

 代码部分

代码总体实现
<!DOCTYPE html>
<html><head><meta charset="utf-8"><meta name="viewport"content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /><title></title><style>* {margin: 0;padding: 0;}#title {width: 100%;height: 50px;background-color: white;font-weight: 800;font-size: 19px;display: flex;justify-content: center;align-items: center;position: fixed;z-index: 1;margin-top: -10px;}#searchContent {width: 95%;margin-left: 2%;height: 4vh;position: relative;}#searchContent input {margin-top: 50px;width: 100%;height: 100%;border-radius: 50px;/* border-style: none; *//* background-color: lightgray; */display: inline-block;}input::placeholder {color: gray;font-size: 16px;text-align: center;}#searchContent img {margin-top: 50px;position: absolute;width: 9%;height: 100%;top: 4px;right: 10px;}#productContent {/* margin-top: 50px; */column-count: 2;column-gap: 10px;padding: 10px;}#product {break-inside: avoid;width: 100%;margin-bottom: 10px;/* background-color: ; */box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);/* padding: 10px; */}#product img {width: 100%;height: auto;}#product div {/* width: 96%; */text-align: center;/* height: 2vh; */margin-left: 2%;margin-top: 0;font-size: 10px;}#name {font-size: 19px;font-weight: 700;}#info {font-weight: 400;/* height: 30px; *//* background-color: blue; */font-size: 15px;width: 100%;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 2;overflow: hidden;text-overflow: ellipsis;}#product p {margin-left: 2%;margin-bottom: 0;/* color: #666; */color: red;font-size: 20px;}#titles {background-color: orangered;border-radius: 10px;color: yellow;width: 45px;padding: 3px;font-weight: 600;}#orderBut {margin-top: 60px;padding: 5px;}#noResult {text-align: center;font-size: 18px;color: gray;margin-top: 50px;}</style></head><body><div id="title">主页</div><!-- 搜索框部分 --><div id="searchContent"><input id="searchInput" style="text-align: center;font-size: 16px;" type="text" placeholder="搜索框" /><img src="./img/sousuo.png" /></div><div><button id="orderBut">排序</button></div><!-- 内容区域 --><div id="productContent"><!-- 商品部分 --><div id="product"><!-- 商品图片 --><div id="imgBox"><img src="" /></div><!-- 商品名字 --><div id="name"></div><!-- 商品详情 --><div>统一</div><!-- 简介 --><div>方便面</div><!-- 价钱 --><p>¥16.44</p></div></div><script>let data;let productContent = document.getElementById('productContent');let searchInput = document.getElementById('searchInput'); // 获取搜索框输入元素let originalData;// 发起请求获取数据的代码部分保持不变let xhr = new XMLHttpRequest();xhr.open('get', './js/productAbout.json', true);xhr.send();xhr.onreadystatechange = function() {if (xhr.readyState == 4 && xhr.status == 200) {let text = xhr.responseText;data = JSON.parse(text);// 把data数据赋值给originalData,用于输入框清空后显示原始的数据originalData = data;//渲染originalDatarender(originalData);}};function render(data) {let str = "";for (let i in data) {str += `<div id="product"><div id="imgBox" onclick="jumpPage(${i})"><img  src="${data[i].img[0]}" /></div><div id="name">${data[i].name}</div><h3 id="info">${data[i].info}</h3><div id="titles">${data[i].about}</div><p>${data[i].prise}</p></div>`}document.getElementById('productContent').innerHTML = str};// 详情页跳转函数保持不变function jumpPage(index) {localStorage.setItem('details', JSON.stringify(data[index]))window.location.href = './shopAbout.html';}//==========================模糊搜索============================// 先获取输入框元素let input = document.getElementById('searchInput');//给输入框上事件监听 input.addEventListener('input', function() {//用于下面往里面拼东西let str_content = '';//判断输入框里的值let searchValue = input.value.trim()//如果值为空if (searchValue === "") {// 把data数据赋值给originalDataoriginalData = data;} else {//声明originalData为空数组originalData = [];//值不为空的话(说明我往输入框里输入东西了),就循环data数据for (let i in data) {//检查data数组中(namez值info值prise值)是否包括搜索框(searchValue)输入的值if (data[i].name.includes(searchValue) || data[i].info.includes(searchValue) || data[i].prise.includes(searchValue)) {//把data数据的下标i的数据插入到originalData中originalData.push(data[i]);}}}//如果搜索不到if (originalData.length === 0) {// 如果经过筛选后originalData数组为空,说明没有找到符合搜索条件的数据str_content = '<div id="noResult">无符合条件的内容</div>';//否则就是搜索到了} else {// 如果找到了符合条件的数据,就按照原来的逻辑拼接字符串(上面的)for (let i in originalData) {str_content += `<div id="product"><div id="imgBox" onclick="jumpPage(${i})"><img  src="${originalData[i].img[0]}" /></div><div id="name">${originalData[i].name}</div><h3 id="info">${originalData[i].info}</h3><div id="titles">${originalData[i].about}</div><p>${originalData[i].prise}</p></div>`;}}// 获取商品展示区域的元素,假设其id为productContentlet productContent = document.getElementById('productContent');productContent.innerHTML = str_content;});// 	//最后渲染上去// 	render(originalData);// })//========================排序==================//获取按钮let orderBut = document.getElementById('orderBut');//初始化次数为零let num = 0;//给按钮上点击事件orderBut.onclick = function() {//次数+1num++;//如果次数等于1 的时候if (num == 1) {//用sort排序originalData = originalData.sort(function(a, b) {//反值a-b的价钱//如果 a.prise - b.prise 的计算结果小于 0,//即 a 的 prise 值小于 b 的 prise 属性值,此时 a 会排在 b 的前面。return a.prise - b.prise;});console.log(data);//次数等于2的时候//当 b.prise - a.prise 的值小于 0 时,//就是 b 的 prise 属性值小于 a 的 prise 属性值,此时 b 元素会排在 a 元素前面} else if (num == 2) {originalData = originalData.sort(function(a, b) {return b.prise - a.prise;});} else if (num == 3) {num = 0;//展开语法(...),将 data 数组中的元素逐个复制到 originalData 数组中,相当于重置originalData = [...data]}//渲染render(originalData);};</script></body>
</html>

代码详解

HTML
<div id="title">主页</div><!-- 搜索框部分 --><div id="searchContent"><input id="searchInput" style="text-align: center;font-size: 16px;" type="text" placeholder="搜索框" /><img src="./img/sousuo.png" /></div><div><button id="orderBut">排序</button></div><!-- 内容区域 --><div id="productContent"><!-- 商品部分 --><div id="product"><!-- 商品图片 --><div id="imgBox"><img src="" /></div><!-- 商品名字 --><div id="name"></div><!-- 商品详情 --><div>统一</div><!-- 简介 --><div>方便面</div><!-- 价钱 --><p>¥16.44</p></div></div>
CSS
* {margin: 0;padding: 0;}#title {width: 100%;height: 50px;background-color: white;font-weight: 800;font-size: 19px;display: flex;justify-content: center;align-items: center;position: fixed;z-index: 1;margin-top: -10px;}#searchContent {width: 95%;margin-left: 2%;height: 4vh;position: relative;}#searchContent input {margin-top: 50px;width: 100%;height: 100%;border-radius: 50px;/* border-style: none; *//* background-color: lightgray; */display: inline-block;}input::placeholder {color: gray;font-size: 16px;text-align: center;}#searchContent img {margin-top: 50px;position: absolute;width: 9%;height: 100%;top: 4px;right: 10px;}#productContent {/* margin-top: 50px; */column-count: 2;column-gap: 10px;padding: 10px;}#product {break-inside: avoid;width: 100%;margin-bottom: 10px;/* background-color: ; */box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);/* padding: 10px; */}#product img {width: 100%;height: auto;}#product div {/* width: 96%; */text-align: center;/* height: 2vh; */margin-left: 2%;margin-top: 0;font-size: 10px;}#name {font-size: 19px;font-weight: 700;}#info {font-weight: 400;/* height: 30px; *//* background-color: blue; */font-size: 15px;width: 100%;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 2;overflow: hidden;text-overflow: ellipsis;}#product p {margin-left: 2%;margin-bottom: 0;/* color: #666; */color: red;font-size: 20px;}#titles {background-color: orangered;border-radius: 10px;color: yellow;width: 45px;padding: 3px;font-weight: 600;}#orderBut {margin-top: 60px;padding: 5px;}#noResult {text-align: center;font-size: 18px;color: gray;margin-top: 50px;}
JS
总览
let data;let productContent = document.getElementById('productContent');let searchInput = document.getElementById('searchInput'); // 获取搜索框输入元素let originalData;// 发起请求获取数据的代码部分保持不变let xhr = new XMLHttpRequest();xhr.open('get', './js/productAbout.json', true);xhr.send();xhr.onreadystatechange = function() {if (xhr.readyState == 4 && xhr.status == 200) {let text = xhr.responseText;data = JSON.parse(text);// 把data数据赋值给originalData,用于输入框清空后显示原始的数据originalData = data;//渲染originalDatarender(originalData);}};function render(data) {let str = "";for (let i in data) {str += `<div id="product"><div id="imgBox" onclick="jumpPage(${i})"><img  src="${data[i].img[0]}" /></div><div id="name">${data[i].name}</div><h3 id="info">${data[i].info}</h3><div id="titles">${data[i].about}</div><p>${data[i].prise}</p></div>`}document.getElementById('productContent').innerHTML = str};// 详情页跳转函数保持不变function jumpPage(index) {localStorage.setItem('details', JSON.stringify(data[index]))window.location.href = './shopAbout.html';}//==========================模糊搜索============================// 先获取输入框元素let input = document.getElementById('searchInput');//给输入框上事件监听 input.addEventListener('input', function() {//用于下面往里面拼东西let str_content = '';//判断输入框里的值let searchValue = input.value.trim()//如果值为空if (searchValue === "") {// 把data数据赋值给originalDataoriginalData = data;} else {//声明originalData为空数组originalData = [];//值不为空的话(说明我往输入框里输入东西了),就循环data数据for (let i in data) {//检查data数组中(namez值info值prise值)是否包括搜索框(searchValue)输入的值if (data[i].name.includes(searchValue) || data[i].info.includes(searchValue) || data[i].prise.includes(searchValue)) {//把data数据的下标i的数据插入到originalData中originalData.push(data[i]);}}}//如果搜索不到if (originalData.length === 0) {// 如果经过筛选后originalData数组为空,说明没有找到符合搜索条件的数据str_content = '<div id="noResult">无符合条件的内容</div>';//否则就是搜索到了} else {// 如果找到了符合条件的数据,就按照原来的逻辑拼接字符串(上面的)for (let i in originalData) {str_content += `<div id="product"><div id="imgBox" onclick="jumpPage(${i})"><img  src="${originalData[i].img[0]}" /></div><div id="name">${originalData[i].name}</div><h3 id="info">${originalData[i].info}</h3><div id="titles">${originalData[i].about}</div><p>${originalData[i].prise}</p></div>`;}}// 获取商品展示区域的元素,假设其id为productContentlet productContent = document.getElementById('productContent');productContent.innerHTML = str_content;});// 	//最后渲染上去// 	render(originalData);// })//========================排序==================//获取按钮let orderBut = document.getElementById('orderBut');//初始化次数为零let num = 0;//给按钮上点击事件orderBut.onclick = function() {//次数+1num++;//如果次数等于1 的时候if (num == 1) {//用sort排序originalData = originalData.sort(function(a, b) {//反值a-b的价钱//如果 a.prise - b.prise 的计算结果小于 0,//即 a 的 prise 值小于 b 的 prise 属性值,此时 a 会排在 b 的前面。return a.prise - b.prise;});console.log(data);//次数等于2的时候//当 b.prise - a.prise 的值小于 0 时,//就是 b 的 prise 属性值小于 a 的 prise 属性值,此时 b 元素会排在 a 元素前面} else if (num == 2) {originalData = originalData.sort(function(a, b) {return b.prise - a.prise;});} else if (num == 3) {num = 0;//展开语法(...),将 data 数组中的元素逐个复制到 originalData 数组中,相当于重置originalData = [...data]}//渲染render(originalData);};
JS详解
  • 变量声明
    • data:用于存储从 ./js/productAbout.json 文件获取并解析后的商品数据。
    • productContent:获取页面上商品展示区域的,后续用于更新商品展示内容。
    • searchInput:获取搜索框的 DOM 元素,监听输入事件。
    • originalData:用于存储原始商品数据,在搜索和排序操作中作为基础数据使用。
let data;
let productContent = document.getElementById('productContent');
let searchInput = document.getElementById('searchInput'); 
let originalData;
  • 数据请求
    • 使用 XMLHttpRequest 对象发送 GET 请求到 ./js/productAbout.json 文件。
    • 当请求成功(readyState 为 4 且 status 为 200)时,将响应文本解析为 JSON 格式并赋值给 data
    • 将 data 赋值给 originalData,并调用 render 函数渲染原始数据。
let xhr = new XMLHttpRequest();
xhr.open('get', './js/productAbout.json', true);
xhr.send();
xhr.onreadystatechange = function() {if (xhr.readyState == 4 && xhr.status == 200) {let text = xhr.responseText;data = JSON.parse(text);originalData = data;render(originalData);}
};
  • 数据渲染函数:
    • 该函数用于将商品数据渲染到页面上。
    • 初始化一个空字符串 str,通过 for...in 循环遍历 data 数组。
    • 为每个商品拼接 HTML 字符串,包括商品图片、名称、详情、简介和价格等信息,并为商品图片添加点击事件 jumpPage(${i}),其中 i 为商品在数组中的索引。
    • 最后将拼接好的 HTML 字符串设置为 productContent 的 innerHTML,从而在页面上显示商品。
function render(data) {let str = "";for (let i in data) {str += `<div id="product"><div id="imgBox" onclick="jumpPage(${i})"><img  src="${data[i].img[0]}" /></div><div id="name">${data[i].name}</div><h3 id="info">${data[i].info}</h3><div id="titles">${data[i].about}</div><p>${data[i].prise}</p></div>`}document.getElementById('productContent').innerHTML = str
};
  • 详情页跳转函数:
    • 当用户点击商品图片时,该函数被调用。
    • 它将当前点击商品的数据(data[index])以 JSON 字符串的形式存储在本地存储中,键为 details
    • 然后将页面导航到 ./shopAbout.html,通常这个页面会从本地存储中读取商品详情数据并展示。
function jumpPage(index) {localStorage.setItem('details', JSON.stringify(data[index]))window.location.href = './shopAbout.html';
}
  • 模糊搜索功能:
    • 获取搜索框元素并添加 input 事件监听器,当用户在搜索框中输入内容时触发。
    • 初始化一个空字符串 str_content 用于存储搜索结果的 HTML 内容,获取并修剪搜索框的值 searchValue
    • 如果搜索框为空,将 originalData 重置为原始的 data。否则,清空 originalData 数组,遍历 data 数组,检查商品的名称、详情或价格是否包含搜索值,若包含则将该商品添加到 originalData 中。
    • 如果 originalData 数组为空,说明没有找到符合条件的商品,设置 str_content 为提示信息。否则,遍历 originalData 数组,拼接符合条件的商品的 HTML 内容。
    • 最后更新 productContent 的 innerHTML 以显示搜索结果。
let input = document.getElementById('searchInput');
input.addEventListener('input', function() {let str_content = '';let searchValue = input.value.trim()if (searchValue === "") {originalData = data;} else {originalData = [];for (let i in data) {if (data[i].name.includes(searchValue) || data[i].info.includes(searchValue) || data[i].prise.includes(searchValue)) {originalData.push(data[i]);}}}if (originalData.length === 0) {str_content = '<div id="noResult">无符合条件的内容</div>';} else {for (let i in originalData) {str_content += `<div id="product"><div id="imgBox" onclick="jumpPage(${i})"><img  src="${originalData[i].img[0]}" /></div><div id="name">${originalData[i].name}</div><h3 id="info">${originalData[i].info}</h3><div id="titles">${originalData[i].about}</div><p>${originalData[i].prise}</p></div>`;}}let productContent = document.getElementById('productContent');productContent.innerHTML = str_content;
});
  • 排序功能
    • 获取 “排序” 按钮元素,并初始化一个计数器 num 为 0。
    • 为按钮添加点击事件,每次点击 num 自增 1。
    • 当 num 为 1 时,使用 sort 方法对 originalData 进行升序排序,比较商品价格 prise
    • 当 num 为 2 时,进行降序排序。
    • 当 num 为 3 时,将 num 重置为 0,并通过展开运算符将 data 数组的内容复制给 originalData,恢复原始顺序。
    • 最后调用 render 函数,根据排序后的 originalData 重新渲染商品展示区域。
let orderBut = document.getElementById('orderBut');
let num = 0;
orderBut.onclick = function() {num++;if (num == 1) {originalData = originalData.sort(function(a, b) {return a.prise - b.prise;});} else if (num == 2) {originalData = originalData.sort(function(a, b) {return b.prise - a.prise;});} else if (num == 3) {num = 0;originalData = [...data]}render(originalData);
};

商品详情部分

代码部分

代码总体实现
<!DOCTYPE html>
<html><head><meta charset="utf-8"><meta name="viewport"content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /><title></title><style>* {margin: 0;padding: 0;}.return {width: 100%;/* height: 45px; */background-color: white;font-weight: 800;font-size: 19px;display: flex;/* justify-content: space-between; */align-items: center;position: fixed;z-index: 1;/* margin-top: -10px; */}.return p {/* margin-left: auto; *//* position: absolute; */margin-left: 36%;}.return img {width: 7%;}/* 定义轮播图底板大小 */.banner {width: 100%;/* height: 700px; *//* margin-top: 6vh; *//* margin: auto; *//* border: 5px solid blue; *//* 将多余部分隐藏 */overflow: hidden;font-size: 0;}/* 规定容器里图片规格 */.box img {width: 25%;height: 40vh;/* float: left; *//* display: inline-block; */}/* 包着图片的容器大小 */.box {width: 400%;margin-top: 26px;/* height: 700px; *//* 动画效果运用到每个图片身上 *//* ---名字--持续时间--动画播放次数=无限 */animation: donghua 13s infinite;}/* 当在 @keyframes 创建动画,把它绑定到一个选择器,否则动画不会有任何效果。 */@keyframes donghua {/* 0% 是动画的开始,100% 是动画的完成。 */0% {margin-left: 0;}33.33% {/* 向左移负的1885px。因为上面规定的一张图片的大小是1885px */margin-left: -100%;}66.66% {margin-left: -200%;}100% {margin-left: -300%;}}.priseContent {display: flex;justify-content: space-between;width: 100%;/* height: 60px; */background-color: #ff1e21;}.deja {/* display: inline-block; */}.price {margin-left: 10px;}.priceWord {/* display: inline-block; */background-color: #eb0003;padding: 6px;font-size: 17px;color: white;}.nowPrice {font-size: 25px;color: white;/* margin-left: 10px; */}.infoProduct {width: 96%;margin-left: 2%;margin-top: 5px;}#freeBuy {color: darkgray;}#infoProduct {color: #eb0003;font-weight: 400;}.infoProduct p {color: #eb0003;font-size: 20px;font-weight: 700;}.infoImg img {width: 100%;}.infoImg {/* height: 150vh; */width: 96%;margin-left: 2%;}.line {width: 100%;height: 5px;background-color: lightgray;margin-top: 5px;}.bottonContent {width: 100%;height: 70px;background-color: cadetblue;}/* /底部板子 */.foot-center {width: 100%;display: flex;position: fixed;bottom: 0;z-index: 1;justify-content: space-around;background-color: white;margin-top: 15%;height: 50px;}/* 小块 */.chef {display: flex;flex-direction: column;text-align: center;width: 48px;height: 100%;font-size: 13px;font-weight: 100;margin-bottom: 5px;margin-top: 5px;}.foot-center img {width: 18px;height: 18px;}.kong {width: auto;height: 100px;}.buy {display: flex;align-items: center;justify-content: center;background-color: red;border-radius: 50px;padding-left: 70px;padding-right: 70px;color: white;margin-bottom: 5px;margin-top: 5px;/* margin-left: 50px; */}#wide {height: 10vh;}</style></head><body><!-- 大底板 --><div class="aboutContent"><!-- 返回按键 --><div class="return"><img src="./img/jiantou.png" /><p>详情页</p></div><!-- 轮播图 --><div class="banner"><div class="box"><!-- 图1 --><img src="./img/iwtch.jpg" /><!-- 图2 --><img src="./img/watch3.jpg" /><!-- 图3 --><img src="./img/watch2.jpg" /><!-- 重复图1 --><img src="./img/iwtch.jpg" /></div></div><!-- 价格横条 --><!-- 详情 --><div class="infoProduct"><!-- 名字 --><div id="infoProduct"></div><!-- 详情 --><h3></h3><!-- 包邮 --><div></div><!-- 价格 --><p></p></div><!-- 分割线 --><div class="line"></div><!-- 图片详情 --><div class="infoImg"></div><div id="wide"></div><!-- 底部导航 --><div class="foot"><!-- 底部板子 --><div class="foot-center"><!-- 主页 --><div class="chef"><div class="chef-logo"><img src="./img/home.png" alt="" /></div>主页</div><!-- 分享 --><div class="chef"><div class="chef-logo"><img src="./img/about.png" alt="" /></div>分享</div><!-- 我的 --><div class="chef"><div class="chef-logo"><img src="./img/my.png" alt="" /></div>我的</div><!-- 购买 --><div class="buy"><div class="buy-logo"></div>立即购买</div></div></div></div><script>// 回主页的点击事件let returnHome = document.getElementsByClassName('chef-logo')[0];returnHome.onclick = function() {window.location.href = './shop.html';}// 回主页的点击事件let returnLeft = document.getElementsByClassName('return')[0];returnLeft.onclick = function() {window.location.href = './shop.html';}//通过键名details在详情页获取在主页存的数据//它的作用是将一个 JSON 格式的字符串解析为 JavaScript 对象let data = JSON.parse(localStorage.getItem('details'));console.log(data);//先声明一个空字符串let str = "";//拼接字符串(根据json中的数据拼)//如果想给他改样式 需要在拼接字符串里命名 然后在用名字改样式str += `<div id="aboutContent"><div id="infoProduct">${data.name}</div><h3>${data.info}</h3><div id="freeBuy">${data.about}</div><p>${data.prise}</p>`//获取商品的详情部分,并把拼好的str写进去document.getElementsByClassName('infoProduct')[0].innerHTML = str;//渲染函数(为了渲染图片的)function render() {//=========================轮播图的图片拼接=========================//声明一个空的字符串let imgStr = ""//使用for循环去遍历img数组(json里的)for (let i = 0; i < data.img.length; i++) {// 每次循环都把当前的img下标往imgstr字符串里面拼imgStr += `<img src = "${data.img[i]}"/>	`}// 首张图片在展示时有重复显示的效果imgStr += `<img src = "${data.img[0]}"/>`//获取轮播图的box容器 并把拼好的字符串(imgStr)写进去document.getElementsByClassName('box')[0].innerHTML = imgStr;//=========================详情的图片拼接=========================//声明一个空的字符串let infoImgStr = ""//使用for循环去遍历img数组(json里的)for (let j = 0; j < data.infoImg.length; j++) {// 每次循环都把当前的img下标往infoImgStr字符串里面拼infoImgStr += `<img src = "${data.infoImg[j]}"/>`}//获取详情照片的infoImg容器 并把拼好的字符串(infoImgStr)写进去document.getElementsByClassName('infoImg')[0].innerHTML = infoImgStr;};render();</script></body>
</html>

代码详解

HTML
<!-- 大底板 --><div class="aboutContent"><!-- 返回按键 --><div class="return"><img src="./img/jiantou.png" /><p>详情页</p></div><!-- 轮播图 --><div class="banner"><div class="box"><!-- 图1 --><img src="./img/iwtch.jpg" /><!-- 图2 --><img src="./img/watch3.jpg" /><!-- 图3 --><img src="./img/watch2.jpg" /><!-- 重复图1 --><img src="./img/iwtch.jpg" /></div></div><!-- 价格横条 --><!-- 详情 --><div class="infoProduct"><!-- 名字 --><div id="infoProduct"></div><!-- 详情 --><h3></h3><!-- 包邮 --><div></div><!-- 价格 --><p></p></div><!-- 分割线 --><div class="line"></div><!-- 图片详情 --><div class="infoImg"></div><div id="wide"></div><!-- 底部导航 --><div class="foot"><!-- 底部板子 --><div class="foot-center"><!-- 主页 --><div class="chef"><div class="chef-logo"><img src="./img/home.png" alt="" /></div>主页</div><!-- 分享 --><div class="chef"><div class="chef-logo"><img src="./img/about.png" alt="" /></div>分享</div><!-- 我的 --><div class="chef"><div class="chef-logo"><img src="./img/my.png" alt="" /></div>我的</div><!-- 购买 --><div class="buy"><div class="buy-logo"></div>立即购买</div></div></div></div>
CSS
* {margin: 0;padding: 0;}.return {width: 100%;/* height: 45px; */background-color: white;font-weight: 800;font-size: 19px;display: flex;/* justify-content: space-between; */align-items: center;position: fixed;z-index: 1;/* margin-top: -10px; */}.return p {/* margin-left: auto; *//* position: absolute; */margin-left: 36%;}.return img {width: 7%;}/* 定义轮播图底板大小 */.banner {width: 100%;/* height: 700px; *//* margin-top: 6vh; *//* margin: auto; *//* border: 5px solid blue; *//* 将多余部分隐藏 */overflow: hidden;font-size: 0;}/* 规定容器里图片规格 */.box img {width: 25%;height: 40vh;/* float: left; *//* display: inline-block; */}/* 包着图片的容器大小 */.box {width: 400%;margin-top: 26px;/* height: 700px; *//* 动画效果运用到每个图片身上 *//* ---名字--持续时间--动画播放次数=无限 */animation: donghua 13s infinite;}/* 当在 @keyframes 创建动画,把它绑定到一个选择器,否则动画不会有任何效果。 */@keyframes donghua {/* 0% 是动画的开始,100% 是动画的完成。 */0% {margin-left: 0;}33.33% {/* 向左移负的1885px。因为上面规定的一张图片的大小是1885px */margin-left: -100%;}66.66% {margin-left: -200%;}100% {margin-left: -300%;}}.priseContent {display: flex;justify-content: space-between;width: 100%;/* height: 60px; */background-color: #ff1e21;}.deja {/* display: inline-block; */}.price {margin-left: 10px;}.priceWord {/* display: inline-block; */background-color: #eb0003;padding: 6px;font-size: 17px;color: white;}.nowPrice {font-size: 25px;color: white;/* margin-left: 10px; */}.infoProduct {width: 96%;margin-left: 2%;margin-top: 5px;}#freeBuy {color: darkgray;}#infoProduct {color: #eb0003;font-weight: 400;}.infoProduct p {color: #eb0003;font-size: 20px;font-weight: 700;}.infoImg img {width: 100%;}.infoImg {/* height: 150vh; */width: 96%;margin-left: 2%;}.line {width: 100%;height: 5px;background-color: lightgray;margin-top: 5px;}.bottonContent {width: 100%;height: 70px;background-color: cadetblue;}/* /底部板子 */.foot-center {width: 100%;display: flex;position: fixed;bottom: 0;z-index: 1;justify-content: space-around;background-color: white;margin-top: 15%;height: 50px;}/* 小块 */.chef {display: flex;flex-direction: column;text-align: center;width: 48px;height: 100%;font-size: 13px;font-weight: 100;margin-bottom: 5px;margin-top: 5px;}.foot-center img {width: 18px;height: 18px;}.kong {width: auto;height: 100px;}.buy {display: flex;align-items: center;justify-content: center;background-color: red;border-radius: 50px;padding-left: 70px;padding-right: 70px;color: white;margin-bottom: 5px;margin-top: 5px;/* margin-left: 50px; */}#wide {height: 10vh;}</style></head><body><!DOCTYPE html>
<html><head><meta charset="utf-8"><meta name="viewport"content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /><title></title><style>* {margin: 0;padding: 0;}.return {width: 100%;/* height: 45px; */background-color: white;font-weight: 800;font-size: 19px;display: flex;/* justify-content: space-between; */align-items: center;position: fixed;z-index: 1;/* margin-top: -10px; */}.return p {/* margin-left: auto; *//* position: absolute; */margin-left: 36%;}.return img {width: 7%;}/* 定义轮播图底板大小 */.banner {width: 100%;/* height: 700px; *//* margin-top: 6vh; *//* margin: auto; *//* border: 5px solid blue; *//* 将多余部分隐藏 */overflow: hidden;font-size: 0;}/* 规定容器里图片规格 */.box img {width: 25%;height: 40vh;/* float: left; *//* display: inline-block; */}/* 包着图片的容器大小 */.box {width: 400%;margin-top: 26px;/* height: 700px; *//* 动画效果运用到每个图片身上 *//* ---名字--持续时间--动画播放次数=无限 */animation: donghua 13s infinite;}/* 当在 @keyframes 创建动画,把它绑定到一个选择器,否则动画不会有任何效果。 */@keyframes donghua {/* 0% 是动画的开始,100% 是动画的完成。 */0% {margin-left: 0;}33.33% {/* 向左移负的1885px。因为上面规定的一张图片的大小是1885px */margin-left: -100%;}66.66% {margin-left: -200%;}100% {margin-left: -300%;}}.priseContent {display: flex;justify-content: space-between;width: 100%;/* height: 60px; */background-color: #ff1e21;}.deja {/* display: inline-block; */}.price {margin-left: 10px;}.priceWord {/* display: inline-block; */background-color: #eb0003;padding: 6px;font-size: 17px;color: white;}.nowPrice {font-size: 25px;color: white;/* margin-left: 10px; */}.infoProduct {width: 96%;margin-left: 2%;margin-top: 5px;}#freeBuy {color: darkgray;}#infoProduct {color: #eb0003;font-weight: 400;}.infoProduct p {color: #eb0003;font-size: 20px;font-weight: 700;}.infoImg img {width: 100%;}.infoImg {/* height: 150vh; */width: 96%;margin-left: 2%;}.line {width: 100%;height: 5px;background-color: lightgray;margin-top: 5px;}.bottonContent {width: 100%;height: 70px;background-color: cadetblue;}/* /底部板子 */.foot-center {width: 100%;display: flex;position: fixed;bottom: 0;z-index: 1;justify-content: space-around;background-color: white;margin-top: 15%;height: 50px;}/* 小块 */.chef {display: flex;flex-direction: column;text-align: center;width: 48px;height: 100%;font-size: 13px;font-weight: 100;margin-bottom: 5px;margin-top: 5px;}.foot-center img {width: 18px;height: 18px;}.kong {width: auto;height: 100px;}.buy {display: flex;align-items: center;justify-content: center;background-color: red;border-radius: 50px;padding-left: 70px;padding-right: 70px;color: white;margin-bottom: 5px;margin-top: 5px;/* margin-left: 50px; */}#wide {height: 10vh;}
JS
js详解
  • 返回主页事件
    • 获取元素
      • document.getElementsByClassName('chef-logo')[0] 选择了页面上第一个具有 chef - logo 类名的元素,该元素通常用于代表主页图标。
      • document.getElementsByClassName('return')[0] 选择了页面上第一个具有 return 类名的元素,这个元素可能是返回按钮。
    • 绑定点击事件
      • 对于 returnHome 元素,当点击时,window.location.href = './shop.html'; 会将页面导航到 ./shop.html,实现返回主页的功能。
      • 同样,对于 returnLeft 元素,点击时也会导航到 ./shop.html。这意味着无论是点击主页图标还是返回按钮,都能回到 shop.html 页面。
// 回主页的点击事件
let returnHome = document.getElementsByClassName('chef-logo')[0];
returnHome.onclick = function() {window.location.href = './shop.html';
}
// 回主页的点击事件
let returnLeft = document.getElementsByClassName('return')[0];
returnLeft.onclick = function() {window.location.href = './shop.html';
}
  • 数据渲染部分
    • 获取本地存储数据
      • localStorage.getItem('details') 从本地存储中获取键为 details 的数据,该数据通常是在主页存储的商品详情信息,以 JSON 字符串形式存储。
      • JSON.parse(localStorage.getItem('details')) 将获取到的 JSON 字符串解析为 JavaScript 对象,并赋值给 data 变量。然后通过 console.log(data) 将解析后的数据打印到控制台,方便调试查看。
    • 拼接并渲染商品详情
      • 初始化一个空字符串 str,用于拼接商品详情的 HTML 内容。
      • 根据 data 对象中的属性,将商品的名称(data.name)、详情(data.info)、包邮信息(data.about)和价格(data.prise)拼接成 HTML 片段。
      • document.getElementsByClassName('infoProduct')[0].innerHTML = str; 获取页面上第一个具有 infoProduct 类名的元素,并将拼接好的 HTML 内容设置为该元素的 innerHTML,从而在页面上渲染出商品详情。
//通过键名details在详情页获取在主页存的数据
//它的作用是将一个 JSON 格式的字符串解析为 JavaScript 对象
let data = JSON.parse(localStorage.getItem('details'));
console.log(data);//先声明一个空字符串
let str = "";
//拼接字符串(根据json中的数据拼)
//如果想给他改样式 需要在拼接字符串里命名 然后在用名字改样式
str += `<div id="aboutContent"><div id="infoProduct">${data.name}</div><h3>${data.info}</h3><div id="freeBuy">${data.about}</div><p>${data.prise}</p>
`
//获取商品的详情部分,并把拼好的str写进去
document.getElementsByClassName('infoProduct')[0].innerHTML = str;
  • 轮播图图片渲染
    • 定义 render 函数用于渲染图片。在函数内部,首先初始化一个空字符串 imgStr,用于拼接轮播图的图片 HTML 代码。
    • 通过 for 循环遍历 data.img 数组,data.img 数组应该包含了轮播图所需的图片路径。每次循环将当前图片路径拼接到 imgStr 中。
    • 为了实现轮播图首尾相连的循环效果,在循环结束后,又将第一张图片路径再次拼接到 imgStr 中。
    • document.getElementsByClassName('box')[0].innerHTML = imgStr; 获取页面上第一个具有 box 类名的元素(轮播图容器),并将拼接好的图片 HTML 代码设置为该容器的 innerHTML,从而实现轮播图图片的渲染。
  • 详情图片渲染
    • 同样初始化一个空字符串 infoImgStr,用于拼接商品详情图片的 HTML 代码。
    • 使用 for 循环遍历 data.infoImg 数组,data.infoImg 数组包含商品详情图片的路径。每次循环将当前图片路径拼接到 infoImgStr 中。
    • document.getElementsByClassName('infoImg')[0].innerHTML = infoImgStr; 获取页面上第一个具有 infoImg 类名的元素(商品详情图片容器),并将拼接好的图片 HTML 代码设置为该容器的 innerHTML,完成商品详情图片的渲染。
  • 函数调用:最后调用 render() 函数,执行上述图片渲染操作。
//渲染函数(为了渲染图片的)
function render() {//=========================轮播图的图片拼接=========================//声明一个空的字符串let imgStr = ""//使用for循环去遍历img数组(json里的)for (let i = 0; i < data.img.length; i++) {// 每次循环都把当前的img下标往imgstr字符串里面拼imgStr += `<img src = "${data.img[i]}"/>	`}// 首张图片在展示时有重复显示的效果imgStr += `<img src = "${data.img[0]}"/>`//获取轮播图的box容器 并把拼好的字符串(imgStr)写进去document.getElementsByClassName('box')[0].innerHTML = imgStr;//=========================详情的图片拼接=========================//声明一个空的字符串let infoImgStr = ""//使用for循环去遍历img数组(json里的)for (let j = 0; j < data.infoImg.length; j++) {// 每次循环都把当前的img下标往infoImgStr字符串里面拼infoImgStr += `<img src = "${data.infoImg[j]}"/>`}//获取详情照片的infoImg容器 并把拼好的字符串(infoImgStr)写进去document.getElementsByClassName('infoImg')[0].innerHTML = infoImgStr;
};
render();

相关文章:

商品列表及商品详情展示

前言 本文将展示一段结合 HTML、CSS 和 JavaScript 的代码&#xff0c;实现了一个简单的商品展示页面及商品详情&#xff0c;涵盖数据获取、渲染、搜索及排序等功能。 效果展示 点击不同的商品会展示对应的商品详情。 代码部分 代码总体实现 <!DOCTYPE html> <htm…...

使用where子句筛选记录

默认情况下,SearchCursor将返回一个表或要素类的所有行.然而在很多情况下,常常需要某些条件来限制返回行数. 操作方法: 1.打开IDLE,加载先前编写的SearchCursor.py脚本 2.添加where子句,更新SearchCursor()函数,查找记录中有<>文本的<>字段 with arcpy.da.Searc…...

SQL Server查询计划操作符(7.3)——查询计划相关操作符(5)

7.3. 查询计划相关操作符 38)Flow Distinct:该操作符扫描其输入并对其去重。该操作符从其输入得到每行数据时即将其返回(除非其为重复数据行,此时,该数据行会被抛弃),而Distinct操作符在产生任何输出前将消费所有输入。该操作符为逻辑操作符。该操作符具体如图7.2-38中…...

C++中常用的十大排序方法之4——希尔排序

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C中常用的排序方法之4——希尔排序的相…...

扶摇计划--从失业的寒冬,慢慢的走出来

作为资深 Java 开发工程师,你有丰富的技术经验和解决问题的能力,即使暂时失业,也可以通过多种方式赚取收入。以下是结合你的技能和市场需求的具体建议,分阶段规划实现: 第一阶段:快速变现(短期,1-3个月) 自由职业与远程工作 平台接单:在 Upwork、Freelancer 或国内平…...

unity学习24:场景scene相关生成,加载,卸载,加载进度,异步加载场景等

目录 1 场景数量 SceneManager.sceneCount 2 直接代码生成新场景 SceneManager.CreateScene 3 场景的加载 3.1 用代码加载场景&#xff0c;仍然build setting里先加入配置 3.2 卸载场景 SceneManager.UnloadSceneAsync(); 3.3 同步加载场景 SceneManager.LoadScene 3.3.…...

[cg] 使用snapgragon 对UE5.3抓帧

最近想要抓opengl 的api&#xff0c;renderdoc在起应用时会闪退&#xff08;具体原因还不知道&#xff09;&#xff0c;试了下snapgraon, 还是可以的 官网需要注册登录后下载&#xff0c;官网路径&#xff1a;Developer | Qualcomm 为了方便贴上已经下载好的exe安装包&#x…...

一元函数微积分的几何应用:二维平面光滑曲线的曲率公式

文章目录 前言曲率和曲率半径的定义曲率计算公式参数方程形式直角坐标显式方程形式极坐标形式向量形式 前言 本文将介绍二维平面光滑曲线的曲率定义以及不同形式的曲率及曲率半径公式的推导。 曲率和曲率半径的定义 &#xff08;关于二维平面光滑曲线的定义以及弧长公式请参…...

ISBN 号码——蓝桥杯

1.题目描述 每一本正式出版的图书都有一个 ISBN 号码与之对应&#xff0c;ISBN 码包括 9 位数字、1 位识别码和 3 位分隔符&#xff0c;其规定格式如 “x-xxx-xxxxx-x”&#xff0c;其中符号“-”是分隔符&#xff08;键盘上的减号&#xff09;&#xff0c;最后一位是识别码&a…...

Spring Boot - 数据库集成06 - 集成ElasticSearch

Spring boot 集成 ElasticSearch 文章目录 Spring boot 集成 ElasticSearch一&#xff1a;前置工作1&#xff1a;项目搭建和依赖导入2&#xff1a;客户端连接相关构建3&#xff1a;实体类相关注解配置说明 二&#xff1a;客户端client相关操作说明1&#xff1a;检索流程1.1&…...

51单片机CLD1602显示万年历+闹钟+农历+整点报时

1. 硬件设计 硬件是我自己设计的一个通用的51单片机开发平台&#xff0c;可以根据需要自行焊接模块&#xff0c;这是用立创EDA画的一个双层PCB板&#xff0c;所以模块都是插针式&#xff0c;不是表贴的。电路原理图在文末的链接里&#xff0c;PCB图暂时不选择开源。 B站上传的…...

C++ 中的类(class)和对象(object)

在 C 中&#xff0c;类&#xff08;class&#xff09;和对象&#xff08;object&#xff09;是面向对象编程&#xff08;OOP&#xff09;的核心概念。类是一种用户自定义的数据类型&#xff0c;它将数据&#xff08;成员变量&#xff09;和操作这些数据的函数&#xff08;成员函…...

安卓通过网络获取位置的方法

一 方法介绍 1. 基本权限设置 首先需要在 AndroidManifest.xml 中添加必要权限&#xff1a; xml <uses-permission android:name"android.permission.INTERNET" /> <uses-permission android:name"android.permission.ACCESS_NETWORK_STATE" /&g…...

2025 年,链上固定收益领域迈向新时代

“基于期限的债券市场崛起与 Secured Finance 的坚定承诺” 2025年&#xff0c;传统资产——尤其是股票和债券——大规模涌入区块链的浪潮将创造历史。BlackRock 首席执行官 Larry Fink 近期在彭博直播中表示&#xff0c;代币化股票和债券将逐步融入链上生态&#xff0c;将进一…...

npm启动前端项目时报错(vue) error:0308010C:digital envelope routines::unsupported

vue 启动项目时&#xff0c;npm run serve 报下面的错&#xff1a; error:0308010C:digital envelope routines::unsupported at new Hash (node:internal/crypto/hash:67:19) at Object.createHash (node:crypto:133:10) at FSReqCallback.readFileAfterClose [as on…...

11.QT控件:输入类控件

1. Line Edit(单行输入框) QLineEdit表示单行输入框&#xff0c;用来输入一段文本&#xff0c;但是不能换行。 核心属性&#xff1a; 核心信号&#xff1a; 2. Text Edit(多行输入框) QTextEdit表示多行输入框&#xff0c;也是一个富文本 & markdown编辑器。并且能在内容超…...

deepseek核心技术:MLA架构-多头潜在注意力

deepseek核心技术:MLA架构-多头潜在注意力 MLA架构即Multi-Head Latent Attention(多头潜在注意力)架构,是一种优化后的注意力机制。以下是对其及相关示例的具体介绍: 工作原理 输入嵌入:将输入序列中的每个元素转换为向量表示,即嵌入向量。例如在处理文本时,将文本中…...

讯飞星火大模型API使用Python调用

本文仅仅为简单API调用&#xff0c;更多复杂使用方法请参见接口文档 先在科大讯飞开放平台注册账号&#xff0c;点击控制台&#xff0c;在我的应用中创建新应用&#xff0c;新应用的名称可以自定义&#xff0c;这里我写的是ai对话&#xff1a; 在这里我们使用的模型为Speak Ul…...

C#面试常考随笔7:什么是匿名⽅法?还有Lambda表达式?

匿名方法本质上是一种没有显式名称的方法&#xff0c;它可以作为参数传递给需要委托类型的方法&#xff0c;常用于事件处理、回调函数等场景&#xff0c;能够让代码更加简洁和紧凑。 使用场景 事件处理&#xff1a;在处理事件时&#xff0c;不需要为每个事件处理程序单独定义…...

Elasticsearch:如何搜索含有复合词的语言

作者&#xff1a;来自 Elastic Peter Straer 复合词在文本分析和标记过程中给搜索引擎带来挑战&#xff0c;因为它们会掩盖词语成分之间的有意义的联系。连字分解器标记过滤器等工具可以通过解构复合词来帮助解决这些问题。 德语以其长复合词而闻名&#xff1a;Rindfleischetik…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...