博客列表 >front 20 跨域请求(jsonp)-事件冒泡-事件代理 (0814fri)

front 20 跨域请求(jsonp)-事件冒泡-事件代理 (0814fri)

老黑
老黑原创
2020年08月22日 15:23:06578浏览

主要内容:

  1. 跨域请求(广义、getCORS、JSONP)
  2. classList方法操作元素属性
  3. 自定义data属性
  4. 事件冒泡
  5. 事件代理(委托)

1. 跨域请求的基本知识

1-1. 背景知识

  • 跨域:跨越不同的域名/网站的访问资源
  • 我们主要是学习如何通过 js 脚本发起一个跨域请求
  • 为了网站的安全,默认是禁止通过 js 脚本发起跨域请求,但可以进行伪装之类的。
  • 同源策略: 保护网站的最基本的一道安全防线

1-2. 跨域资源

  • CORS: 跨域资源共享
  • CSRF: 跨站请求伪造

1-3. 同源策略

  • 页面 URL 中的三要素完全相同,就认为同源
    • 协议(http/https/ftp/…)相同
    • 域名(domain)相同
    • 端口(port)相同
  1. - 同源
  2. http://php.cn:80/course/1088.html
  3. http://php.cn:80/wenda/18.html
  4. - 非同源,协议不同
  5. https://php.cn:80/wenda/18.html
  6. - 非同源,域名主机
  7. https://php88.cn:80/wenda/18.html
  8. - 非同源,端口不同
  9. http://php.cn:9098/abc.html

2. 广义的跨域请求,通过html标签发起

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <!-- <link rel="stylesheet" href="cdn...">
  7. <script src="cdn..."></script> -->
  8. <title>广义上的跨域请求,通过html标签发起的</title>
  9. </head>
  10. <body>
  11. <!-- 当前该请求所在的页面的域名是: http://front.edu/ -->
  12. <!-- 要访问资源所在的目标站点域名是:https://www.php.cn/ -->
  13. <!-- 这就是一个最简单的跨域访问 -->
  14. <a href="https://www.php.cn/">访问php中文网</a>
  15. <!-- img完成了一个跨域请求,请求另外一个域名站点中的一张图片 -->
  16. <img src="https://img.php.cn/upload/course/000/000/001/5f36339d51421830.png" alt="">
  17. </body>
  18. </html>

3. 通过CORS发起跨域请求

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>跨域请求之-跨域资源共享-CORS</title>
  7. </head>
  8. <body>
  9. <button>跨域请求-CORS</button>
  10. <h2></h2>
  11. <script>
  12. var btn = document.querySelector("button");
  13. btn.addEventListener("click", getData, false);
  14. // 1. 创建ajax对象
  15. var xhr = new XMLHttpRequest();
  16. // 之前这个更多是放到function中,但这次因为是两个function调用,因此就放出来,放到公共空间中。
  17. function getData() {
  18. // 2. 监听请求
  19. xhr.addEventListener("readystatechange", getCORS, false);
  20. // 3. 配置参数
  21. xhr.open("get", "http://php.io/test1.php", true);
  22. // 4. 发送请求
  23. xhr.send(null);
  24. }
  25. function getCORS() {
  26. if (xhr.readyState === 4 && xhr.status === 200) {
  27. console.log(xhr.responseText);
  28. document.querySelector("h2").innerHTML = xhr.responseText;
  29. }
  30. }
  31. </script>
  32. </body>
  33. </html>

