JavaScript编程基础(五)细说事件与实战之经典计算器

原创 阁主  2023-08-09 17:37:44  阅读 2049 次 评论 0 条
摘要:

继续上次的JavaScript编程基础(四)继续学习,简单记录学习PHP中文网23期JavaScript基础知识,内容包括:dataset自定义属性、class属性、getComputedStyle计算样式、事件添加与派发、事件冒泡、事件冒泡: 事件代理/委托

dataset 对象

  1. 预定义属性: id,class,style, title...
  2. 自定义属性: data-前缀
  3. 注: data-不要写,蛇形->驼峰
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>dataset: 自定义属性</title>
  8. </head>
  9. <body>
  10. <!--
  11. 属性
  12. 1. 内置属性: id, class, style,...
  13. 2. 自定义属性: data-前缀
  14. data-uname, data-my-email
  15. -->
  16. <div
  17. id="user_id"
  18. class="user_class"
  19. style="color: red"
  20. data-uname="朱老师"
  21. data-my-email="zhu@qq.com"
  22. >
  23. 用户信息
  24. </div>
  25. <script>
  26. const div = document.querySelector("div");
  27. // 1. 访问内置属性: obj.prop
  28. console.log(div.id);
  29. // class是关键字, className -> class
  30. console.log(div.className);
  31. // 返回CSSStyleDeclaration对象
  32. console.log(div.style);
  33. console.log(div.style.color);
  34. // ====================================
  35. // 2. 自定义属性: dataset.prop
  36. // data-uname="朱老师"
  37. // data-: 省略
  38. console.log(div.dataset["uname"]);
  39. // 合法属性可以直接用点语法访问
  40. console.log(div.dataset.uname);
  41. // data-my-email="zhu@qq.com"
  42. // 蛇形 -> 小驼峰, user_name -> userName
  43. console.log(div.dataset["my-email"]);
  44. console.log(div.dataset["myEmail"]);
  45. console.log(div.dataset.myEmail);
  46. </script>
  47. </body>
  48. </html>

getComputedStyle对象

  • 计算样式: 元素上的全样样式,包括行内,文档,外部等
  • 只读

style1.css代码:

  1. h2 {
  2. background-color: yellow;
  3. }

完整示例代码:

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>getComputedStyle: 计算样式</title>
  8. <link rel="stylesheet" href="style1.css" />
  9. <!-- 文档样式 -->
  10. <style>
  11. h2 {
  12. border: 1px solid #000;
  13. width: 200px;
  14. height: 50px;
  15. }
  16. </style>
  17. </head>
  18. <body>
  19. <!-- 行内样式 -->
  20. <h2 style="color: red">Hello world</h2>
  21. <script>
  22. const h2 = document.querySelector("h2");
  23. // 行内样式style=""
  24. console.log(h2.style.color);
  25. // 文档样式<style>
  26. console.log(h2.style.width);
  27. console.log(h2.style.height);
  28. console.log(h2.style.backgroundColor);
  29. // 一个元素最终样式,由行内,文档,外部css共同作用的结果
  30. // 全局函数, 计算属性,可以获取元素上的任何css属性
  31. // console.log(window.getComputedStyle(h2));
  32. console.log(window.getComputedStyle(h2).width);
  33. console.log(window.getComputedStyle(h2).height);
  34. console.log(typeof window.getComputedStyle(h2).height);
  35. console.log(window.getComputedStyle(h2).backgroundColor);
  36. // 宽度
  37. let width = window.getComputedStyle(h2).width;
  38. console.log(typeof width);
  39. // 转换为整数
  40. console.log(typeof parseInt(width), parseInt(width));
  41. // 根据 任何数乘以1 都不变,但是一个数字字符串乘以1, 会发生类型的自动转换
  42. console.log(typeof ("123" * 1), "123" * 1);
  43. width = parseInt(width);
  44. h2.style.width = "300px";
  45. h2.style.width = width + 100 + "px";
  46. </script>
  47. </body>
  48. </html>

classList

