本人在做websockect同步的项目积累了一些经验,整理出来即是方便自己日后查看,也可以分享给大家一起讨论学习,很多出代码都是要记一下的,所以下面贴代码可能会比较多。本文主要内容包含了一下技术点:
- iframe注入脚本
- iframe与父级页面的交互
- 鼠标事件转发原理
- 在express中使用sockect.io库配合前端交互
下面一个一个的来
1. iframe注入脚本
//通过代码动态创建一个iframe
let myFrame = document.createElement('iframe')
setProps(frame, {
id: frameId,
src: "www.baidu.com", // 设置iframe加载的页面,不可跨域
scrolling: 'no', // 禁用滚动条
frameborder: '0', // 禁用边框
width:'' + scaleW, // 根据情况适当缩放
height: '' + scaleH,
class: someCondition ? 'frame-class1' : 'frame-class2'
})
document.body.appendChild(myFrame)
frame.onload = function (e) {
var insertJsTag = frame.contentDocument.createElement('script');
insertJsTag.setAttribute('src', "https://mycdn.com/xxx.js")
var jqTag = frame.contentDocument.createElement('script'); // 插入jquery库
jqTag.setAttribute('src', "https://mycdn.com/jquery.min.js")
var styleTag = frame.contentDocument.createElement('style');
styleTag.innerText = 'body{ overflow: hidden !important }'
frame.contentDocument.body.appendChild(jqTag);
frame.contentDocument.body.appendChild(insertJsTag);
frame.contentDocument.body.appendChild(styleTag);
}
function setProps(element, props){
if(!element) return;
for (const key in props) {
if (props.hasOwnProperty(key)) {
const prop = props[key];
element.setAttribute(key, prop);
}
}
}
2. iframe与父级页面的交互
页面之间的信息交流主要通过拿到目标的window对象,然后调用postMessage实现的:
// 发送方
function postMessageToFrame(frameId,messageStr) {
var frame = getFrameId(frameId);
if (Object.prototype.toString.call(message) != '[object String]') message = JSON.stringify(message);
/* 在子窗口中通过window.parent拿到父级窗口的window对象
* 比如 window.parent.postMessage(JSON.stringify(messageObj), "*")
* postMessage第二个参数是目标iframe的origin,如果不对应,则无法介绍到消息
*/
frame.contentWindow.postMessage(messageStr, location.origin); //
}
// 接收方:
window.addEventListener('message', function (e) {
if (!e.data) return;
var msg = JSON.parse(e.data)
switch (msg.method) {
case 'action':
handleFrameAction(msg);
break;
case 'onpage':
user.page = msg.page;
break;
default: // do something
}
});
3. 鼠标事件转发原理
鼠标事件转发主要解决了两个问题: 1. 事件发生元素转化成位派发生成事件的元素 2. 事件生成与派发。 第一点其实详细说就是,要在转发页面和起始鼠标事件产生页面选中同一个对应的元素,这样,我们在对应的元素上派发对应的事件,以达到产生相同鼠标事件效果的目的。这里通过使用jquery来生成元素的选择器字符串,传递到目标页面 然后找到对应的元素:
function makeSelector(el) {
var tag, index, stack = [];
for (; el.parentNode; el = el.parentNode) {
tag = el.tagName;
if (tag != "HTML") {
index = $(el).prevAll().length + 1;
if (tag == "BODY") {
stack.unshift(tag);
} else {
stack.unshift(tag + ':nth-child(' + index + ')');
}
}
}
return stack.join(' > ');
}
// 找到对应元素
document.querySelector(selectorStr)
加下来是事件的派发:
//获取事件
document.addEventListener('click', function(ev){
e.type = ev.type;
e.pageX = ev.pageX;
e.pageY = ev.pageY;
e.srcElement = mackSelector(ev.srcElement);
e.clientX = ev.clientX;
e.clientY = ev.clientY;
window.parent.postMessage(JSON.stringify({event: e}))
}, {capture:true, passive: true})
// 目标页面中派发事件:
handleMessage(msgStr){
const msgObj = JSON.parse(msgStr);
const {event} = msgObj;
let e = new Event(event.type);
let srcElement = document.querySelector(event.srcElement);
e.initEvent(event.type, true, true);
e.clientX = event.clientX;
e.clientY = event.clientY;
e.pageX = event.pageX;
e.pageY = event.pageY;
if(srcElement&&srcElement.dispatchEvent){
srcElement.dispatchEvent(e)
}
}
4. 在express中使用sockect.io库配合前端交互
首先需要安装express
和socket.io
包
npm i express socket.io
创建服务端:
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server);
io.on('connection', (socket) => {
socket.emit('open', '连接服务器成功'); // 通知客户端已连接
socket.on('someAction', (msg) => { // 监听客户端的消息并响应
console.log(msg)
socket.emit(JSON.stringify({msg: 'this is a response message'}))
});
//监听出退事件
socket.on('disconnect', function () {
// 客户端断开连接
})
})
// express基本配置
app.configure(() => {
app.set('port', 10086);
app.use(express.logger('dev'));
});
app.configure('development', function () {
app.use(express.errorHandler());
});
server.listen(app.get('port'), () => {
console.log("Express server listening on port " + app.get('port'));
})
在页面中使用socket.io: