使用钉钉的扫码会出现多个回调(DTFrameLogin)

官方:地址

标题

  • 出现的问题
  • 解决后效果
  • 正常使用(按照官网的流程进行使用)
  • 修改后使用(解决方式)
    • **解决组件关闭后,多次开启组件会产生多个回调的bug**
  • 自己的理解(路人可忽略该内容!)

出现的问题

1692861955468

解决后效果

1692861665687

正常使用(按照官网的流程进行使用)

fn.js
该文件就是钉钉官网的js文件,我下载到了本地
js文件下载地址

!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=1382)}({1382:function(e,t){var r=function(e,t){var r=e.match(new RegExp("[?&]"+t+"=([^&]+)"));return r?r[1]:null};window.DTFrameLogin=function(e,t,n,o){var i,u=e.id&&document.getElementById(e.id)||null,c=document.createElement("iframe");t.client_id&&t.redirect_uri&&t.response_type&&t.scope?u?(u.innerHTML="",u.appendChild(c),c&&c.contentWindow&&c.contentWindow.postMessage&&window.addEventListener?(c.src="https://"+((i=t).isPre?"pre-login":"login")+".dingtalk.com/oauth2/auth?iframe=true&redirect_uri="+i.redirect_uri+"&response_type="+i.response_type+"&client_id="+i.client_id+"&scope="+i.scope+(i.prompt?"&prompt="+i.prompt:"")+(i.state?"&state="+i.state:"")+(i.org_type?"&org_type="+i.org_type:"")+(i.corpId?"&corpId="+i.corpId:"")+(i.exclusiveLogin?"&exclusiveLogin="+i.exclusiveLogin:"")+(i.exclusiveCorpId?"&exclusiveCorpId="+i.exclusiveCorpId:""),c.width=""+(e.width||300),c.height=""+(e.height||300),c.frameBorder="0",c.scrolling="no",window.addEventListener("message",(function(e){var t=e.data,i=e.origin;if(/login\.dingtalk\.com/.test(i)&&t)if(t.success&&t.redirectUrl){var u=t.redirectUrl,c=r(u,"authCode")||"",d=r(u,"state")||"",s=r(u,"error")||"";c?n&&n({redirectUrl:u,authCode:c,state:d}):o&&o(s)}else o&&o(t.errorMsg)}))):o&&o("Browser not support")):o&&o("Element not found"):o&&o("Missing parameters")}}});

util.js
这个文件就是按照钉钉文档的流程编写的代码