这是专用于操作元素的class属性

  1. 添加: classList.add()
  2. 判断: classList.contains()
  3. 替换: classList.replace()
  4. 移除: classList.remove()
  5. 切换: classList.toggle()
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>classList: class属性</title>
  8. <style>
  9. .red {
  10. color: red;
  11. }
  12. .blue {
  13. color: blue;
  14. }
  15. .bgc {
  16. background-color: yellow;
  17. }
  18. </style>
  19. </head>
  20. <body>
  21. <h2 class="red">Hello world</h2>
  22. <script>
  23. const h2 = document.querySelector("h2");
  24. // 1. 传统: className
  25. // 添加 <h2 class="red">...</h2>
  26. h2.className = "red";
  27. h2.className = "red bgc";
  28. // 删除
  29. h2.className = "";
  30. // =================================
  31. // 2. classList
  32. // 添加
  33. h2.classList.add("red");
  34. h2.classList.add("bgc");
  35. h2.classList.add("red", "bgc");
  36. /// 替换
  37. h2.classList.replace("red", "blue");
  38. // 删除
  39. h2.classList.remove("bgc", "blue");
  40. // 切换: 自动在 add() , remove() 之间自动切换
  41. h2.classList.toggle("red");
  42. </script>
  43. </body>
  44. </html>

事件基础

  • 事件 3 要素
  1. 事件名称: 字符串, click, keydown, scroll
  2. 事件主体: 元素, <button>,<div>,<form>...
  3. 事件方法: 函数, function(ev){}, ()=>{}
  • 事件增删
  1. 事件添加: 事件属性, addEventListener()
  2. 事件删除: null,removeEventListener()
  3. 事件派发:dispatchEvent()
  • 定时器
  1. 一次性: setTimeout()
  2. 间歇式: setInterval()
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>事件添加与派发</title>
  8. </head>
  9. <body>
  10. <!-- 1. 标签属性: 事件属性 tag.on+事件名称 -->
  11. <button onclick="alert('登陆成功')">登录</button>
  12. <!-- =================================== -->
  13. <!-- 2. html对象属性: obj.onclick -->
  14. <button class="save">保存</button>
  15. <script>
  16. let saveBtn = document.querySelector(".save");
  17. saveBtn.onclick = function () {
  18. alert("保存成功");
  19. };
  20. saveBtn.onclick = function () {
  21. alert("保存失败");
  22. };
  23. // 删除
  24. saveBtn.onclick = null;
  25. // onclick: 不能重复添加同名事件
  26. </script>
  27. <!-- =================================== -->
  28. <!-- 3. 事件监听器: obj.addEventListener() -->
  29. <button class="submit">提交</button>
  30. <script>
  31. let submitBtn = document.querySelector(".submit");
  32. // submitBtn.addEventListener(事件名称,事件方法,是否冒泡false)
  33. submitBtn.addEventListener("click", function () {
  34. alert("提交成功");
  35. });
  36. // 简写
  37. submitBtn.addEventListener("click", () => alert("提交成功"));
  38. submitBtn.addEventListener("click", function () {
  39. alert("提交失败");
  40. });
  41. // submitBtn.removeEventListener('click', 不能用匿名函数)
  42. // addEventListener():注册的同名事件方法会依次触发
  43. </script>
  44. <!-- =================================== -->
  45. <!-- 4. (自定义)事件派发 -->
  46. <button class="ads">广告位</button>
  47. <script>
  48. const adsBtn = document.querySelector(".ads");
  49. let money = 0;
  50. // 点击一次赚10元
  51. adsBtn.addEventListener("click", function () {
  52. console.log((money += 10) + " 元");
  53. });
  54. // 定时器: 自动累加赚钱
  55. /**
  56. * 定时器
  57. * 1. 一次性: setTimeout(function(){}, time)
  58. * 2. 间歇式: setInterval(function(){}, time)
  59. */
  60. setTimeout(function () {
  61. console.log("大家晚上好");
  62. }, 2000);
  63. setInterval(function () {
  64. console.log("大家晚上好");
  65. }, 2000);
  66. setInterval(function () {
  67. console.log((money += 10) + " 元");
  68. }, 1000);
  69. // 创建一个机器人, 帮我去点击
  70. // 机器人 -> 自定义事件去模拟它
  71. const myClick = new Event("click");
  72. setInterval(function () {
  73. adsBtn.dispatchEvent(myClick);
  74. }, 1000);
  75. // 赚够250元, 就停止
  76. let timer = setInterval(function () {
  77. adsBtn.dispatchEvent(myClick);
  78. // 如果money >= 250 ,就不要点击
  79. if (money >= 250) {
  80. // 清除定时器
  81. // 如果是setTimeout(),用 clearTimeout()来清除
  82. // 如果是setInterval(), 用clearInterval()
  83. clearInterval(timer);
  84. console.warn(`今天已经赚了${money}元,明天再来吧`);
  85. }
  86. }, 1000);
  87. </script>
  88. </body>
  89. </html>

