为了账号安全,请及时绑定邮箱和手机立即绑定

【九月打卡】第5天 前端工程师2022版 项目应用实战:async/await

标签:
JavaScript

课程名称:await 函数用法

课程章节:二级菜单

课程讲师: Alex

课程内容:

二级菜单

先发送Ajax请求获取主菜单,鼠标在主菜单每一项会发送新的请求来获取子菜单,显示二级菜单。发送完请求,不再二次发送请求

https://img1.sycdn.imooc.com//631b50f200013d4613380625.jpg

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" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="./loading.gif" alt="加载中" />
            <p>内地热门城市</p>
            <p>热门景点</p>
          </div>
        </li>
    </ul>

二级菜单里默认情况是加载中的小图标,但获取到内容时,把小图标去掉显示内容

https://img1.sycdn.imooc.com//631b512e00017aec12140471.jpg

https://img1.sycdn.imooc.com//631b512e0001007511720443.jpg

接下来,我们用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" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="./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" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="./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


课程收获:

这一节是实战课,老师讲的有点不太明白,但是太困了,明天再复习复习,期待明天的学习 。



点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消