上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
返回列表 发新帖

[脚本实战篇]实现iframe通信

[复制链接]
  • TA的每日心情
    擦汗
    4 天前
  • 签到天数: 194 天

    [LV.7]常住居民III

    720

    主题

    6071

    回帖

    6850

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6850

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2022-5-11 09:19:38 | 显示全部楼层 | 阅读模式

    前言

    我们之前已经实现了视频的静默播放以及结束播放的检测
    现在我们开始尝试编写播放结束后自动关闭对话框
    先回忆一下之前的代码

                vdobj.hook('setup', function(player) {
                    console.log('setup',player)
                    // 绑定结束事件
                    player.on("ended", function() {
                        console.log('播放完毕')
                    });
    
                });

    根据内容来看,红色的是我们的视频
    可以看到是一个iframe
    图片.png
    那我们可以编写代码
    使用postmessage进行通信
    unsafeWindow.parent.postMessage('lhd_close')
    同时在外部的iframe里进行监听,我们直接写在之前的OpenOriginDialog函数中

    function OpenOriginDialog(Content){
        return new Promise((resolve,reject)=>{
            unsafeWindow.require(["Play"],function(Play){
                let courseId=unsafeWindow._courseId;
                let userId=unsafeWindow._userId;
                let companyCode=unsafeWindow._companyCode;
                const ListenMessage= (e)=> {
                    if(e.data==='lhd_close'){
                        unsafeWindow.removeEventListener('message', ListenMessage)
                        //关闭窗口代码
                        resolve()
                    }
                }
                unsafeWindow.addEventListener('message', ListenMessage);
                Play.dialog({
                    //唯一ID
                    id:"videoBox-link",
                    data:{
                        url:Content.fullResUrl,
                        companyCode:companyCode,//三方公司id
                        resId:Content.id,
                        type:Content.mediaType,
                        userId:userId,
                        courseId:courseId,
                        title:Content.title+'-李恒道破解'
                    },
                    //弹出框宽度
                    width:"auto",
                    //弹出框高度
                    height:(screen.availHeight-200) + "px",
                    //是否开启打点功能
                    isTicker:true
                });
            })
        })
    }

    这样就完成了
    整理一下
    大概逻辑是这样的
    在调用打开对话框函数之后
    我们做了以下几件事
    1.对message进行监听,如果找到lhd_close则关闭对话框,并解除监听
    2.打开对话框
    3.对话框会加载一个iframe,在适当时机发送lhd_close让父级关闭对话框
    那么我们的嵌套层级大概是这样的
    图片.png
    但是根据我的测试,
    青色的在不同的地址里可能出现第三次嵌套
    所以我们需要对复杂环境进行判断
    这里我直接编写了一个小函数

    function EmitParentClose(){
        let parentif=unsafeWindow.parent
        while(parentif!==unsafeWindow.top){
            parentif.postMessage('lhd_close')
            parentif=parentif.parent
        }
    }

    因为第一级也就是黄色部分,根据测试是没有任何用的
    所以我们可以不对他发送
    青色内部的不管多少层的iframe嵌套,如果触发退出时间
    都会一直向上追溯直到完毕,每一层iframe都发送一次消息
    那我们的通信部分就完毕了
    接下来我们研究一下怎么关闭这个窗口
    还是老规矩。搜一下标题class
    图片.png
    我们找到了这里
    图片.png
    发现了

            //当弹出框隐藏时删除弹出框
            $('#'+dialogId).on('hidden.bs.modal', function () {
                $('#'+dialogId).remove();
            })

    也就是说当隐藏的之后直接调用remove函数
    那dialogId是什么呢?
    全局搜索一下找到了
    var dialogId="dialog-myModal"+config.id+cacheNum;
    前边的是固定的,后边是自动变化的
    也就是说我们可以写一个css语句
    document.querySelector('[id^=dialog-myModal]')?.remove()
    这里用了id的前缀匹配,同时?是为了在找不到元素的情况下不调用remove,防止报错
    那么我们再看一下OpenOriginDialog代码

    function OpenOriginDialog(Content){
        return new Promise((resolve,reject)=>{
            unsafeWindow.require(["Play"],function(Play){
                let courseId=unsafeWindow._courseId;
                let userId=unsafeWindow._userId;
                let companyCode=unsafeWindow._companyCode;
                const ListenMessage= (e)=> {
                    if(e.data==='lhd_close'){
                        unsafeWindow.removeEventListener('message', ListenMessage)
                        document.querySelector('[id^=dialog-myModal]')?.remove()
                        resolve()
                    }
                }
                unsafeWindow.addEventListener('message', ListenMessage);
                Play.dialog({
                    //唯一ID
                    id:"videoBox-link",
                    data:{
                        url:Content.fullResUrl,
                        companyCode:companyCode,//三方公司id
                        resId:Content.id,
                        type:Content.mediaType,
                        userId:userId,
                        courseId:courseId,
                        title:Content.title+'-李恒道破解'
                    },
                    //弹出框宽度
                    width:"auto",
                    //弹出框高度
                    height:(screen.availHeight-200) + "px",
                    //是否开启打点功能
                    isTicker:true
                });
            })
        })
    }

    我们完成了对话框的打开关闭,以及子iframe的消息监听
    而子video的代码也非常简单
    我们只需要一个小修改

                function EmitParentClose(){
                    let parentif=unsafeWindow.parent
                    while(parentif!==unsafeWindow.top){
                        parentif.postMessage('lhd_close')
                        parentif=parentif.parent
                    }
                }
                ----以下为video的结束钩子代码---
    
                vdobj.hook('setup', function(player) {
                    player.on("ended", function() {
                        EmitParentClose()
                    });
                });

    触发关闭条件的时候直接调用EmitParentClose函数即可。

    结语

    那么我们这节课就完成了iframe的监听
    撒花~

    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
  • TA的每日心情
    开心
    2024-11-21 13:37
  • 签到天数: 213 天

    [LV.7]常住居民III

    306

    主题

    4256

    回帖

    4105

    积分

    管理员

    积分
    4105

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

    发表于 2022-5-11 09:27:32 | 显示全部楼层
    woc,生产队的驴!
    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    883

    回帖

    1381

    积分

    荣誉开发者

    积分
    1381

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2022-5-11 11:49:01 | 显示全部楼层
    能不能addStyle让对话框一直display: none呢?感觉这样更简单可靠一点,其实postMessage的问题挺多的,如果message在前,脚本注入在后,就会出现收不到的情况,使用的时候可能需要加延迟,或者控制脚本运行时机等等,还有如果网页本身有对message做监听,还需要避免冲突,挺麻烦的,我更倾向于能不做跨域通信就不做。
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    4 天前
  • 签到天数: 194 天

    [LV.7]常住居民III

    720

    主题

    6071

    回帖

    6850

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6850

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2022-5-11 12:38:07 | 显示全部楼层
    cxxjackie 发表于 2022-5-11 11:49
    能不能addStyle让对话框一直display: none呢?感觉这样更简单可靠一点,其实postMessage的问题挺多的,如果 ...

    这个网页搞的太烂...
    我依赖他的大概逻辑做的
    如果对话框display:none的话到下个还会继续创建
    这不是最离谱的
    我怀疑他好像有内存泄漏...
    调试的时候发现他的post堆栈有一百多层requirejs?????
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    4 天前
  • 签到天数: 194 天

    [LV.7]常住居民III

    720

    主题

    6071

    回帖

    6850

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6850

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2022-5-11 12:42:34 | 显示全部楼层
    cxxjackie 发表于 2022-5-11 11:49
    能不能addStyle让对话框一直display: none呢?感觉这样更简单可靠一点,其实postMessage的问题挺多的,如果 ...


    我上面刚说完那些话
    果真出问题了....
    videojs时间没写好...我在搞一下

    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    883

    回帖

    1381

    积分

    荣誉开发者

    积分
    1381

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2022-5-11 22:00:33 | 显示全部楼层
    李恒道 发表于 2022-5-11 12:38
    这个网页搞的太烂...
    我依赖他的大概逻辑做的
    如果对话框display:none的话到下个还会继续创建

    我是说加一条css:
    1. [id^=dialog-myModal]{display:none !important;}
    复制代码

    这样他创建几个都没用吧,css还是方便的。
    回复

    使用道具 举报

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表