十五(AJAX)、bootstrap弹框、案例(图书管理、图片上传、网站换肤、个人设置)、作业(英雄百科、必要商城分类)

1. bootstrap弹框

2. 案例1_图书管理

javascript 复制代码
// 自己的图书数据: 给自己起个外号
const creator = "chl";

// 获取-图书列表
function render() {
  axios({
    url: "https://hmajax.itheima.net/api/books",
    params: {
      creator,
    },
  }).then((res) => {
    // console.log(res.data.data);
    let str = res.data.data
      .map((item, index) => {
        const { id, bookname, author, publisher } = item;
        return `
          <tr>
            <td>${index + 1}</td>
            <td>${bookname}</td>
            <td>${author}</td>
            <td>${publisher}</td>
            <td>
              <span class="del" data-id="${id}">删除</span>
              <span class="edit" data-id="${id}">编辑</span>
            </td>
          </tr>
        `;
      })
      .join("");
    document.querySelector(".list").innerHTML = str;
  });
}
render();

const editModal = document.querySelector(".edit-modal");
const modalEdit = new bootstrap.Modal(editModal);

// 删除+编辑-事件委托
let id = "";
document.querySelector(".list").addEventListener("click", function (e) {
  id = e.target.dataset.id;
  // console.log(id);

  // 删除-图书
  if (e.target.classList.contains("del")) {
    axios({
      url: `https://hmajax.itheima.net/api/books/${id}`,
      method: "DELETE",
    }).then((res) => {
      render();
    });
  }

  // 编辑
  if (e.target.classList.contains("edit")) {
    // console.log(e.target.parentNode.parentNode); // tr
    modalEdit.show();
    // 获取-图书详情
    axios({
      url: `https://hmajax.itheima.net/api/books/${id}`,
    }).then((res) => {
      // console.log(res);
      // console.log(res.data.data);

      // 解构 剩余参数 对象方法
      /* const { id, ...other } = res.data.data;
      const oValues = Object.values(other);
      // console.log(other);
      Object.keys(other).forEach((key, index) => {
        document.querySelector(`.edit-form .${key}`).value = oValues[index];
      }); */

      // for in遍历对象 key是属性名 获取属性值->对象名[属性名]
      for (const key in res.data.data) {
        document.querySelector(`.edit-form .${key}`).value = res.data.data[key];
      }

      /* document.querySelector(`.edit-form .bookname`).value =
        res.data.data.bookname;
      document.querySelector(`.edit-form .author`).value = res.data.data.author;
      document.querySelector(`.edit-form .publisher`).value =
        res.data.data.publisher; */
    });
  }
});

// 编辑 确认修改按钮
const editBtn = document.querySelector(".edit-btn");
editBtn.addEventListener("click", function () {
  const editForm = document.querySelector(".edit-form");
  const data = serialize(editForm, { hash: true, empty: true });
  // 修改-图书详情
  axios({
    url: `https://hmajax.itheima.net/api/books/${id}`,
    method: "PUT",
    data: {
      ...data,
      creator,
    },
  }).then((res) => {
    render();
    modalEdit.hide();
  });
});

// 新增-图书
const addBtn = document.querySelector(".add-btn");
const addModal = document.querySelector(".add-modal");
const modalAdd = new bootstrap.Modal(addModal);
addBtn.addEventListener("click", function () {
  // serialize 获取表单值
  const addForm = document.querySelector(".add-form");
  const data = serialize(addForm, { hash: true, empty: true });
  // console.log(data); // {bookname: '12', author: '12', publisher: '12'}

  axios({
    url: "https://hmajax.itheima.net/api/books",
    method: "post",
    data: {
      // 展开运算符,解构data
      ...data,
      /* bookname,
      author,
      publisher, */
      creator,
    },
  }).then((res) => {
    // console.log(res);
    render();
    modalAdd.hide();
    // console.log(Object.keys(data)); // ['bookname', 'author', 'publisher']
    // 增加后表单数据置空,data对象内属性名和所需找的标签类名相同 --> forEach
    Object.keys(data).forEach((key) => {
      document.querySelector(`.add-form .${key}`).value = "";
    });
  });
});

3. 案例2_图片上传

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">

<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>
  <style>
    .img {
      width: 200px;
    }
  </style>
</head>

<body>
  <!-- file标签 -->
  <input type="file" class="upload">

  <!-- 渲染服务器返回的图片URL -->
  <img src="" class="img" alt="">

  <!-- 导入axios -->
  <!-- <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.2.0/axios.min.js"></script> -->
  <script src="./axios.min.js"></script>
  <script>
    /**
     * 图片上传
     * 1. 选择图片
     * 2. FormData对象
     * 3. 调用上传接口
     * */
    const upload = document.querySelector('.upload')
    upload.addEventListener('change', function () {
      // FormData内置对象,负责向服务器传递表单数据,常用于文件上传
      const data = new FormData()
      data.append('img', this.files[0])
      // 调用上传接口
      axios({
        url: 'https://hmajax.itheima.net/api/uploadimg',
        method: 'post',
        // data:formData对象
        data,
      }).then(res => {
        // console.log(res.data)
        document.querySelector('.img').src = res.data.data.url
      })
    })

  </script>