//钉钉js文件地址
import './fn.js'
//跳转地址,需要在钉钉后台提前配置好,暂时未用到
const url = location.origin + '/#/'
export const BASE_URL = encodeURIComponent(url);
const appid_default = 'xxxxxx' //填写自己的钉钉应用id
const state_default = 'PC'const fn = () => {console.log('默认的回调');
}//INIT_DINDING 生成钉钉二维码 传递两个参数
//参数一,html标签id,该标签用来渲染二维码
//参数二,回调,在扫码完成后,进行的操作
export const INIT_DINDING = (id = "qr_code_div", callback = fn) => {const demo = new window.DTFrameLogin({id,width: 300,//二维码宽度height: 300,//二维码高度},{client_id: appid_default,redirect_uri: BASE_URL,client_id: appid_default,scope: 'openid',response_type: 'code',state: state_default,prompt: 'consent',},(loginResult) => {// const { redirectUrl, authCode, state } = loginResult;//loginResult字段说明____________________________//redirectUrl  重定向的地址//authCode     !!!很重要,这个就是钉钉返回的唯一标识//state        我上面写的PC,因此这个值就是PC,用来以后区别pc和app// 这里可以直接进行重定向// window.location.href = redirectUrl;// 也可以在不跳转页面的情况下,使用code进行授权//——————————————触发回调————————————————————————————————————callback && callback(loginResult)return},)
}

edit.vue
封装出现二维码的组件

<template><div><div class="qr_code_div" ref="qrCodeDiv" id="qr_code_div"></div></div>
</template>
<script>
//看准你自己的文件地址---------------
import { INIT_DINDING, SET_MESSAGE } from "./util.js";
export default {data() {return {};},mounted() {INIT_DINDING("qr_code_div",function () {console.log("this__________________这是扫码的回调");// fn=null});},created() {},methods: {},beforeDestroy(){}
};
</script>
<style lang="scss" scoped>
.qr_code_div {width: 300px;height: 300px;margin: 0 auto;
}
</style>

app.vue
使用组件

<template><div><button @click='blg = !blg'>{{blg}}</button><edit v-if="blg"></edit></div>
</template>
<script>
import edit from './edit'
export default {data() {return {blg:true};},components:{edit},mounted() {},created() {},methods: {},
};
</script>
<style lang="scss" scoped>
</style>

按照上面的流程便可以正常的在h5使用钉钉的扫码组件了

修改后使用(解决方式)

解决组件关闭后,多次开启组件会产生多个回调的bug

在上方的edit.vue组件中进行修改

<template><div><div class="qr_code_div" ref="qrCodeDiv" id="qr_code_div"></div></div>
</template>
<script>
import { INIT_DINDING, SET_MESSAGE } from "../utils/init";
//1、步骤一
//修改之前的匿名回调
let fn = function () {console.log("this__________________这是扫码的回调");//2、步骤二//回调执行后把函数置空fn = null;
};
export default {data() {return {};},mounted() {//3、步骤三,传递修改后的回调INIT_DINDING("qr_code_div", fn);},created() {},methods: {},beforeDestroy() {//4、步骤四---组件销毁也把函数置空fn = null;},
};
</script>
<style lang="scss" scoped>
.qr_code_div {width: 300px;height: 300px;margin: 0 auto;
}
</style>

自己的理解(路人可忽略该内容!)

查看钉钉的打包后的源码,发现是通过绑定message监听来接受回调的
其实还有另外一种,就是在message事件执行后,立即取消绑定,只让他执行一次
但是考虑到是匿名事件,并且是打包后的代码,并没有进行更改
就使用了另一种方法,也就是上诉的方法
钉钉源码

! function (e) {var t = {};function r(n) {if (t[n]) return t[n].exports;var o = t[n] = {i: n,l: !1,exports: {}};return e[n].call(o.exports, o, o.exports, r), o.l = !0, o.exports}r.m = e, r.c = t, r.d = function (e, t, n) {r.o(e, t) || Object.defineProperty(e, t, {enumerable: !0,get: n})}, r.r = function (e) {"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {value: "Module"}), Object.defineProperty(e, "__esModule", {value: !0})}, r.t = function (e, t) {if (1 & t && (e = r(e)), 8 & t) return e;if (4 & t && "object" == typeof e && e && e.__esModule) return e;var n = Object.create(null);if (r.r(n), Object.defineProperty(n, "default", {enumerable: !0,value: e}), 2 & t && "string" != typeof e)for (var o in e) r.d(n, o, function (t) {return e[t]}.bind(null, o));return n}, r.n = function (e) {var t = e && e.__esModule ? function () {return e.default} : function () {return e};return r.d(t, "a", t), t}, r.o = function (e, t) {return Object.prototype.hasOwnProperty.call(e, t)}, r.p = "", r(r.s = 1382)
}({1382: function (e, t) {var r = function (e, t) {var r = e.match(new RegExp("[?&]" + t + "=([^&]+)"));return r ? r[1] : null};window.DTFrameLogin = function (e, t, n, o) {var i, u = e.id && document.getElementById(e.id) || null,c = document.createElement("iframe");t.client_id && t.redirect_uri && t.response_type && t.scope ? u ? (u.innerHTML = "", u.appendChild(c), c && c.contentWindow && c.contentWindow.postMessage && window.addEventListener ? (c.src = "https://" + ((i = t).isPre ? "pre-login" : "login") + ".dingtalk.com/oauth2/auth?iframe=true&redirect_uri=" + i.redirect_uri + "&response_type=" + i.response_type + "&client_id=" + i.client_id + "&scope=" + i.scope + (i.prompt ? "&prompt=" + i.prompt : "") + (i.state ? "&state=" + i.state : "") + (i.org_type ? "&org_type=" + i.org_type : "") + (i.corpId ? "&corpId=" + i.corpId : "") + (i.exclusiveLogin ? "&exclusiveLogin=" + i.exclusiveLogin : "") + (i.exclusiveCorpId ? "&exclusiveCorpId=" + i.exclusiveCorpId : ""), c.width = "" + (e.width || 300), c.height = "" + (e.height || 300), c.frameBorder = "0", c.scrolling = "no", window.addEventListener("message", (function (e) {var t = e.data,i = e.origin;//这里这里-------------------------------看上面👆if (/login\.dingtalk\.com/.test(i) && t)if (t.success && t.redirectUrl) {var u = t.redirectUrl,c = r(u, "authCode") || "",d = r(u, "state") || "",s = r(u, "error") || "";c ? n && n({redirectUrl: u,authCode: c,state: d}) : o && o(s)} else o && o(t.errorMsg)}))) : o && o("Browser not support")) : o && o("Element not found") : o && o("Missing parameters")}}
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/57380.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java中使用sockjs、stomp完成websocket通信

主要配置 import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary;import org.…

vue3+ ts ts语法在script写不知道为啥一直报错

在vue3页面中写ts语法 发现识别不了 一直报错 1.出现这种问题的话,首先查看自己写的有没有问题,没有问题的话 2.再查看 script里边有没有写 lang"ts" <script setup lang"ts">解析 setup&#xff1a;是vue3在单文件组件 (SFC) 中使用 composition …

LLM - Baichuan-13B 多卡加载与推理测试

目录 ​编辑 一.引言 二.模型加载 1.量化加载 ◆ 基础配置 ◆ 8_bit 加载 ◆ 4_bit 加载 2.多卡加载 ◆ API 加载 ◆ accelerate 加载 三.模型推理 1.显存查看 ◆ Nvidia 显卡监控 ◆ Python subprocess 调用 2.双卡推理 ◆ 双卡 divice 分配 ◆ 双卡推理 GPU…

网络直播源码UDP协议搭建:为平台注入一份力量

网络直播源码中的UDP协议的定义&#xff1a; UDP协议又名用户数据报协议&#xff0c;是一种轻量级、无连接的协议。在网络直播源码平台中&#xff0c;UDP协议有着高速传输与实时性的能力&#xff0c;尤其是在网络直播源码实时性要求较高的场景&#xff0c;UDP协议的应用有着重要…

【Flutter】Flutter 使用 flutter_timezone 获取当前操作系统的时区

【Flutter】Flutter 使用 flutter_timezone 获取当前操作系统的时区 文章目录 一、前言二、flutter_timezone 包的背景三、安装和基本使用四、深入理解时区五、实际业务中的用法六、完整示例七、总结 一、前言 大家好&#xff01;我是小雨青年&#xff0c;今天我想和大家分享一…

NeRFMeshing - 精确提取NeRF中的3D网格

准确的 3D 场景和对象重建对于机器人、摄影测量和 AR/VR 等各种应用至关重要。 NeRF 在合成新颖视图方面取得了成功&#xff0c;但在准确表示底层几何方面存在不足。 推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 我们已经看到了最新的进展&#xff0c;例如 NVIDIA 的 …

前端UI组件库深度解析:构建现代化的用户体验

引言 在当今的前端开发中&#xff0c;UI组件库已经成为了我们工具箱中不可或缺的一部分。这些库可以极大地提高我们的工作效率&#xff0c;同时也使我们能够专注于实现真正的业务逻辑&#xff0c;而不是重复地编写UI代码。本篇博客将详细地探讨UI组件库的核心概念&#xff0c;…

软件工程(二十) 系统运行与软件维护

1、系统转换计划 1.1、遗留系统的演化策略 时至今日,你想去开发一个系统,想完全不涉及到已有的系统,基本是不可能的事情。但是对于已有系统我们有一个策略。 比如我们是淘汰掉已有系统,还是继承已有系统,或者集成已有系统,或者改造遗留的系统呢,都是不同的策略。 技术…

AI大模型的使用-让AI帮你写单元测试

1.体验多步提示语 我们本节就让AI帮我们写一个单元测试&#xff0c;全程用AI给我们答案&#xff0c;首先单元测试前需要有代码&#xff0c;那么我们让AI给我们生成一个代码&#xff0c;要求如下&#xff1a; 用Python写一个函数&#xff0c;进行时间格式化输出&#xff0c;比…

WPF基础入门-Class4-WPF绑定

WPF基础入门 Class4&#xff1a;WPF绑定 一、简单绑定数据 1、cs文件中设置需要绑定的数据&#xff1a; public partial class Class_4 : Window{public Class_4(){InitializeComponent();List<Color> test new List<Color>();test.Add(new Color() { Code &q…

leetcode算法题--使子序列的和等于目标的最少操作次数

原题链接&#xff1a;https://leetcode.cn/problems/minimum-operations-to-form-subsequence-with-target-sum/description/ 视频讲解&#xff1a;https://www.bilibili.com/video/BV1Em4y1T7Bq?t1456.1 这题是真的难。。 func minOperations(nums []int, target int) int…

netty与websockt实现聊天

配置websockt&#xff1a; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration;/*** websocket配置*/ Data Configuration ConfigurationProperties(prefix &qu…

PHP获取两个日期之间的所有日期

下面是一个示例代码&#xff0c;用于计算给定开始和结束日期之间的所有日期&#xff1a; <?phpfunction getDatesBetween($start_date, $end_date) {// 初始化结果数组$dates array();// 将开始日期转换为时间戳$current_date strtotime($start_date);$end_date strtot…

Java并发编程第6讲——线程池(万字详解)

Java中的线程池是运用场景最多的并发框架&#xff0c;几乎所有需要异步或并发执行任务的程序都可以使用线程池&#xff0c;本篇文章就详细介绍一下。 一、什么是线程池 定义&#xff1a;线程池是一种用于管理和重用线程的技术&#xff08;池化技术&#xff09;&#xff0c;它主…

微服务中间件--分布式搜索ES

分布式搜索ES 11.分布式搜索 ESa.介绍ESb.IK分词器c.索引库操作 (类似于MYSQL的Table)d.查看、删除、修改 索引库e.文档操作 (类似MYSQL的数据)1) 添加文档2) 查看文档3) 删除文档4) 修改文档 f.RestClient操作索引库1) 创建索引库2) 删除索引库/判断索引库 g.RestClient操作文…

http协议与apache

http概念&#xff1a; 互联网&#xff1a;是网络的网络&#xff0c;是所有类型网络的母集 因特网&#xff1a;世界上最大的互联网网络。即因特网概念从属于互联网概念 万维网&#xff1a;万维网并非某种特殊的计算机网络&#xff0c;是一个大规模的、联机式的信息贮藏库&…

C++11---std::bind

下面这段代码解析 std::function<decltype(f(args...))()> func std::bind(std::forward<F>(f), std::forward<Args>(args)...); 这行代码的作用是创建一个 std::function 对象 func&#xff0c;将其绑定到一个可调用对象上。 让我们逐步解释这行代码的各…

长胜证券:沪指探底回升涨0.47%,券商、酿酒板块拉升,传媒板块活跃

24日早盘&#xff0c;沪指盘中震动回落&#xff0c;接近午盘快速拉升走高&#xff1b;深成指、创业板指强势上扬&#xff1b;北向资金今天转向&#xff0c;早盘积极出场&#xff0c;半日净买入近30亿元。 到午间收盘&#xff0c;沪指涨0.47%报3092.88点&#xff0c;深成指涨1.1…

最新AI创作系统ChatGPT源码+详细图文部署教程/支持GPT-4/AI绘画/H5端/Prompt知识库/思维导图生成

一、AI系统 如何搭建部署AI创作ChatGPT系统呢&#xff1f;小编这里写一个详细图文教程吧&#xff01;SparkAi使用Nestjs和Vue3框架技术&#xff0c;持续集成AI能力到AIGC系统&#xff01; 1.1 程序核心功能 程序已支持ChatGPT3.5/GPT-4提问、AI绘画、Midjourney绘画&#xf…

Django(8)-静态资源引用CSS和图片

除了服务端生成的 HTML 以外&#xff0c;网络应用通常需要一些额外的文件——比如图片&#xff0c;脚本和样式表——来帮助渲染网络页面。在 Django 中&#xff0c;我们把这些文件统称为“静态文件”。 我们使用static文件来存放静态资源&#xff0c;django会在每个 INSTALLED…