4. 通过jsonp来发起跨域请求

  • 基本过程逻辑
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>jsonp的背景知识</title>
  7. </head>
  8. <body>
  9. <h3>jsonp的背景知识</h3>
  10. <script>
  11. // 动态生成script标签,并加载一个外部的js文档
  12. // 1. 生成一个script元素
  13. var script = document.createElement("script");
  14. // 可选
  15. script.type = "text/javascript";
  16. // 2. 添加src,指定外部请求的文档资源。这个地方可以是js,也可以是txt,也可以是下面的带回调的php。
  17. // 没报这个CORS错误,说明其他类型的文件都可以访问
  18. script.src = "http://php.io/test1.php?id=2&jsonp=回调handle";
  19. // 3. 把script元素添加到文档(页面中)
  20. document.head.appendChild(script);
  21. // 此时通过script标签发起一个跨域请求,轻松的绕过了同源策略的限制
  22. function handle() {
  23. //...
  24. }
  25. // 这行函数的调用代码必须要在服务器脚本上生成,以字符串方式返回
  26. handle(data);
  27. </script>
  28. </body>
  29. </html>
  • 上面调取的是php_io下的test1.php文件
  1. <?php
  2. // header('Access-Control-Allow-Origin:http://front.edu');
  3. // 请资源开放给所有的请求
  4. header('Access-Control-Allow-Origin:*');
  5. // 允许以后带着cookie发起请求
  6. // header('Access-Control-Allow-Origin:true');
  7. echo '跨域脚本返回的数据';
  8. // 下面这行是用来刷新缓存的。
  9. flush();

  • demo4.html的演示
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>跨域请求-JSONP</title>
  7. </head>
  8. <body>
  9. <button>跨域请求-JSONP</button>
  10. <script>
  11. var btn = document.querySelector("button");
  12. btn.addEventListener("click", function () {
  13. // 动态生成script标签,发起jsonp请求
  14. var script = document.createElement("script");
  15. // url中的最后一个键值对,必须是一个回调,需要跟test2.php中的名称一致(jsonp,但也可以是其他名字)
  16. script.src = "http://php.io/test2.php?id=3&jsonp=handle";
  17. // 这块是将外部请求生成的js内容放到什么位置。这个地方是放到了head下,其他地方也可以放。
  18. document.head.appendChild(script);
  19. });
  20. // 从php中拿到信息后进行解析,并渲染到前端去。
  21. // 这个地方的handle必须和上面的script.src最后一致。
  22. function handle(data) {
  23. // console.log(data);
  24. var obj = JSON.parse(data);
  25. console.log(obj);
  26. var ul = document.createElement("ul");
  27. ul.innerHTML += "<li>" + obj.title + "</li>";
  28. ul.innerHTML += "<li>" + obj.user.name + "</li>";
  29. ul.innerHTML += "<li>" + obj.user.email + "</li>";
  30. document.body.appendChild(ul);
  31. }
  32. </script>
  33. </body>
  34. </html>
  • 调取的是test2.php
  1. <?php
  2. header('content-type:text/html;charset=utf-8');
  3. // 因为js只支持utf-8,因此这个地方需要确定下,尽管默认也是utf-8。
  4. http://php.io/test2.php?id=2&jsonp=handle
  5. // id: 查询参数,这是可选。
  6. $id = $_GET['id'];
  7. // 前端的回调函数的名称[必选],
  8. // 这个地方的jsonp也可以是其他名字,只要跟demo4中url最后一个参数名字保持一致即可。
  9. // callback在下面最后再将一些内容传递回去,给到demo4.html中的handle去处理。
  10. $callback = $_GET['jsonp'];
  11. // 模拟接口数据,根据查询条件返回不同的值
  12. // 这个数组有三个元素,每个元素是字符串,字符串的内容是json格式的数据
  13. $users = [
  14. 0=>'{"name":"朱老师", "email":"peter@php.cn"}',
  15. 1=>'{"name":"西门老师", "email":"xm@php.cn"}',
  16. 2=>'{"name":"猪哥", "email":"pig@php.cn"}'
  17. ];
  18. if (array_key_exists(($id-1), $users)) {
  19. // 查询结果保存到变量$user中
  20. $user = $users[$id-1];
  21. }
  22. // 返回前端给回调的参数是一个json格式的数据
  23. $json = '{
  24. "title": "用户信息表",
  25. "user": ' . $user . '
  26. }';
  27. // 生成js函数的调用语句
  28. echo $callback .' (' . json_encode($json) . ')';

5. classList对象

  • 通过classList来控制属性的格式变化
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>classList对象</title>
  7. <style>
  8. .red {
  9. color: red;
  10. }
  11. .bgc {
  12. background-color: yellow;
  13. }
  14. .blue {
  15. color: green;
  16. }
  17. </style>
  18. </head>
  19. <body>
  20. <p class="red">大家晚上好</p>
  21. <h3>classList对象你会了吗?</h3>
  22. <script>
  23. // classList: 操作class中的内容
  24. var h3 = document.querySelector("h3");
  25. h3.className = "red";
  26. // h3.className = "red bgc";
  27. // 添加样式
  28. // h3.classList.add("red");
  29. // h3.classList.add("bgc");
  30. // 移除样式
  31. // h3.classList.remove("bgc");
  32. // 切换样式
  33. // h3.classList.toggle("red");
  34. // 替换样式
  35. h3.classList.replace("red", "blue");
  36. </script>
  37. </body>
  38. </html>

