前端跨页面交互信息或传递信息都有这么几种方式,总有一个满足你的使用场景

同源页面通信:

方法:Broadcast Channel 【广播】

这个可以查看我另一篇文章有使用案例

同一来源的不同文档(在不同的窗口、选项卡、框架或 iframe 中)之间进行通信

// page1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>page1</title>
</head>
<body>
    <button onclick="sendMessage()">发广播</button>
    <button onclick="closeBroadcast()">关闭广播</button>
    <button onclick="openBroadcast()">开启广播</button>
</body>
</html>

<script>
    let bc = null;

    // 开启广播
    function openBroadcast() {
        console.log('开启广播');
        bc = new BroadcastChannel('cctv');

        // 接收广播
        bc.onmessage = function(e) {
            alert(e.data);
        };

        // 异常处理
        bc.onmessageerror = function(e) {
            console.warn('onmessageerror');
        };
    }
    openBroadcast();

    // 关闭广播
    function closeBroadcast() {
        console.log('关闭广播');
        bc.close();
    }

    // 发消息
    function sendMessage() {
        bc.postMessage('page1: 咯咯')
    }
</script>
// page2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>page2</title>
</head>
<body>
    <button onclick="sendMessage()">发广播</button>
    <button onclick="closeBroadcast()">关闭广播</button>
    <button onclick="openBroadcast()">开启广播</button>
</body>
</html>

<script>
    let bc = null;

    // 开启广播
    function openBroadcast() {
        console.log('开启广播');
        bc = new BroadcastChannel('cctv');

        // 接收广播
        bc.onmessage = function(e) {
            alert(e.data);
        };

        // 异常处理
        bc.onmessageerror = function(e) {
            console.warn('onmessageerror');
        };
    }
    openBroadcast();

    // 关闭广播
    function closeBroadcast() {
        console.log('关闭广播');
        bc.close();
    }

    // 发消息
    function sendMessage() {
        bc.postMessage('page2: 哒~')
    }
</script>

Service Worker 【广播】

// page1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>page1</title>
</head>
<body>
    <button onclick="sendMessage()">发广播</button>
    <p></p>
</body>
</html>

<script>
    navigator.serviceWorker.register('sw.js').then(function () {
        console.log('Service Worker 注册成功');
    })

    navigator.serviceWorker.addEventListener('message', function (e) {
        const { data } = e;

        // 过滤自己发送的消息
        if (data.from !== 'page1') {
            document.querySelector('p').innerText = `${data.from}:${data.data}`;
        }
    });

    function sendMessage() {
        const msg = {
            from: 'page1',
            data: '咯咯'
        }
        navigator.serviceWorker.controller.postMessage(msg);
    }
</script>
// page2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>page2</title>
</head>
<body>
    <button onclick="sendMessage()">发广播</button>
    <p></p>
</body>
</html>

<script>
    navigator.serviceWorker.register('sw.js').then(function () {
        console.log('Service Worker 注册成功');
    })

    navigator.serviceWorker.addEventListener('message', function (e) {
        const { data } = e;

        // 过滤自己发送的消息
        if (data.from !== 'page2') {
            document.querySelector('p').innerText = `${data.from}:${data.data}`;
        }
    });

    function sendMessage() {
        const msg = {
            from: 'page2',
            data: '哒~'
        }
        navigator.serviceWorker.controller.postMessage(msg);
    }
</script>
// sw.js

self.addEventListener('message', function (e) {
    console.log('service worker receive message', e.data);
    e.waitUntil(
        self.clients.matchAll().then(function (clients) {
            if (!clients || clients.length === 0) {
                return;
            }
            clients.forEach(function (client) {
                client.postMessage(e.data);
            });
        })
    );
});

localStorage 【共享存储 + 监听】

// page1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>page1</title>
</head>
<body>
    <button onclick="sendMessage()">发广播</button>
    <button onclick="closeBroadcast()">关闭广播</button>
    <button onclick="openBroadcast()">开启广播</button>
</body>
</html>