事件冒泡

  1. 事件由内向外,逐级向上传递,直到根元素
  2. 事件冒泡可以被禁用:ev.stopPropagation()
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>事件冒泡</title>
  8. <style>
  9. .box {
  10. border: 1px solid;
  11. padding: 15px;
  12. }
  13. </style>
  14. </head>
  15. <body>
  16. <div class="box box1">
  17. box1
  18. <div class="box box2">
  19. box2
  20. <div class="box box3">box3</div>
  21. </div>
  22. </div>
  23. <script>
  24. const boxes = document.querySelectorAll(".box");
  25. // 为每个div添加一个点击事件
  26. boxes.forEach(function (box) {
  27. box.addEventListener(
  28. "click",
  29. function () {
  30. console.log(this.className.replace("box", ""));
  31. // 取消冒泡
  32. // 事件对象 event, 总是可用
  33. console.log(event.stopPropagation());
  34. },
  35. false
  36. );
  37. });
  38. /**
  39. * 冒泡前提
  40. * 1. 元素之间存在层次关系
  41. * 2. 祖先元素也定义与之同名的事件
  42. */
  43. /**
  44. * addEventListener(event,callback,是否冒泡false)
  45. * 1. false: 默认值,冒泡(从内向外)
  46. * 2. true: 捕获 ( 从外向内 )
  47. */
  48. </script>
  49. </body>
  50. </html>

事件代理

  1. 利用事件冒泡,将子元素事件委托到父级上触发
  2. 事件代理机制,可以极大的简化事件添加操作
  3. 事件绑定主体ev.currentTarge
  4. 事件触发主体: ev.target
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>事件冒泡: 事件代理/委托</title>
  8. </head>
  9. <body>
  10. <ul class="list1">
  11. <li class="item">电脑</li>
  12. <li class="item">手机</li>
  13. <li class="item">外套</li>
  14. </ul>
  15. <hr />
  16. <ul class="list2">
  17. <li class="item">西瓜</li>
  18. <li class="item">苹果</li>
  19. <li class="item">草莓</li>
  20. </ul>
  21. <script>
  22. // 任务: 点击任何一个<li>,显示内容
  23. // 1. 传统
  24. const items = document.querySelectorAll(".list1 > .item");
  25. items.forEach((item) => {
  26. item.onclick = function (ev) {
  27. // ev: 事件对象
  28. console.log(ev);
  29. // 事件绑定者: ev.currentTarget
  30. console.log(ev.currentTarget);
  31. // 事件触发者: ev.target
  32. console.log(ev.target);
  33. // this
  34. console.log(this);
  35. console.log(this === ev.target);
  36. console.log(ev.currentTarget === ev.target);
  37. // 因为三者完全相同所以用哪个都可以获取内容
  38. console.log(ev.currentTarget.textContent);
  39. };
  40. });
  41. // ====================================
  42. // 事件冒泡: 子元素上的同名事件,会自动冒泡到父元素上面去触发
  43. // 2. 事件代理
  44. const list = document.querySelector(".list2");
  45. list.onclick = function (ev) {
  46. // 事件绑定者: ev.currentTarget, 父元素
  47. console.log(ev.currentTarget);
  48. // 事件触发者: ev.target, 子元素
  49. console.log(ev.target);
  50. // this
  51. console.log(this);
  52. console.log(this === ev.currentTarget);
  53. console.log(this === ev.target);
  54. // 需要用时间触发者来获取元素文本
  55. console.log(ev.target.textContent);
  56. };
  57. </script>
  58. </body>
  59. </html>

实战计算器

index.html:

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>计算器</title>
  8. <link rel="stylesheet" href="style.css" />
  9. </head>
  10. <body>
  11. <!-- 事件代理, eval() -->
  12. <div class="calculator">
  13. <!-- 结果区 -->
  14. <input type="text" class="result" value="0" readonly />
  15. <!-- 按键区 -->
  16. <div class="btns" onclick="calculator(event)">
  17. <button>F1</button>
  18. <button>F2</button>
  19. <button>CE</button>
  20. <button>AC</button>
  21. <button>7</button>
  22. <button>8</button>
  23. <button>9</button>
  24. <button>/</button>
  25. <button>4</button>
  26. <button>5</button>
  27. <button>6</button>
  28. <button>X</button>
  29. <button>1</button>
  30. <button>2</button>
  31. <button>3</button>
  32. <button>-</button>
  33. <button>0</button>
  34. <button>.</button>
  35. <button>=</button>
  36. <button>+</button>
  37. </div>
  38. </div>
  39. <script src="script.js"></script>
  40. </body>
  41. </html>

