一、搜素提示
我们在网站上输入关键字往往都会得到相应匹配的值出现在下拉框中,这是如何实现的呢?
实际上也是通过发送ajax请求之后得到响应将响应的值显示在下拉框里即可!!!
示例如下:
1、准备一个input输入框以及ul列表。
2、监听输入事件,并且设置定时器来根据input中的值发送ajax请求得到相关联匹配的值。
定时器解决问题:精准定位用户搜索内容发出ajax请求(对于关键内容用户会一下子输完,在快速输入过程中不会发出请求),不发出无用的请求为后端增加压力。
3、输入框有值时,显示ul列表即查询出来的值;没有值时,进行隐藏。
<body> <input type="text" id="search"> <ul id="results"></ul> <script type="module"> import { getJSON } from './手撕代码/01、ajax封装(含Promise封装)/index(2封装ajax进阶Promise).js'; const searchInput = document.getElementById("search"); const results = document.getElementById("results"); const url = "https://www.imooc.com/api/http/search/suggest?words="; //封装请求操作(包含发送ajax请求以及挂载响应后的值到页面上) const handleQueryKey = () => { // 当前输入框中值不为空 if (searchInput.value.trim() !== '') { // console.log(searchInput.value); getJSON(url + searchInput.value) .then(response => { console.log(response); let addHtml = ''; //将响应得到数组中的word连接挂载到ul标签中 for (const obj of response.data) { addHtml += `<li>${obj.word}</li>` } results.innerHTML = addHtml; results.style.display = ''; }) .catch(error => { console.log(error) }); } else { // 为空时,隐藏ul元素 results.style.display = 'none'; } }; let timer = null; searchInput.addEventListener('input', () => { if (timer) clearTimeout(timer); // 关键:通过使用定时器来进行前端优化关键字查询,只有在输入框之后时间后才会发送 timer = setTimeout(handleQueryKey, 300); }, false); </script> </body>
二、二级菜单
实现思路
①访问指定页面,发送一个ajax请求,网页预览出所有的一级菜单挂载到ul标签中(动态设置键值对data-key="${item.key}"),并为每个一级菜单添加鼠标移动监听事件。
data-key对应的值为之后发送ajax请求的关键值。
②鼠标移动到一级菜单时,会先判断是否有data-done="done",没有再次发送ajax请求加载数据将p标签挂载到li标签里,并且设置data-done="done"表明当前数据标签已经动态加载好了,下次不需要再发出ajax请求了!!!
思考:通过这种方式来优化前端页面,将一些必要的数据先查询展示出来,其他一些无关紧要的等待用户的相关操作再进行请求加载数据,这种方式的话能够前端页面加载速度变快也能更好的减轻后端接收服务请求的压力。
亮点:对于下一次要查询的数据保存在data-xxx标签中,阻止重复发出请求同样是添加data-done="done"键值对形式。
实现
效果:
<head> <meta charset="UTF-8" /> <title>二级菜单</title> <style> /* css reset */ * { padding: 0; margin: 0; } li { list-style: none; } /* menu */ .menu { width: 100px; background-color: rgba(0, 0, 0, 0.1); margin: 10px; } .menu-item { position: relative; padding: 5px; cursor: pointer; } .menu-content { display: none; position: absolute; left: 100%; top: 0; width: 200px; height: 100px; padding: 0 5px; background-color: rgba(0, 0, 0, 0.1); } .menu-item:hover { background-color: rgba(0, 0, 0, 0.4); } .menu-item:hover .menu-content { display: block; } .menu-loading { margin: 45px 0 0 92px; } </style> </head> <body> <ul id="menu" class="menu"> <!-- <li class="menu-item" data-key="hot" data-done="done"> <span>热门</span> <div class="menu-content"> <p><img class="menu-loading" src="./loading.gif" alt="加载中" /></p> </div> </li> --> </ul> <script type="module"> // https://www.imooc.com/api/mall-PC/index/menu/hot // https://www.imooc.com/api/mall-PC/index/menu import { getJSON } from './ajax/index.js'; const menuURL = 'https://www.imooc.com/api/mall-PC/index/menu'; const menuEl = document.getElementById('menu'); // 加载页面时就发出ajax请求 getJSON(menuURL) // 1、发出ajax请求,加载一级菜单 .then(repsonse => { let html = ''; for (const item of repsonse.data) { html += ` <li class="menu-item" data-key="${item.key}"> <span>${item.title}</span> <div class="menu-content"> <p><img class="menu-loading" src="./loading.gif" alt="加载中" /></p> </div> </li> `; } menuEl.innerHTML = html; }) // 2、避免代码冗余,我们将添加监听器事件放置在第二个then()中 .then(() => { const items = menuEl.querySelectorAll('.menu-item'); // 为所有的一级菜单添加鼠标移入事件 for (const item of items) { item.addEventListener( 'mouseenter', () => { // 通过data-done="done"来表示是否需要再发送ajax请求 if (item.dataset.done === 'done') return; // 这里是二级菜单的ajax请求 getJSON( `https://www.imooc.com/api/mall-PC/index/menu/${item.dataset.key}` ) .then(repsonse => { // 正常响应后,设置data-done="done",让下次不要再发出不必要的请求了 item.dataset.done = 'done'; let html = ''; for (const item of repsonse.data) { html += `<p>${item.title}</p>`; } item.querySelector('.menu-content').innerHTML = html; }) .catch(err => { console.log(err); }); }, false ); } }) .catch(err => { console.log(err); }); </script> </body>
三、多个ajax请求的并发执行
需求:当你的页面有多个ajax请求时,你想要ajax请求都得到响应并填充网页之后再给用户看,就需要你额外添加一个加载效果。
方案:此时你就可以使用到Promise.all([p,p1])方法了,在all()方法后使用then(),表示数组中的promise都执行完了此时该回调函数你就可以进行操作了如将加载效果关闭等。
示例
/** 加载样式效果:充满整个页面 注意其中设置了z-index值也就是在最顶层 **/ .loading-page { position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 1000; background-color: #eee; text-align: center; } /** 让加载图片处于页面中间 **/ .loading-img { position: absolute; top: 50%; } /** 加载效果消失样式 **/ .none { display: none; } <div id="loading-page" class="loading-page"> <img class="loading-img" src="./loading.gif" alt="加载中" /> </div> <script type="module"> const p1=xxx;//Promise的ajax请求 const p2=xxx;//Promise的ajax请求 //当两个promise都执行完之后才会指定then()中的回调函数,此时我们就可以将加载效果给隐藏啦 Promise.all([p1, p2]).then(() => { // loadingPageEl.style.display = 'none'; // IE10 开始支持 loadingPageEl.classList.add('none'); // loadingPageEl.classList.remove('none'); }); </script>
效果:将页面请求都完成响应过后即可将加载的样式过渡效果清除即可!!!