搜索框Demo

记录一个搜索框的demo,搜索图标在阿里矢量图标库下载

效果图展示

  • 常态图如下:
    image

  • 获得焦点的输入框
    image

  • 有内容输入时,展示关联的列表,可以点击列表项;也可以按上下箭头选择,然后按回车键选择列表项
    image

代码

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>Document</title>
  <link rel="stylesheet" href="./index.css">
</head>
<body>
  <input type="text">
  <div class="list"></div>
  <script src="index.js"></script>
</body>
</html>

js部分如下:

const input = document.querySelector('input');
const listDiv = document.querySelector('.list');

// 模拟数据
let infos = [
  { id: 1, name: '《JavaScript高级程序设计》' },
  { id: 2, name: '《JavaScript高级程序设计》' },
  { id: 3, name: '《JavaScript高级程序设计》' },
  { id: 4, name: '《JavaScript高级程序设计》' },
  { id: 5, name: '《JavaScript高级程序设计》' },
  { id: 6, name: '《JavaScript高级程序设计》' },
  { id: 7, name: '《JavaScript高级程序设计》' },
  { id: 8, name: '《JavaScript高级程序设计》' },
  { id: 9, name: '《JavaScript高级程序设计》' },
  { id: 10, name: '《JavaScript高级程序设计》' },
  { id: 11, name: '《JavaScript高级程序设计》' },
  { id: 12, name: '《JavaScript高级程序设计》' },
  { id: 13, name: '《JavaScript高级程序设计》' },
  { id: 14, name: '《JavaScript高级程序设计》' },
  { id: 15, name: '《JavaScript高级程序设计》' },
]

// input联想列表选中项的索引
let index = 0;
// input的旧值
let oldValue = "";
// input联想列表的长度
let tmpListLenth = 10;

input.addEventListener('keyup', (e) => {
  keyUpEvent(e);
})

input.addEventListener('blur', () => {
  listDiv.classList.remove('listActive');
  input.value = "";
})

listDiv.addEventListener('mousedown', (e) => {
  mouseDownEvent(e, e.target.getAttribute('key'));
})

function filterList(inputValue, allList) {
  inputValue = inputValue.length > 10 ? inputValue.slice(0, 10) : inputValue;
  let tmpList = allList.slice(0, 11 - inputValue.length);
  return tmpList;
}

function keyUpEvent(e) {
  let tmpValue = input.value.trim();
  // 四种情况,一种render,两种innerHtml = "",一种不处理
  if (tmpValue) {
    if (oldValue !== tmpValue) {
      listDiv.classList.add('listActive');
      let tmpList = filterList(tmpValue, infos);
      renderList(tmpList);
      tmpListLenth = tmpList.length;
    }
  } else {
    listDiv.innerHTML = "";
  }
  oldValue = tmpValue;

  // keyCode:40
  if (e.key === "ArrowDown") {
    index = index !== tmpListLenth - 1 ? index + 1 : 0;
    arrowEvent();
  }

  // keyCode:38
  if (e.key === "ArrowUp") {
    index = index !== 0 ? index - 1 : tmpListLenth - 1;
    arrowEvent();
  }

  // keyCode:13
  if (e.key === "Enter") {
    let selectedBook = document.querySelector('.bookActive');
    mouseDownEvent(e, selectedBook.getAttribute('key'));
  }
}

// enter或者mousedown,要根据选中的元素做点事情
function mouseDownEvent(e, id) {
  e.preventDefault();
  input.value = '';
  input.blur();
}

// 按上下箭头,修改列表样式
function arrowEvent() {
  const bookList = document.querySelectorAll('.bookItem');
  // 空数组不会执行回调函数
  bookList.forEach(function (item) {
    item.classList.remove('bookActive');
    if (item.getAttribute('key') == index) {
      item.classList.add('bookActive');
    }
  })
}

// input框中的值变化且不为空,先清空,再重新渲染列表
function renderList(tmpList) {
  listDiv.innerHTML = "";
  console.log('render');
  // 实际情况,直接根据传入的tmpList渲染
  var bookTemplate = tmpList.map((item, index) => {
    return `<div class="bookItem" key=${index}>${item.id}.&nbsp;&nbsp;${item.name}</div>`
  }).join('');
  listDiv.innerHTML = bookTemplate;
  index = 0;
  arrowEvent();
}

css部分如下:

input {
  background: url("./search.svg") no-repeat;
  background-position: 10px;
  background-size: 25px 25px;

  position: absolute;
  top: 30%;
  left: 50%;
  transform: translateX(-50%);

  height: 50px;
  width: 400px;

  border: 1px solid rgb(191,191,191);
  border-radius: 25px;

  box-shadow: 2px 2px 2px #eee;
  padding-left: 40px;

  font-size: 16px;
}

/* input边框的颜色,默认是outline控制的,不是border */
/* jQuery设置的border会生效(未尝试) */
input:focus {
  background-image: url("./search-active.svg");
  border-color: #66afe9;
  outline: none;
  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);
  box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);
}

.list {
  visibility: hidden;
  width: 410px;
  /* height: 300px; */
  box-shadow: 2px 2px 5px rgb(191,191,191);
  position: absolute;
  left: 50%;
  top: calc(30% + 55px);
  transform: translateX(-50%);
}

.listActive {
  visibility: visible;
}

.bookItem {
  height: 30px;
  border-bottom: 1px solid rgb(236,236,236);
  line-height: 30px;
}

.bookItem:hover {
  background-color: rgb(236,236,236);
}

.bookActive {
  background-color: rgb(236,236,236);
}
posted @ 2021-11-14 21:08  hmh12345  阅读(108)  评论(0)    收藏  举报