• 页面中使用iframe


    start

    • 任务需要:希望父页面中嵌入 iframe 页面,但是在此之前对 iframe了解不够深入,让我们今天来研究一下 iframe ;

    思路

    iframe 首要的区分就是 是否同源,我就以同源和不同源两种情况去分析,页面和iframe 之间的交互和通信。

    1. 同源的iframe

    调试方式说明

    为了方便本地调试,我使用了Vscode的插件 live Server,来启动本地的静态服务。此静态服务包含 协议+ip+端口;

    例如:http://127.0.0.1:56741/2.html

    然后不同服务可以理解为不同源的页面,同一服务可以理解为同源的页面,以此来方便测试。

    当然除了 live Server这种方案,使用webpack等依赖实现静态服务也是OK的,有能力可自行实现

    1.1 正常交互

    1.html

    DOCTYPE html>
    <html lang="en">
    
    <head>
      <style>
        .iframe1 {
          background: pink;
        }
      style>
    head>
    
    <body>
    
      我是主页面1.html,主页面引入一个同源的 2.html
    
      <button id="btn">点我弹出消息button>
      <br>
      <iframe src="http://127.0.0.1:56741/2.html" class="iframe1" id="iframe1">iframe>
    
      <script>
        window.onload = function () {
          var iframe1 = document.getElementById('iframe1')
          console.log(iframe1)
          // 
          console.log(iframe1.contentDocument)
    
          var info = iframe1.contentDocument.getElementById('info')
          console.log(info)
          // 

    大家好,我是2.html页面

    info.style.color = 'yellow' // 是可以修改iframe中 id为info元素的文本颜色的 }
    script> body> html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    2.html

    DOCTYPE html>
    <html lang="en">
    
    <head>
    head>
    
    <body>
    
      <h1 id="info">大家好,我是2.html页面h1>
    
      <script>
        window.onload = function () {
          // 借助 window.parent,可以操作父页面。例如我这里给父页面的按钮添加一个点击事件
          var btn = window.parent.document.getElementById('btn')
    
          btn.addEventListener('click', function () {
            alert('子页面给父页面添加点击事件')
          })
        }
      script>
    
    body>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述

    总结

    1. 在同源的情况下 ,例如我演示的示例,父页面和嵌套的 iframe 是可以互相操作的。
    # 两个页面的地址
    http://127.0.0.1:56741/1.html
    http://127.0.0.1:56741/2.html
    
    # 做了那些操作
    1. 获取dom元素,修改颜色,添加事件
    
    能够获取dom,那么就代表我们可以随意操作页面
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. 操作dom的方法
    # 父 操作 子iframe
    iframe.contentDocument
    
    # 子iframe 操作 父
    window.parent.document
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 其他注意事项:

      注意一下,需要添加一个 window.onload事件,切记

    1.2 通信

    通信最常见的通信就是 postmessage,写个示例:

    父传子

    
    <body>
    
      我是主页面1.html,主页面引入一个同源的 2.html
      <br>
      <iframe src="http://127.0.0.1:56741/2.html" class="iframe1" id="iframe1">iframe>
    
      <script>
        const msg = {
          name: "A"
        }
        window.onload = () => {
          // 自动调用必须放在onload中,通过事件调用则不用
          let frame = document.querySelector("#iframe1").contentWindow
          frame.postMessage("父传子--番茄", "http://127.0.0.1:56741")
        }
      script>
    body>
    
    
    <body>
      <h1 id="info">大家好,我是2.html页面h1>
      <script>
        window.onload = function () {
          window.addEventListener("message", (e) => {
            console.log(e.data)
            // 父传子--番茄
          })
        }
      script>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    子传递父

    
    <body>
      我是主页面1.html,主页面引入一个同源的 2.html
      <br>
      <iframe src="http://127.0.0.1:56741/2.html" class="iframe1" id="iframe1">iframe>
    
      <script>
        window.onload = function () {
    
          // 给window加一个监听事件,监听message
          window.addEventListener('message', (e) => {
            console.log('message', e)
          })
        }
      script>
    body>
    
    
    <body>
      <h1 id="info">大家好,我是2.html页面h1>
      <button id="sonBtn">点我给父页面发消息button>
    
      <script>
        window.onload = function () {
          document.getElementById('sonBtn').onclick = function () {
            console.log('开始发送')
            // 1.通过 contentWindow,发送消息`我是小番茄`  给 http://127.0.0.1:56741
            window.top.postMessage('我是小番茄', 'http://127.0.0.1:56741')
          }
        }
      script>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    总结

    1. 主要是通过 window上的 postMessage 方法发送数据,另一个页面监听 message 事件即可;
    2. postMessage 参数主要有两个,一个是需要发送的信息(建议是字符串兼容性较好),一个是目标地址;
    3. 生产环境需要考虑安全性,在 message 事件中,需要判断消息来源的地址;

    2. 不同源的iframe

    2.1 正常交互

    父页面获取子页面

    <body>
      我是主页面1.html,
      http://127.0.0.1:56741/1.html
    
    
      <button id="btn">点我弹出消息button>
      <br>
      <iframe src="http://127.0.0.1:58056/3.html" class="iframe3" id="iframe3">iframe>
    
      <script>
        window.onload = function () {
          var iframe3 = document.getElementById('iframe3')
          console.log(iframe3)
          // 
          console.log(iframe3.contentDocument)
          // null
        }
      script>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    子页面获取父页面

    <body>
      <h1 id="h222">大家好,我是不同源的页面3h1>
        http://127.0.0.1:58056/3.html
    
      <script>
        window.onload = function () {
          console.log(window.parent.document)
          /* 
          3.html:16 Uncaught DOMException: Blocked a frame with origin "http://127.0.0.1:58056" from accessing a cross-origin frame.
        at window.onload (http://127.0.0.1:58056/3.html:16:33)
          */
          
        }
    
      script>
    
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    总结:
    1. 父页面无法操作子页面的dom,获取的时候直接返回 null;
    2. 子页面无法获取父页面,获取的时候直接报错;

    2.2 通信

    
      <body>
    
        我是主页面1.html(http://127.0.0.1:56741),主页面引入一个不同源的 3.html
        <br>
        <iframe src="http://127.0.0.1:58056/3.html" class="iframe3" id="iframe3">iframe>
    
        <script>
          window.onload = () => {
            // 自动调用必须放在onload中,通过事件调用则不用
            let frame = document.querySelector("#iframe3").contentWindow
            frame.postMessage("父传子--番茄333", "http://127.0.0.1:58056 ")
          }
        script>
      body>
    
      
    
      <body>
        <h1 id="info">大家好,我是2.html页面h1>
        <script>
          window.onload = function () {
            window.addEventListener("message", (e) => {
              console.log(e.data)
              // 父传子--番茄333
            })
          }
        script>
      body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    总结:
    1. postMessage可以跨域通信

    3. 其他问题的思考

    问题一:页面中的 iframe 的内容可以随意操作吗?

    答:可以,例如按钮之类的页面完全是允许自由操作的。

    问题二:页面中的 iframe 的页面跳转到其他页面会如何

    答:例如:父页面 A 中有一个 iframe 指向同源的 B 页面,A页面可以获取到 B页面的dom。但是当 B 页面利用例如 location.href = 'https://www.baidu.com' 跳转到百度等页面,在A页面就无法获取B页面的dom了。

    4.兼容性

    兼容性考虑:

    https://caniuse.com/?search=postMessage

    在这里插入图片描述

    总结:

    综上所述:

    1. 最优解是同源的情况,可以直接操作 dom,可以不借助 postMessage 直接通信。

    2. 如果不同源,可以通过 postMessage,传递消息。但是需要在 iframe 中添加代码主动发送消息,外层页面监听 message 事件接受数据;

  • 相关阅读:
    PyTorch笔记 - LSTM(Long Short-Term Memory) 和 LSTMP(Projection)
    2.9每日一题(定积分的奇偶性以及比较大小)
    使用 python 检测泛洪攻击的案例
    ENSP实验-实现不同VLAN间互访的两种方式
    GRACE球谐数据滤波处理(利用matlab实现GRACE月水储量的二维傅里叶变化滤波)
    【11】二进制编码:“手持两把锟斤拷,口中疾呼烫烫烫”?
    基于Qt4的电机连续性测试软件开发
    Redis学习总结(三)
    Python爬虫(三)
    《Nature》论文插图的Matlab复刻第2期—单组多色横向柱状图(Part1-305)
  • 原文地址:https://blog.csdn.net/wswq2505655377/article/details/126645570