<script>
    function handleMessage(e) {
        if (e.key === 'localMessage') {
            const msg = JSON.parse(e.newValue);
            alert(msg.data);
        }
    }

    // 开启广播
    function openBroadcast() {
        console.log('开启广播');

        // 在当前页面setItem,storage事件不会触发,另外开个标签页,可以在另一个标签页中触发
        window.addEventListener('storage', handleMessage);
    }
    openBroadcast();

    // 关闭广播
    function closeBroadcast() {
        console.log('关闭广播');
        window.removeEventListener('storage', handleMessage)
    }

    // 发消息
    function sendMessage() {
        const msg = {
            data: 'page1: 咯咯',
            stamp: new Date()
        }

        // 设置相同的内容,storage不会触发,用时间戳解决
        window.localStorage.setItem('localMessage', JSON.stringify(msg));
    }
</script>
<!DOCTYPE html>
// page2

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>page2</title>
</head>
<body>
    <button onclick="sendMessage()">发广播</button>
    <button onclick="closeBroadcast()">关闭广播</button>
    <button onclick="openBroadcast()">开启广播</button>
</body>
</html>

<script>
    function handleMessage(e) {
        if (e.key === 'localMessage') {
            const msg = JSON.parse(e.newValue);
            alert(msg.data);
        }
    }

    // 开启广播
    function openBroadcast() {
        console.log('开启广播');

        // 在当前页面setItem,storage事件不会触发,另外开个标签页,可以在另一个标签页中触发
        window.addEventListener('storage', handleMessage);
    }
    openBroadcast();

    // 关闭广播
    function closeBroadcast() {
        console.log('关闭广播');
        window.removeEventListener('storage', handleMessage)
    }

    // 发消息
    function sendMessage() {
        const msg = {
            data: 'page2: 哒~',
            stamp: new Date()
        }

        // 设置相同的内容,storage不会触发,用时间戳解决
        window.localStorage.setItem('localMessage', JSON.stringify(msg));
    }
</script>

Shared Worker 【共享存储 + 轮询

无法主动通知,需要轮询获取最新数据

// page1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>page1</title>
</head>
<body>
<button onclick="sendMessage()">发广播</button>
<button onclick="closeBroadcast()">关闭广播</button>
<button onclick="openBroadcast()">开启广播</button>
</body>
</html>

<script>
    let worker = null;
    let timer = null;

    // 开启广播
    function openBroadcast() {
        console.log('开启广播');
        worker = new SharedWorker("sharedWorker.js", 'messageWorker'); // [https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorker/SharedWorker]

        // 定时轮询,发送 get 指令的消息
        timer = setInterval(function () {
            worker.port.postMessage({ get: true });
        }, 1000);

        // 监听 get 消息的返回数据
        worker.port.onmessage = function (e) {
            console.log(e.data);
        }
    }
    openBroadcast();

    function closeBroadcast() {
        console.log('关闭广播');
        clearInterval(timer);
    }

    // 发消息
    function sendMessage() {
        worker.port.postMessage('page1: 咯咯');
    }
</script>
// page2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>page2</title>
</head>
<body>
    <button onclick="sendMessage()">发广播</button>
    <button onclick="closeBroadcast()">关闭广播</button>
    <button onclick="openBroadcast()">开启广播</button>
</body>
</html>

<script>
    let worker = null;
    let timer = null;

    // 开启广播
    function openBroadcast() {
        console.log('开启广播');
        worker = new SharedWorker("sharedWorker.js", 'messageWorker'); // [https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorker/SharedWorker]

        // 定时轮询,发送 get 指令的消息
        timer = setInterval(function () {
            worker.port.postMessage({ get: true });
        }, 1000);

        // 监听 get 消息的返回数据
        worker.port.addEventListener('message', (e) => {
            console.log(e.data);
        }, false);

        // addEventListener监听时要手动开始,onmessage时不需要
        worker.port.start();
    }
    openBroadcast();

    function closeBroadcast() {
        console.log('关闭广播');
        clearInterval(timer);
    }

    // 发消息
    function sendMessage() {
        worker.port.postMessage('page2: 哒~');
    }
</script>
// sharedWorker.js
let data = null;

self.addEventListener('connect', function (e) {
    const port = e.ports[0];

    port.addEventListener('message', function (event) {
        // get 指令则返回存储的消息数据
        if (event.data.get) {
            data && port.postMessage(data);
        }
        // 非 get 指令则存储该消息数据
        else {
            data = event.data;
        }
    });

    port.start();
});

window.opener 【口口相传】

// page1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>page1</title>
</head>
<body>
    <button onclick="sendMessage()">发广播</button>
    <button onclick="closeBroadcast()">关闭广播</button>
    <button onclick="openBroadcast()">开启广播</button>