</body>

</html>

4. 案例3_网站换肤

javascript 复制代码
const skin = document.querySelector("#skin");
skin.addEventListener("change", function () {
  const data = new FormData();
  data.append("img", this.files[0]);
  axios({
    url: "https://hmajax.itheima.net/api/uploadimg",
    method: "post",
    data,
  }).then((res) => {
    // document.body.style.backgroundImage = `url(${res.data.data.url})`;

    // 本地存储
    localStorage.setItem("url", res.data.data.url);
    document.body.style.backgroundImage = `url(${localStorage.getItem("url")})`;
  });
});
document.body.style.backgroundImage = `url(${
  localStorage.getItem("url") || ""
} )`;

5. 案例4_个人设置

html

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">

<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">
  <!-- 导入bootstrap -->
  <!-- <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/css/bootstrap.min.css" rel="stylesheet"> -->
  <!-- 核心样式 -->
  <link rel="stylesheet" href="./css/index.css">
  <title>个人设置</title>
</head>

<body>
  <!-- toast 提示框 -->
  <div class="toast my-toast" data-bs-autohide="true" data-bs-delay="1500" aria-live="assertive" aria-atomic="true"
    role="alert">
    <div class="toast-body">
      <div class="alert alert-success info-box" role="alert">
        操作成功
      </div>
    </div>
  </div>
  <!-- 核心内容区域 -->
  <div class="container">
    <ul class="my-nav">
      <li class="active">基本设置</li>
      <li>安全设置</li>
      <li>账号绑定</li>
      <li>新消息通知</li>
    </ul>
    <div class="content">
      <div class="info-wrap">
        <h3 class="title">基本设置</h3>
        <form class="user-form" action="javascript:;">
          <div class="form-item">
            <label for="email">邮箱</label>
            <input id="email" name="email" class="email" type="text" placeholder="请输入邮箱" autocomplete="off">
          </div>
          <div class="form-item">
            <label for="nickname">昵称</label>
            <input id="nickname" name="nickname" class="nickname" type="text" placeholder="请输入昵称" autocomplete="off">
          </div>
          <div class="form-item">
            <label>性别</label>
            <label class="male-label"><input type="radio" name="gender" class="gender" value="0">男</label>
            <label class="male-label"><input type="radio" name="gender" class="gender" value="1">女</label>
          </div>
          <div class="form-item">
            <label for="desc">个人简介</label>
            <textarea id="desc" name="desc" class="desc" placeholder="请输入个人简介" cols="20" rows="10"
              autocomplete="off"></textarea>
          </div>
          <button class="submit">提交</button>
        </form>
      </div>
      <div class="avatar-box">
        <h4 class="avatar-title">头像</h3>
          <img class="avatar" src="./img/头像.png" alt="">
          <label for="upload">更换头像</label>
          <input id="upload" type="file">
      </div>

    </div>
  </div>
  <!-- 导入 axios -->
  <!-- <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.2.0/axios.min.js"></script> -->
  <script src="../axios.min.js"></script>
  <!-- 导入 bootstrap -->
  <!-- <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/js/bootstrap.min.js"></script> -->
  <!-- 导入 form-serialize -->
  <script src="./lib/form-serialize.js"></script>
  <!-- 核心逻辑 -->
  <script src="./js/index.js"></script>
</body>

</html>

js

javascript 复制代码
// 修改-个人头像
const upload = document.querySelector("#upload");
const creator = "chl";
upload.addEventListener("change", function () {
  const data = new FormData();
  data.append("avatar", this.files[0]);
  data.append("creator", creator);

  axios({
    url: "https://hmajax.itheima.net/api/avatar",
    method: "put",
    data,
  }).then((res) => {
    // console.log(res.data);
    document.querySelector(".avatar").src = res.data.data.avatar;
  });
});

// 获取-个人信息
function getData() {
  axios({
    url: "https://hmajax.itheima.net/api/settings",
    params: {
      creator,
    },
  }).then((res) => {
    // 方法一:解构并渲染到页面
    // const {} = res.data.data;
    // console.log(res.data.data);

    // 方法二:将要获取的元素类名和数据对象属性名相同 --> 遍历
    Object.keys(res.data.data).forEach((key) => {
      if (key == "avatar") {
        document.querySelector(".avatar").src = res.data.data[key];
      } else if (key == "gender") {
        const genders = document.querySelectorAll(".gender");
        genders[res.data.data[key]].checked = true;
      } else {
        document.querySelector(`.${key}`).value = res.data.data[key];
      }
    });
  });
}
getData();

