页面中使用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)
      // <iframe src="http://127.0.0.1:58056/3.html" class="box3" id="demo3"></iframe>
      console.log(iframe1.contentDocument)

      var info = iframe1.contentDocument.getElementById('info')
      console.log(info)
      // <h1 id="h222" style="color: yellow;">大家好,我是2.html页面</h1>

      info.style.color = 'yellow'
      // 是可以修改iframe中 id为info元素的文本颜色的
    }

  </script>
</body>

</html>

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. 在同源的情况下 ,例如我演示的示例,父页面和嵌套的 iframe 是可以互相操作的。
# 两个页面的地址
http://127.0.0.1:56741/1.html
http://127.0.0.1:56741/2.html

# 做了那些操作
1. 获取dom元素,修改颜色,添加事件

能够获取dom,那么就代表我们可以随意操作页面
  1. 操作dom的方法
# 父 操作 子iframe
iframe.contentDocument

# 子iframe 操作 父
window.parent.document
  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>

子传递父

<!-- 父页面 -->
<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. 主要是通过 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)
      // <iframe src="http://127.0.0.1:58056/3.html" class="box3" id="demo3"></iframe>
      console.log(iframe3.contentDocument)
      // null
    }
  </script>
</body>

子页面获取父页面

<body>
  <h1 id="h222">大家好,我是不同源的页面3</h1>
    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. 父页面无法操作子页面的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. 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 事件接受数据;

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lazy_tomato

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值