</body>
</html>

<script>
    let wins = []; // 记录打开的子窗口

    const openedWin = window.open('page2.html')
    wins.push(openedWin);

    // 发广播
    function sendMessage() {
        const openingWins = wins.filter(item => !item.closed); // 过滤已被关闭的页面

        // 向子级窗口发送消息
        if (openingWins.length) {
            const msg = {
                data: 'page1: 咯咯',
                upMsg: false,         // 是否向上级窗口发送的消息
            }

            openingWins.forEach(item => item.postMessage(msg))
        }

        // 有父级窗口,向父级窗口发消息
        if (window.opener && !window.opener.closed) {
            const msg = {
                data: 'page1: 咯咯',
                upMsg: true,         // 是否向上级窗口发送的消息
            }

            window.opener.postMessage(msg);
        }
    }

    // 开启广播
    function openBroadcast() {
        window.addEventListener('message', function (e) {
            const { data, upMsg } = e.data;
            alert(data);

            // 收到向上传递的消息,有父级窗口,继续向上传递
            if (window.opener && !window.opener.closed && upMsg) {
                window.opener.postMessage(e.data);
            }

            const openingWins = wins.filter(item => !item.closed); // 过滤已被关闭的页面

            // 收到向下传递的消息,有子级窗口,继续向下传递
            if (openingWins.length && !upMsg) {
                openingWins.forEach(item => item.postMessage(e.data))
            }
        });
    }
    openBroadcast()

    // 关闭广播
    function closeBroadcast() {
        // TODO
    }
</script>
// page2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>page2</title>
</head>
<body>
    <button onclick="sendMessage()">发广播</button>
    <button onclick="closeBroadcast()">关闭广播</button>
    <button onclick="openBroadcast()">开启广播</button>
</body>
</html>

<script>
    let wins = []; // 记录打开的子窗口

    const openedWin = window.open('page3.html')
    wins.push(openedWin);

    // 发广播
    function sendMessage() {
        const openingWins = wins.filter(item => !item.closed); // 过滤已被关闭的页面

        // 向子级窗口发送消息
        if (openingWins.length) {
            const msg = {
                data: 'page2: 咯咯',
                upMsg: false,         // 是否向上级窗口发送的消息
            }

            openingWins.forEach(item => item.postMessage(msg))
        }

        // 有父级窗口,向父级窗口发消息
        if (window.opener && !window.opener.closed) {
            const msg = {
                data: 'page2: 咯咯',
                upMsg: true,         // 是否向上级窗口发送的消息
            }

            window.opener.postMessage(msg);
        }
    }

    function openBroadcast() {
        window.addEventListener('message', function (e) {
            const { data, upMsg } = e.data;
            alert(data);


            // 收到向上传递的消息,有父级窗口,继续向上传递
            if (window.opener && !window.opener.closed && upMsg) {
                window.opener.postMessage(e.data);
            }

            const openingWins = wins.filter(item => !item.closed); // 过滤已被关闭的页面

            // 收到向下传递的消息,有子级窗口,继续向下传递
            if (openingWins.length && !upMsg) {
                openingWins.forEach(item => item.postMessage(e.data))
            }
        });
    }
    openBroadcast()

    // 关闭广播
    function closeBroadcast() {
        // TODO
    }
</script>
// page3

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>page3</title>
</head>
<body>
    <button onclick="sendMessage()">发广播</button>
    <button onclick="closeBroadcast()">关闭广播</button>
    <button onclick="openBroadcast()">开启广播</button>
</body>
</html>

<script>
    let wins = []; // 记录打开的子窗口

    // 发广播
    function sendMessage() {
        const openingWins = wins.filter(item => !item.closed); // 过滤已被关闭的页面

        // 向子级窗口发送消息
        if (openingWins.length) {
            const msg = {
                data: 'page3: 咯咯',
                upMsg: false,         // 是否向上级窗口发送的消息
            }

            openingWins.forEach(item => item.postMessage(msg))
        }

        // 有父级窗口,向父级窗口发消息
        if (window.opener && !window.opener.closed) {
            const msg = {
                data: 'page3: 咯咯',
                upMsg: true,         // 是否向上级窗口发送的消息
            }

            window.opener.postMessage(msg);
        }
    }

    function openBroadcast() {
        window.addEventListener('message', function (e) {
            const { data, upMsg } = e.data;
            alert(data);

            // 收到向上传递的消息,有父级窗口,继续向上传递
            if (window.opener && !window.opener.closed && upMsg) {
                window.opener.postMessage(e.data);
            }

            const openingWins = wins.filter(item => !item.closed); // 过滤已被关闭的页面

            // 收到向下传递的消息,有子级窗口,继续向下传递
            if (openingWins.length && !upMsg) {
                openingWins.forEach(item => item.postMessage(e.data))
            }
        });
    }
    openBroadcast()

    // 关闭广播
    function closeBroadcast() {
        // TODO
    }