// 修改-个人信息
document.querySelector(".submit").addEventListener("click", function () {
  const userForm = document.querySelector(".user-form");
  const data = serialize(userForm, { hash: true, empty: true });
  // console.log(data);
  // serialize获取到的data数据为字符串,axios请求时其gender数据类型应为数字类型 --> 数据类型转换
  data.gender = +data.gender;
  axios({
    url: "https://hmajax.itheima.net/api/settings",
    method: "PUT",
    data: {
      ...data,
      creator,
    },
  }).then((res) => {
    // console.log(res.data);

    getData();
  });
});

6. 作业

6.1 英雄百科

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" />
  <link rel="stylesheet" href="./css/bootstrap.min.css" />
  <link rel="stylesheet" href="./css/index.css" />
  <title>英雄百科</title>
</head>

<body>
  <div class="main">
    <img class="cover"
      src="https://img.crawler.qq.com/lolwebschool/0/JAutoCMS_LOLWeb_f6416138ae858f73e2ca40a11587e17f/0" />
    <div class="hero-container">
      <input type="text" class="search" placeholder="检索" />
      <ul class="list">
        <li>
          <img src="http://game.gtimg.cn/images/lol/act/img/champion/Annie.png" class="pic" alt="" />
          <p>安妮</p>
        </li>
      </ul>
    </div>
  </div>
  <div id="infoModal" class="modal" tabindex="-1">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title">黑暗之女安妮</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div class="modal-body">
          <div class="info">
            <img src="http://game.gtimg.cn/images/lol/act/img/champion/Annie.png" class="icon img-thumbnail"
              alt="..." />
            <div class="progress-box">
              <div class="progress">
                <div class="attack progress-bar bg-success" style="width: 25%">攻击:</div>
              </div>
              <div class="progress">
                <div class="defense progress-bar bg-info" role="progressbar" style="width: 50%">防御:</div>
              </div>
              <div class="progress">
                <div class="magic progress-bar bg-warning" role="progressbar" style="width: 75%">魔法:</div>
              </div>
              <div class="progress">
                <div class="difficulty progress-bar bg-danger" role="progressbar" style="width: 100%">难度:</div>
              </div>
            </div>
          </div>
          <p>
            拥有危险夺命的能力,却长着一幅小大人儿的可爱模样,这就是掌握深不可测占火魔法的女孩------安妮。安妮生活在诺克萨斯北边的山脚下,但即便是在这种地方,她也依然是魔法师中的异类。她与火焰的紧密关系与生俱来------最初那些火焰是伴随着喜怒无常的冲动情绪出现的,后来她学会了如何掌握这些"好玩的小把戏"。其中,安妮最喜欢的就是她召唤亲爱的泰迪熊提伯斯------那头狂野的守护火兽。如今安妮已经迷失在了永恒的天真里,她在黑暗森林中游荡,寻觅着能陪自己玩耍的人。
          </p>
        </div>
      </div>
    </div>
  </div>
</body>
<script src="./lib/axios.js"></script>
<script src="./lib/bootstrap.min.js"></script>
<script>
  /*
    需求如下:
      渲染英雄列表数据
      搜索英雄
      渲染英雄详情数据
  */

  // 1. 渲染英雄列表数据
  axios({
    url: 'https://hmajax.itheima.net/api/lol/search',
  }).then(res => {
    console.log(res.data.data)
    render(res.data.data)
  })
  function render(data) {
    let str = data.map(item => {
      return `
        <li>
          <img src=${item.icon} class="pic" alt="" data-id="${item.heroId}" />
          <p>${item.title}</p>
        </li>
      `
    }).join('')
    document.querySelector('.list').innerHTML = str
  }


  // 2. 搜索英雄
  const search = document.querySelector('.search')
  search.addEventListener('keyup', function (e) {
    console.log(e)
    if (e.code === 'Enter') {

      // if (e.key === 'Enter') {
      console.log(1)
      const q = search.value
      axios({
        url: 'https://hmajax.itheima.net/api/lol/search',
        params: {
          q,
        }
      }).then(res => {
        render(res.data.data)
      })
    }
  })

  // 3. 渲染英雄详情数据 事件委托
  const modal = new bootstrap.Modal(document.querySelector('.modal'))
  document.querySelector('.list').addEventListener('click', function (e) {
    console.log(e)

    if (e.target.classList.contains('pic')) {
      // console.log(11)
      // console.log()

      const id = e.target.dataset.id
      axios({
        url: 'https://hmajax.itheima.net/api/lol/info',
        params: {
          id
        }
      }).then(res => {
        console.log(res.data.data.hero)
        const { name, title, icon, shortBio, attack, defense, magic, difficulty } = res.data.data.hero
        document.querySelector('.modal-content').innerHTML = `
          <div class="modal-header">
            <h5 class="modal-title">${name + title}</h5>
            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body">
            <div class="info">
              <img src=${icon} class="icon img-thumbnail"
                alt="..." />
              <div class="progress-box">
                <div class="progress">
                  <div class="attack progress-bar bg-success" style="width: ${attack / 10 * 100 + '%'}">攻击:</div>
                </div>
                <div class="progress">
                  <div class="defense progress-bar bg-info" role="progressbar" style="width: ${defense / 10 * 100 + '%'}">防御:</div>
                </div>
                <div class="progress">
                  <div class="magic progress-bar bg-warning" role="progressbar" style="width: ${magic / 10 * 100 + '%'}">魔法:</div>
                </div>
                <div class="progress">
                  <div class="difficulty progress-bar bg-danger" role="progressbar" style="width: ${difficulty / 10 * 100 + '%'}">难度:</div>
                </div>
              </div>
            </div>
            <p>${shortBio}</p>
          </div>
        `

        modal.show()
      })
    }
  })