6. 自定义数据属性

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>自定义数据属性</title>
  7. </head>
  8. <body>
  9. <div
  10. id="user"
  11. data-id="110"
  12. data-user-name="peter"
  13. data-email="peter@php.cn"
  14. >
  15. 用户信息
  16. </div>
  17. <script>
  18. // dataset对象用于获取自定义数据属性的内容
  19. // 自定义数据属性必须以data-为前缀
  20. var user = document.getElementById("user");
  21. // dataset获取data-的数据属性内容时,必须省略data-
  22. console.log(user.dataset.id);
  23. console.log(user.dataset.userName);
  24. // 这个地方的userName,而不是上面的-user-name,这种格式要注意。
  25. console.log(user.dataset.email);
  26. </script>
  27. </body>
  28. </html>

7. 事件:事件监听与派发(addEventListener,dispatchEvent)

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>事件</title>
  7. </head>
  8. <body>
  9. <button>点击广告</button>
  10. <script>
  11. // 获取按钮
  12. var btn = document.querySelector("button");
  13. // 事件监听
  14. btn.addEventListener("click", function () {
  15. console.log("广告被点击了");
  16. });
  17. // 事件派发:每0.1秒点击一次
  18. setInterval(function () {
  19. var event = new Event("click");
  20. btn.dispatchEvent(event);
  21. }, 100);
  22. </script>
  23. </body>
  24. </html>

8. 事件冒泡

  • 一个元素的事件,其实也是发生在其父级上面的事件
  • 因此可以不断向上“冒泡”
  • 区分ev.target(事件对象)和ev.currentTarget(当前对象)
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>事件冒泡</title>
  7. </head>
  8. <body>
  9. <ul>
  10. <li>item1</li>
  11. <li>item2</li>
  12. <li>item3</li>
  13. <li>item4</li>
  14. <li>item5</li>
  15. </ul>
  16. <script>
  17. // 给所有的li添加一个点击事件
  18. var lis = document.querySelectorAll("li");
  19. for (var i = 0; i < lis.length; i++) {
  20. lis[i].addEventListener("click", function (ev) {
  21. // ev.target: 触发事件的元素
  22. // console.log(ev.target);
  23. // ev.currentTarget: 绑定事件的元素
  24. console.log(ev.currentTarget);
  25. });
  26. }
  27. // 给li的父元素ul也添加点击事件
  28. document.querySelector("ul").addEventListener("click", function (ev) {
  29. // ev.target: 触发事件的元素
  30. // console.log(ev.target);
  31. // ev.currentTarget: 绑定事件的元素
  32. console.log(ev.currentTarget);
  33. });
  34. // ul的父级body也添加点击事件
  35. document.body.addEventListener("click", function (ev) {
  36. // ev.target: 触发事件的元素
  37. // console.log(ev.target);
  38. // ev.currentTarget: 绑定事件的元素
  39. console.log(ev.currentTarget);
  40. });
  41. // 根元素
  42. document.documentElement.addEventListener("click", function (ev) {
  43. // ev.target: 触发事件的元素
  44. // console.log(ev.target);
  45. // ev.currentTarget: 绑定事件的元素
  46. console.log(ev.currentTarget);
  47. });
  48. </script>
  49. </body>
  50. </html>

9. 事件委托(代理)

  • 基于的正是事件冒泡的原理,由父级直接来接收、代理子级的事件
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>事件委托/代理</title>
  7. </head>
  8. <body>
  9. <ul>
  10. <li>item1</li>
  11. <li>item2</li>
  12. <li>item3</li>
  13. <li>item4</li>
  14. <li>item5</li>
  15. </ul>
  16. <script>
  17. //根据事件冒泡的原理,当前子元素的事件,必然会冒泡到父级上的同名事件上
  18. // 此时,只需要给所有的li的父级ul添加点击事件就可以
  19. document.querySelector("ul").addEventListener("click", function (ev) {
  20. // ev.target: 触发事件的元素, <li>
  21. console.log(ev.target);
  22. // ev.currentTarget: 绑定事件的元素, <ul>
  23. console.log(ev.currentTarget);
  24. });
  25. </script>
  26. </body>
  27. </html>

10. 作业 (这块在自己的pm中已经实现,具体见pm中的index.php)

  1. 写一个jsonp的实现案例,根据id获取商品信息
  2. 写一个事件代理的案例(自定义)
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议