</script>

非同源页面通信

iframe 【代理】
父A = 非同源应用A (e.g. http://localhost:63342/demo/iframe/page1.html)
子A = 非同源iframe桥(e.g. http://localhost:8081/)

父B = 非同源应用B (e.g. http://192.168.2.112:3000/)
子B = 非同源iframe桥 (e.g. http://localhost:8081/)

1. 所有消息都先发给iframe桥

const bridgeIframe = document.getElementById('bridgeIframe');
const msg = {
    type: 'bridge-msg',
    data: 'page1: 咯咯'
};
bridgeIframe.contentWindow.postMessage(msg, '*');
// window.frames[0].window.postMessage(msg, '*');

2. iframe接收后发起同源广播,同源广播可以在另一个应用中监听

// 接收iframe消息
window.addEventListener('message', (e) => {
  const { data } = e;

  // 转发消息,消息会进入另一个跨域应用的iframe桥的bc.onmessage中
  if (data.type === 'bridge-msg') {
    this.bc.postMessage(`${data.data}`)
  }
});

3. iframe通过窗口对象转发消息

window.parent.postMessage(e.data, '*');

完整代码:

// page1 纯html页面,webstorm服务器运行

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>page1</title>
</head>
<body>
    <span></span>

    <button onclick="sendMessage()">发广播</button>
</body>
</html>

<script>

    // 发消息
    function sendMessage() {
        const bridgeIframe = document.getElementById('bridgeIframe');
        const msg = {
            type: 'bridge-msg',
            data: '咯咯'
        };
        bridgeIframe.contentWindow.postMessage(msg, '*');
    }

    // 创建桥梁
    function createBridge() {
        const bridgeIframe = document.createElement('iframe');
        bridgeIframe.setAttribute('id', 'bridgeIframe');
        // bridgeIframe.style.display = 'none';
        bridgeIframe.src = 'http://localhost:8081/';
        document.body.appendChild(bridgeIframe);
    }
    createBridge();

    // 监听iframe桥发来的消息
    window.addEventListener('message', function(e) {
        const { data, origin } = e;
        document.querySelector('span').innerText = `${origin}: ${data}`;
    });
</script>
// bridgeIframe Vue2应用 http://localhost:8081/

<button @click="sendMessage">发广播</button>

<script>
  export default {
    name: 'App',
    data() {
      return {
        bc: null,
      }
    },
    methods: {
      // 开启广播
      openBroadcast() {
        this.bc = new BroadcastChannel('cctv');
  
        // 接收广播
        // bc广播是同源广播,因为两个跨域应用
        this.bc.onmessage = (e) => {
          console.log(`iframe桥接收到的消息:${e.data}`);
          window.parent.postMessage(e.data, '*');
        };
  
        // 异常处理
        this.bc.onmessageerror = function(e) {
          console.warn('onmessageerror');
        };
      }
    },
    mounted() {
      this.openBroadcast();
  
      // 接收iframe消息
      window.addEventListener('message', (e) => {
        const { data } = e;
  
        // 转发消息,消息会进入另一个跨域应用的iframe桥的bc.onmessage中
        if (data.type === 'bridge-msg') {
          this.bc.postMessage(`${data.data}`)
        }
      });
    }
  }
</script>
// page2 React应用 http://192.168.2.112:3000

import './App.css';
import { useEffect, useState } from "react";

function App() {
    const [msg, setMsg] = useState('');

    useEffect(() => {
        createBridge();

        // 监听iframe桥发来的消息
        window.addEventListener('message', function (e) {
            const { data, origin } = e;
            setMsg(`${origin}: ${data}`);
        });
    }, [])


    // 创建桥梁
    const createBridge = () => {
        const bridgeIframe = document.createElement('iframe');
        bridgeIframe.setAttribute('id', 'bridgeIframe');
        // bridgeIframe.style.display = 'none';
        bridgeIframe.src = 'http://localhost:8081/';
        document.body.appendChild(bridgeIframe);
    }

    // 发消息
    const sendMessage = () => {
        const bridgeIframe = document.getElementById('bridgeIframe');
        const msg = {
            type: 'bridge-msg',
            data: '哒~'
        };
        bridgeIframe.contentWindow.postMessage(msg, '*');
    }

  return (
    <div className="App">
        { msg }

        <button onClick={sendMessage}>发广播</button>
    </div>
  );
}

export default App;

参考文章:面试官:前端跨页面通信,你知道哪些方法? - 掘金

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Django 通常使用模板语言来与前端交互。模板语言是一种特殊的语法,用来结合 Django 的后端数据和 HTML 代码。Django 的模板系统允许你使用变量、标签和过滤器在模板中渲染数据。 例如,你可以在模板中使用如下语法来显示一个变量的值: ``` {{ variable }} ``` 你也可以使用标签来执行一些特殊的操作,比如循环或条件判断: ``` {% for item in items %} {{ item }} {% endfor %} ``` 最后,你可以使用过滤器来对变量做一些额外的处理,比如将变量转化为大写或者首字母大写: ``` {{ variable|upper }} {{ variable|capitalize }} ``` 在模板渲染完成后,Django 会将结果发送给浏览器,从而实现与前端交互。 ### 回答2: Django是一个高效的Python Web框架,也是一个服务器端框架,它与前端交互主要通过以下几种方式: 1. 封装模板引擎:Django内置了强大的模板引擎,可以将前端HTML页面与后端逻辑代码进行分离,实现前后端的交互。通过在模板中使用Django提供的模板标签和变量,可以将后端数据传递前端页面中,完成数据的渲染和展示。 2. 提供RESTful API:Django可以使用Django REST framework来构建RESTful API,通过API可以实现前后端之间的数据交互和通信。前端可以通过发送HTTP请求来调用后端的API,获取数据或进行其他操作,后端则根据请求的方式和参数返回相应的数据。 3. 使用 Ajax 技术:Ajax是一种前端的技术,可以通过在前端页面使用JavaScript发送异步请求,与后端进行数据交互。在Django中,可以通过定义视图函数来处理Ajax请求,并返回相应的数据,前端可以通过JavaScript的回调函数来处理返回的数据,并进行页面更新或其他操作。 4. WebSocket通信:Django可以使用第三方库来实现WebSocket通信,实现实时的双向数据传输。WebSocket可以在前后端之间建立持久性连接,实现实时通信和数据更新。通过在Django中创建WebSocket视图和处理器,前端可以使用WebSocket API与后端进行通信,并实现实时数据更新和推送。 总的来说,Django与前端交互方式有很多种,可以根据具体的需求和场景选择适合的方式进行交互,从而实现前后端的数据传递和通信。 ### 回答3: Django是一个基于Python的Web框架,它可以与前端进行交互以实现动态网页的开发。 首先,Django通过使用模板语言实现与前端交互。模板语言允许将动态数据插入到HTML模板中,从而生成最终的网页。在Django中,我们可以使用模板引擎来处理模板,通过标签和过滤器来操作模板中的数据,将数据传递前端页面。 其次,Django提供了强大的视图功能来处理前端请求。我们可以定义视图函数,它们负责接收前端的请求并返回相应的数据。视图函数可以处理GET和POST等不同类型的请求,根据请求的类型和参数进行相应的操作,并将结果返回给前端页面使用Django的路由系统,我们可以将请求的URL地址与相应的视图函数进行绑定,从而实现请求的分发和处理。 另外,Django还提供了表单功能来处理前端的用户输入。我们可以定义表单类来描述前端页面上的输入字段,并通过视图函数对表单数据进行验证和处理。Django的表单功能提供了丰富的验证选项,可以轻松地检查用户输入的有效性,并将错误信息返回给前端页面。 最后,Django还可以与前端进行异步交互,实现前后端的数据传输和更新。通过使用Django的视图函数和前端的JavaScript代码,我们可以实现异步请求和响应处理,从而实现更加流畅和交互性的用户体验。 综上所述,Django通过模板语言、视图函数、表单功能和异步交互方式前端进行交互,实现了动态网页的开发。这些功能使得开发者能够灵活地处理并响应前端的请求,从而实现了良好的用户体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

柑橘乌云_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值