</script>

</html>

6.2 必要商城-分类

html 复制代码
<script>
  /*
    需求如下:
      页面默认展示所有一级分类数据
      点击一级分类切换,展示下属二级分类数据
      点击二级分类分类,展示下属三级分类数据
  */
  const ulOne = document.querySelector('#one')
  /* function render(data) {
    let str = data.map(item => {
      return `
        <li class="item">${item.firstName}</li>
      `
    }).join('')
    ulOne.innerHTML = str
  } */

  // 1. 页面默认展示所有一级分类数据
  axios({
    url: 'https://hmajax.itheima.net/api-s/categoryfirst',
  }).then(res => {
    // console.log(res.data.list)
    let str = res.data.list.map(item => {
      // console.log(item.firstId)
      return `
        <li class="item" data-id="${item.firstId}">${item.firstName}</li>
      `
    }).join('')
    ulOne.innerHTML = str
  })

  // 2. 点击一级分类切换,展示下属二级分类数据
  const ulTwo = document.querySelector('#two')
  ulOne.addEventListener('click', function (e) {

    if (e.target.classList.contains('item')) {
      // console.log(e.target.dataset.id)
      // console.log(e)
      const firstId = e.target.dataset.id
      axios({
        url: 'https://hmajax.itheima.net/api-s/categorySecond',
        params: {
          firstId,
        }
      }).then(res => {
        // console.log(res.data.list)
        let str = res.data.list.map(item => {
          return `
            <li class="item" data-id="${item.secondId}">${item.secondName}</li>
          `
        }).join('')
        ulTwo.innerHTML = str
      })
    }
  })

  // 3. 点击二级分类分类,展示下属三级分类数据
  const ulThree = document.querySelector('#three')
  ulTwo.addEventListener('click', function (e) {
    if (e.target.classList.contains('item')) {
      const secondId = e.target.dataset.id
      axios({
        url: 'https://hmajax.itheima.net/api-s/categoryThird',
        params: {
          secondId,
        }
      }).then(res => {
        // console.log(res.data.list)
        let str = res.data.list.map(item => {
          return `
            <li class="item">${item.thiredName}</li>
          `
        }).join('')
        ulThree.innerHTML = str
      })
    }
  })

</script>
相关推荐
无我Code12 分钟前
前端-2025年末个人总结
前端·年终总结
文刀竹肃29 分钟前
DVWA -SQL Injection-通关教程-完结
前端·数据库·sql·安全·网络安全·oracle
LYFlied34 分钟前
【每日算法】LeetCode 84. 柱状图中最大的矩形
前端·算法·leetcode·面试·职场和发展
Bigger36 分钟前
Tauri(21)——窗口缩放后的”失焦惊魂”,游戏控制权丢失了
前端·macos·app
Bigger1 小时前
Tauri (20)——为什么 NSPanel 窗口不能用官方 API 全屏?
前端·macos·app
bug总结1 小时前
前端开发中为什么要使用 URL().origin 提取接口根地址
开发语言·前端·javascript·vue.js·html
一招定胜负2 小时前
网络爬虫(第三部)
前端·javascript·爬虫
Shaneyxs2 小时前
从 0 到 1 实现CloudBase云开发 + 低代码全栈开发活动管理小程序(13)
前端
半山烟雨半山青2 小时前
微信内容emoji表情包编辑器 + vue3 + ts + WrchatEmogi Editor
前端·javascript·vue.js
码途潇潇2 小时前
Vue 事件机制全面解析:原生事件、自定义事件与 DOM 冒泡完全讲透
前端·javascript