课程名称:await 函数用法
课程章节:二级菜单
课程讲师: Alex
课程内容:
二级菜单
先发送Ajax请求获取主菜单,鼠标在主菜单每一项会发送新的请求来获取子菜单,显示二级菜单。发送完请求,不再二次发送请求
HTML结构如下:
<ul id="menu" class="menu"> <li class="menu-item" data-key="hot" data-done="done"> <span>热门出发地</span> <div class="menu-content"> <img class="menu-loading" src="./loading.gif" alt="加载中" /> <p>内地热门城市</p> <p>热门景点</p> </div> </li> </ul>
二级菜单里默认情况是加载中的小图标,但获取到内容时,把小图标去掉显示内容
接下来,我们用js动态生成<li>标签里的内容
接口:
// https://www.imooc.com/api/mall-PC/index/menu // https://www.imooc.com/api/mall-PC/index/menu/hot // https://www.imooc.com/api/mall-PC/index/menu/hk
面向过程的写法,比较乱
function wait(ms) { return new Promise(resolve => { setTimeout(resolve, ms); }); } function getJSON(url) { return new Promise(resolve => { const xhr = new XMLHttpRequest(); xhr.addEventListener( 'load', async () => { if ( (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304 ) { // 模拟网络延迟 await wait(1000); resolve(xhr.response); } }, false ); xhr.open('GET', url, true); xhr.responseType = 'json'; xhr.send(null); }); } (async () => { const url = 'https://www.imooc.com/api/mall-PC/index/menu'; const $menu = document.getElementById('menu'); // 发送请求,获取数据,创建主菜单 const menuResult = await getJSON(url); // console.log(menuResult); createMenu($menu, menuResult.data); // 循环绑定事件,发送请求,获取数据,创建子菜单 const $items = $menu.getElementsByClassName('menu-item'); [...$items].forEach($item => { $item.addEventListener( 'mouseenter', async () => { if ($item.dataset.done === 'done') return; const subMenuResult = await getJSON( `${url}/${$item.dataset.key}` ); console.log(subMenuResult); $item.dataset.done = 'done'; createSubMenu($item, subMenuResult.data); }, false ); }); })(); function createMenu($el, data) { let html = ''; for (const item of data) { html += `<li class="menu-item" data-key="${item.key}"> <span>${item.title}</span> <div class="menu-content"> <img class="menu-loading" src="./loading.gif" alt="加载中" /> </div> </li>`; } $el.innerHTML = html; } function createSubMenu($el, data) { let html = ''; for (const item of data) { html += `<p>${item.title}</p>`; } $el.querySelector('.menu-content').innerHTML = html; }
面向对象
前面的wait和getJSON都需要留下来
class Menu { constructor($el) { this.$el = $el; this.url = 'https://www.imooc.com/api/mall-PC/index/menu'; } async getData(url = this.url) { return (await getJSON(url)).data; } render(data) { let html = ''; for (const item of data) { html += `<li class="menu-item" data-key="${item.key}"> <span>${item.title}</span> <div class="menu-content"> <img class="menu-loading" src="./loading.gif" alt="加载中" /> </div> </li>`; } this.$el.innerHTML = html; } } class SubMenu { constructor($el) { this.$el = $el; this.url = 'https://www.imooc.com/api/mall-PC/index/menu'; } // 是否需要获取数据 needGetData() { if (this.$el.dataset.done !== 'done') { this.$el.dataset.done = 'done'; return true; } return false; } async getData(url = `${this.url}/${this.$el.dataset.key}`) { return (await getJSON(url)).data; } render(data) { let html = ''; for (const item of data) { html += `<p>${item.title}</p>`; } this.$el.querySelector('.menu-content').innerHTML = html; } } // 面向对象 (async () => { const $menu = document.getElementById('menu'); // 发送请求,获取数据,创建主菜单 const menu = new Menu($menu); menu.render(await menu.getData()); // 循环绑定事件,发送请求,获取数据,创建子菜单 const $items = $menu.getElementsByClassName('menu-item'); for (const $item of $items) { $item.addEventListener( 'mouseenter', async () => { const subMenu = new SubMenu($item); if (!subMenu.needGetData()) return; subMenu.render(await subMenu.getData()); }, false ); } })();
这里dataset.done 涉及到dataset的用法,详见:https://class.imooc.com/lesson/2123#mid=50481
课程收获:
这一节是实战课,老师讲的有点不太明白,但是太困了,明天再复习复习,期待明天的学习 。