style.css:

  1. * {
  2. padding: 0;
  3. margin: 0;
  4. box-sizing: border-box;
  5. }
  6. body {
  7. background-color: #eee;
  8. }
  9. .calculator {
  10. min-width: 360px;
  11. max-width: 460px;
  12. border-radius: 8px;
  13. background-color: #666;
  14. padding: 15px;
  15. display: grid;
  16. grid-template-rows: 60px 1fr;
  17. gap: 20px;
  18. margin: 40px auto;
  19. }
  20. .calculator .result {
  21. font-size: 32px;
  22. font-weight: bolder;
  23. text-align: right;
  24. padding: 6px;
  25. border: none;
  26. outline: none;
  27. border-radius: 8px;
  28. background-color: #cecece;
  29. box-shadow: 2px 2px 2px #333 inset;
  30. }
  31. .calculator .btns {
  32. display: grid;
  33. grid-template-columns: repeat(4, 1fr);
  34. grid-auto-rows: 50px;
  35. gap: 15px;
  36. }
  37. .calculator .btns > * {
  38. font-size: 32px;
  39. font-weight: bolder;
  40. border-radius: 8px;
  41. color: #888;
  42. border: none;
  43. outline: none;
  44. background-color: #444;
  45. box-shadow: 2px 2px 2px #000;
  46. }
  47. .calculator .btns *:nth-child(-n + 4) {
  48. background-color: #222;
  49. }
  50. .calculator .btns *:nth-child(-n + 4):hover,
  51. .calculator .btns > *:hover {
  52. cursor: pointer;
  53. opacity: 0.7;
  54. color: white;
  55. transition: 0.3s;
  56. }

script.js:

  1. // 计算函数
  2. function calculator(ev) {
  3. // 显示结果区
  4. const result = document.querySelector('.result')
  5. // 当前按钮(事件代理)
  6. if (ev.target.tagName !== 'BUTTON') return false
  7. // 当前按钮
  8. const curBtn = ev.target
  9. // 按钮内容
  10. let content = curBtn.textContent
  11. // eval('字符串表达式'): 将一个字符串表达式进行计算并返回结果
  12. // 将内容显示到结果区
  13. // 根据用户点击的按钮内容确定要执行的操作
  14. switch (content) {
  15. // AC 清零
  16. case 'AC':
  17. result.value = 0
  18. break
  19. // CE: 退格
  20. case 'CE':
  21. // 如果结果区有内容
  22. if (result.value.length == 1 || result.value == '错误') {
  23. result.value = 0
  24. } else {
  25. // 删除最后一个字符
  26. // slice(startIndex,endIndex),结果中不包含结束索引的值
  27. result.value = result.value.slice(0, -1)
  28. }
  29. break
  30. // F1
  31. case 'F1':
  32. break
  33. // F2
  34. case 'F2':
  35. break
  36. // = : 计算结果
  37. case '=':
  38. // 缓存结果
  39. let tmpResult = 0
  40. try {
  41. // 如果是乘法,将 "X" 换成 "*"
  42. result.value = result.value.replace('X', '*')
  43. // 计算字符串表达式
  44. tmpResult = eval(result.value)
  45. // 如果结果是小数,仅保留5位就可以了
  46. if (tmpResult.toString().includes('.')) {
  47. tmpResult = tmpResult.toFixed(5)
  48. // 如果小数部分出现了多余的0,应该去掉(对结果精度没影响)
  49. tmpResult = parseFloat(tmpResult)
  50. }
  51. // 显示出结果
  52. result.value = tmpResult
  53. } catch {
  54. result.value = '错误'
  55. }
  56. break
  57. default:
  58. // 如果当前结果区显示有前导0,先清空, 防止出现前导0
  59. if (result.value == 0 || result.value == '错误') result.value = ''
  60. result.value += content
  61. }
  62. }
  63. /**
  64. * 知识点总结
  65. * 1. 事件代理
  66. * 2. eval()
  67. * 3. try-catch
  68. * 4. toFixed()
  69. */
  70. /**
  71. * 作业
  72. * 1. 处理除零错误
  73. * 2. 处理操作符位于表达式首位的错误
  74. */

完整代码附件:

calculator.zip大小:3KB
已经过安全软件检测无毒,请您放心下载。
本文地址:https://www.mainblog.cn/330.html
版权声明:本文为原创文章,版权归 阁主 所有,欢迎分享本文,转载请保留出处!
免责申明:有些内容源于网络,没能联系到作者。如侵犯到你的权益请告知,我们会尽快删除相关内容。

评论已关闭!