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

官方:地址

标题

出现的问题

1692861955468

解决后效果

1692861665687

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

fn.js

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

javascript 复制代码
!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

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

javascript 复制代码
//钉钉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

封装出现二维码的组件

html 复制代码
<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

使用组件

html 复制代码
<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组件中进行修改

```html
<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事件执行后,立即取消绑定,只让他执行一次

但是考虑到是匿名事件,并且是打包后的代码,并没有进行更改

就使用了另一种方法,也就是上诉的方法

钉钉源码

javascript 复制代码
! 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")
        }
    }
});
相关推荐
高效匠人6 天前
prompt实用技巧-AI+Mermaid【酷炫钉钉文档】
人工智能·prompt·钉钉·ai编程·行业学习
henanxiaoman6 天前
zabbix之钉钉告警
钉钉·zabbix
测试界吖吖7 天前
使用Jenkins扩展钉钉消息通知
自动化测试·软件测试·功能测试·程序人生·servlet·jenkins·钉钉
Dragon_qu·x18 天前
Prometheus 监控域名和consul服务实现alertmanager钉钉告警
运维·云计算·钉钉·prometheus·consul
yukai0800820 天前
Python一些可能用的到的函数系列131 发送钉钉机器人消息
python·机器人·钉钉
鼠爷ねずみ20 天前
钉钉-即时通讯-工作通知
钉钉
梅孔立21 天前
钉钉打包以后发送报错 org.apache.tomcat.util.codec.binary.Base64.encodeBase64([B 解决描述
java·ubuntu·centos·tomcat·maven·apache·钉钉
LookLook同学22 天前
有哪些内部知识库类似钉钉,满足企业多样化需求?
钉钉·企业知识库·知识管理·内部知识库
不知名运维:1 个月前
Prometheus Alertmanager告警之邮件、钉钉群、企业微信群机器人报警
钉钉·企业微信·prometheus
风与尘1 个月前
Spring Boot集成钉钉群通知机器人
java·spring boot·钉钉