美文网首页
web页面基于事件转发的webSocket同步技术分享

web页面基于事件转发的webSocket同步技术分享

作者: Yezzle | 来源:发表于2020-04-26 18:29 被阅读0次

    本人在做websockect同步的项目积累了一些经验,整理出来即是方便自己日后查看,也可以分享给大家一起讨论学习,很多出代码都是要记一下的,所以下面贴代码可能会比较多。本文主要内容包含了一下技术点:

    1. iframe注入脚本
    2. iframe与父级页面的交互
    3. 鼠标事件转发原理
    4. 在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库配合前端交互

    首先需要安装expresssocket.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:

    <script src="./node_modules/socket.io-client/dist/socket.io.js"> </script>
    <script> 
        const socketUrl = "localhost:10086"
        socket = io.connect(socketUrl);
        socket.on('open', () => {
            console.log('连接服务器成功')
        })
    
        socket.on('connection', (msg) => {
            console.log(JSON.parse(msg).msg) // this is a response message
        })
    </script>
    

    相关文章

      网友评论

          本文标题:web页面基于事件转发的webSocket同步技术分享

          本文链接:https://www.haomeiwen.com/subject/jhodwhtx.html