<!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>
<style>
table {
width: 400px;
border: 1px solid #000;
border-collapse: collapse;
margin: 0 auto;
}
td,
th {
border: 1px solid #000;
text-align: center;
}
input {
width: 50px;
}
.search {
width: 600px;
margin: 20px auto;
}
</style>
</head>
<body>
<div class="search"> 按照价格查询: <input type="text" class="start" /> - <input type="text" class="end" /> <button class="search-price">搜索</button> 按照商品名称查询: <input type="text" class="product" /> <button class="search-pro">查询</button> </div>
<table>
<thead>
<tr>
<th>id</th>
<th>产品名称</th>
<th>价格</th>
</tr>
</thead>
<tbody>
<!-- 模板结构 -->
<!-- <tr>
<td>1</td>
<td>小米</td>
<td>3999</td>
</tr> -->
</tbody>
</table>
<script>
// 数据源
var data = [
{
id: 1,
pname: '小米',
price: 3999
},
{
id: 2,
pname: 'oppo',
price: 999
},
{
id: 3,
pname: '荣耀',
price: 1299
},
{
id: 4,
pname: '华为',
price: 1999
},
{
id: 5,
pname: '华为',
price: 6799
}
]
// 获取元素
var tbody = document.querySelector('tbody ')
// 输入开始价格的输入框
var startIpt = document.querySelector('.start')
// 输入结束价格的输入框
var endIpt = document.querySelector('.end')
// 搜索按钮
var search_price_btn = document.querySelector('.search-price')
// 输入商品名的输入框
var proIpt = document.querySelector('.product')
var search_pro_btn = document.querySelector('.search-pro')
// 封装渲染表格数据的处理函数 -> 2中方法,任选其一
// 第一种方法:先创建 tr 元素,然后为 tr 元素赋值,再让 父级 tbody 追加 tr 元素
function renderData1(data) {
// 清空表格
tbody.innerHTML = ''
// 遍历数组
data.forEach(item => {
// 创建 tr 元素
var tr = document.createElement('tr')
// 为 tr 赋值,渲染出表格中的内容
tr.innerHTML = '<td>' + item.id + '</td>' + '<td>' + item.pname + '</td>' + '<td>' + item.price + '</td>'
// 让父级 tbody 追加 tr 元素
tbody.appendChild(tr)
})
}
// 第二种方法:先准备好模板字符串,再通过 insertAdjacentHTML 将模板字符串追加到 tbody 元素中
function renderData2(data) {
// 清空表格
tbody.innerHTML = ''
// 遍历数据
data.forEach(item => {
// 模板字符串
var str = '<tr><td>' + item.id + '</td><td>' + item.pname + '</td><td>' + item.price + '</td>'
// 让 tbody 追加模板字符串
tbody.insertAdjacentHTML('beforeend', str)
})
}
// 调用函数,渲染UI页面,以防止页面空白
renderData2(data) // 这里选用第二种方法
// 封装对用户输入的值做进一步处理的函数
function handleVal(target) {
// 如果用户没有输入其实价格,则默认价格为 0
if (!target.value.trim() && target.className === 'start') {
return 0
}
// 如果用户没有输入结束价格,则默认价格为现有的最大价格
if(!target.value.trim() && target.className === 'end') {
var priceArr = data.map(item => item.price)
var maxPrice = Math.max(...priceArr)
return maxPrice
}
// 如果用户输入了数值,则返回用户输入的值
return target.value.trim()
}
// 根据价格搜索商品的处理函数
function handlePriceSearch() {
// 获取文本输入框中的值,并调用函数handleVal 对值做进一步处理
var startPri = handleVal(startIpt)
var endPri = handleVal(endIpt)
var newData = data.filter(item => item.price >= startPri && item.price <= endPri)
renderData2(newData)
}
// 点击搜索按钮调用处理函数搜索商品
search_price_btn.onclick = handlePriceSearch
// 为查询按钮绑定点击事件
/* search_pro_btn.onclick = function() {
// 获取文本框中的值
var proName = proIpt.value.trim()
// 创建一个新数组
var newArr = []
// 查找满足条件的值
data.some(item => {
if (item.pname === proName) {
// 将找到的item项追加到新数组中
newArr.push(item)
// 固定写法,some 只能返回布尔值,返回 true 表示已找到,此时会终止代码退出循环
return true
}
})
// 重新渲染数据
renderData2(newArr)
} */
// 这个地方除了可以使用 some,感觉 find 也可以,而且使用起来好像更简单。
// 因为键盘弹起事件中也需要用到,所以这里将其封装为函数
function handleProSearch() {
// 获取文本框中的值
var proName = proIpt.value.trim()
// 准备一个新数组
var newArr = []
// find 直接返回找到的那一项
var findItem = data.find(item => item.pname === proName)
// 追加数据
newArr.push(findItem)
// 渲染数据
renderData2(newArr)
}
search_pro_btn.onclick = handleProSearch
// 封装键盘弹起事件的处理函数
function handleKeyup(e) {
// 按下 esc 键清空输入框中的内容
if (e.keyCode === 27) {
this.value = ''
// 如果用户将起始价格和结束价格都清空,则重新渲染完整的数据
if (!startIpt.value && !endIpt.value) {
// 1、直接调用函数渲染:刚清空输入框页面就被重新渲染了,个人感觉这种效果更好。
renderData2(data)
// 2、强制刷新页面:停顿一下再渲染页面,
// location.reload()
}
} else if (e.keyCode === 13) {
// 按下回车键搜索商品
handlePriceSearch()
}
}
// 为开始价格的输入框绑定键盘弹起事件
startIpt.onkeyup = handleKeyup
// 为结束价格的输入框绑定键盘弹起事件
endIpt.onkeyup = handleKeyup
// 为输入商品名的输入框绑定键盘弹起事件
// 因为这里与起始价格和结束价格输入框的处理有些不同,所以单独写一个处理函数
proIpt.onkeyup = function(e) {
// 按下 esc 键清空输入框中的内容
if (e.keyCode === 27) {
this.value = ''
// 将输入框中的内容清空后,重新渲染完整的数据
renderData2(data)
// location.reload() // 上面的效果更好些,保留上面的。
} else if (e.keyCode === 13) {
// 按下回车键搜索商品
handleProSearch()
}
}
</script>
</body>
</html>
<!--
写代码时注意:先实现主要功能,再完善细节!这样不会乱,否则需要频繁的大范围改动代码!
一、主要功能:
1、实现通过价格区间搜索商品的功能。
2、实现通过商品名搜索商品的功能。
二、细节:
1、用户没有输入起始价格,则默认价格为0;用户没有输入结束价格,则默认价格为现有价格中的最大值。
2、按下 esc 键清空输入框中的内容;按下回车键搜索商品。
3、起始价格和结束价格的输入框内容都清空后,重新渲染完整的数据页面;而输入商品名的输入框只要内容被清空后,则重新渲染完整数据。
-->
<!--
此案例中存在的BUG:
1、只能实现“精准搜索”。
2、只能搜索到第一个满足条件的商品。(无论是 some(返回布尔值) 还是 find(直接返回查找到的那一项) 都只会查找到第一个满足的值)
-->