钉钉微应用 开发体验及心得

yang_j_j

开始调研

主要还是看钉钉的官方文档和论坛,钉钉推荐使用saltUI和saltRouter进行开发微应用,但是看了这2个东西的源码后,感觉没封装什么东西,主要的功能还是集中在钉钉的dingtalk.js中,所以个人认为没必要用它推荐的这2个东西。

框架选择

作为一个vue的忠实粉丝,这次也肯定想用vue进行开发,考虑到vue2.0还没有很好的移动端UI框架,所以这次试用了更成熟的vue1.0的ui框架vux,然后微应用其实对应用状态管理的要求还是比较高的,所以也用了vuex来管理应用状态。

微应用流程

我们使用的是免登陆流程如下

  1. 它的入口网页会自动传appid,corpid,suiteKey这3个参数在url上面,通过这3个参数去自己的服务器获取到dd.config需要用的参数.

  2. 然后在dd.ready中设置和获取一些全局的钉钉属性,比如 设置左上角返回键的回调,获取容器的版本信息(用来判断能不能调用某些jsapi)

  3. 再初始化vue,配置vue插件什么的

  4. 最后判断js.config是否成功,然后dispath到vuex中

代码详解

对比上面流程的1. 2. 3. 4. 的代码

getConfig() //1.通过url上的3个参数,获取自己服务器上的配置信息
    .then((data)=>{ 
        ddConfig = data;
        dd.config(ddConfig); //1.初始化钉钉的jssdk
    })
    .then(ddIsReady) //2.做一些钉钉的全局设置
    .then(initVue) //3.初始化vue
    .then(()=>{
        document.querySelector('#init-loading').remove(); //移除加载动画
        console.log('init vue 完成')
        setTimeout(()=>{
            if(ddConfig != null){
                commit('DDCONFIG_SUCCESS', ddConfig)  //4.通知vuex改变应用功能状态
            }else{
                commit('DDCONFIG_ERROR', false);  //4.通知vuex改变应用功能状态
            }
        },300)
    })

getConfig

function getConfig() {
    return Q.Promise((success, error)=>{
        axios.get(env.API_HOST+'/auth/getConfig', {
            params: {
                corpid: getParamByName('corpid')||'',
                appid: getParamByName('appid')||'',
                suitekey: getParamByName('suiteKey')||'',
                paramUrl: document.URL
            },
            timeout: 2000,
        }).then(function (response) {
            if(response.status == 200 && response.data.code == 200){
                let res = response.data.result;
                let ddConfig = {
                    agentId: res.agentId, // 必填,微应用ID
                    corpId: res.corpId,//必填,企业ID
                    timeStamp: res.timeStamp, // 必填,生成签名的时间戳
                    nonceStr: res.nonceStr, // 必填,生成签名的随机串
                    signature: res.signature, // 必填,签名
                    type:0,   //选填。0表示微应用的jsapi,1表示服务窗的jsapi。不填默认为0。该参数从dingtalk.js的0.8.3版本开始支持
                    jsApiList : [
                        'runtime.info',
                        'runtime.permission.requestAuthCode',
                        'runtime.permission.requestOperateAuthCode', //反馈式操作临时授权码

                        'biz.alipay.pay',
                        'biz.contact.choose',
                        'biz.contact.complexChoose',
                        'biz.contact.complexPicker',
                        'biz.contact.createGroup',
                        'biz.customContact.choose',
                        'biz.customContact.multipleChoose',
                        'biz.ding.post',
                        'biz.map.locate',
                        'biz.map.view',
                        'biz.util.openLink',
                        'biz.util.open',
                        'biz.util.share',
                        'biz.util.ut',
                        'biz.util.uploadImage',
                        'biz.util.previewImage',
                        'biz.util.datepicker',
                        'biz.util.timepicker',
                        'biz.util.datetimepicker',
                        'biz.util.chosen',
                        'biz.util.encrypt',
                        'biz.util.decrypt',
                        'biz.chat.pickConversation',
                        'biz.telephone.call',
                        'biz.navigation.setLeft',
                        'biz.navigation.setTitle',
                        'biz.navigation.setIcon',
                        'biz.navigation.close',
                        'biz.navigation.setRight',
                        'biz.navigation.setMenu',
                        'biz.user.get',

                        'ui.progressBar.setColors',

                        'device.base.getInterface',
                        'device.connection.getNetworkType',
                        'device.launcher.checkInstalledApps',
                        'device.launcher.launchApp',
                        'device.notification.confirm',
                        'device.notification.alert',
                        'device.notification.prompt',
                        'device.notification.showPreloader',
                        'device.notification.hidePreloader',
                        'device.notification.toast',
                        'device.notification.actionSheet',
                        'device.notification.modal',
                        'device.geolocation.get',


                    ] // 必填,需要使用的jsapi列表,注意:不要带dd。
                }
                success(ddConfig)
            }else{
                error({errCode:-2,msg:'接口请求失败'})
            }
        }).catch(function (err) {
            error({errCode:-2,msg:'接口请求失败'})
        });
    })

}

ddIsReady

function ddIsReady() {
    return Q.Promise((success, error)=>{
        let timeout = setTimeout(()=>{
            error({errCode:-1,msg:'dd.ready初始化超时'});
        },2000)
        dd.ready(function(){
            console.log('初始化钉钉');
            clearTimeout(timeout)

            //设置返回按钮
            dd.biz.navigation.setLeft({
                show: true,//控制按钮显示, true 显示, false 隐藏, 默认true
                control: true,//是否控制点击事件,true 控制,false 不控制, 默认false
                showIcon: true,//是否显示icon,true 显示, false 不显示,默认true; 注:具体UI以客户端为准
                text: '返回',//控制显示文本,空字符串表示显示默认文本
                onSuccess : function(result) {
                    //如果control为true,则onSuccess将在发生按钮点击事件被回调
                    console.log('点击了返回按钮');
                    window.history.back();
                },
                onFail : function(err) {}
            });
            //获取容器信息
            dd.runtime.info({
                onSuccess: function(result) {
                    window.ability = parseInt(result.ability.replace(/\./g,''));
                    console.log('容器版本为'+window.ability)
                },
                onFail : function(err) {}
            })

            success(true)
        });
        dd.error(function(err){
            clearTimeout(timeout)
            /**
             {
                message:"错误信息",//message信息会展示出钉钉服务端生成签名使用的参数,请和您生成签名的参数作对比,找出错误的参数
                errorCode:"错误码"
             }
             **/
            console.error('dd error: ' + JSON.stringify(err));
            error({errCode:-1,msg:'dd.error配置信息不对'})
        });
    })
}

initVue

function initVue() {
    return Q.Promise((success, error)=>{

        Vue.use(Router)
        Vue.use(bbPlugin)
        Vue.use(ddPlugin)

        let router = new Router({
            transitionOnLoad: false
        })
        router.map({
            [env.BASE_PATH] : {
                component: function(resolve){
                    require.ensure([], function() {
                        let route = require('./page/home/route').default;
                        resolve(route);
                    },'home')
                },
                subRoutes: {
                    '/': {
                        component: function (resolve) {
                            require.ensure([], function () {
                                let route = require('./page/home/index/route').default;
                                resolve(route);
                            },'index')
                        }
                    },
                    '/member' : {
                        component: function(resolve){
                            require.ensure([], function() {
                                let route = require('./page/home/member/route').default;
                                resolve(route);
                            },'member')
                        }
                    },
                }
            },
            [env.BASE_PATH+'/user/sign_in'] : {
                component: function (resolve) {
                    require.ensure([], function () {
                        let route = require('./page/user-sign-in/route').default;
                        resolve(route);
                    }, 'user-sign-in')
                }
            },
            [env.BASE_PATH+'/user/bind'] : {
                component: function (resolve) {
                    require.ensure([], function () {
                        let route = require('./page/user-bind-mobile/route').default;
                        resolve(route);
                    }, 'user-bind-mobile')
                }
            }
        });
        router.redirect({
            '*': env.BASE_PATH
        });
        let history = window.sessionStorage
        history.clear()
        let historyCount = history.getItem('count') * 1 || 0
        history.setItem('/', 0)

        router.beforeEach(({ to, from, next }) => {
            const toIndex = history.getItem(to.path)
            const fromIndex = history.getItem(from.path)
            if (toIndex) {
                if (toIndex > fromIndex || !fromIndex) {
                    commit('UPDATE_DIRECTION', 'forward')
                } else {
                    commit('UPDATE_DIRECTION', 'reverse')
                }
            } else {
                ++historyCount
                history.setItem('count', historyCount)
                to.path !== '/' && history.setItem(to.path, historyCount)
                commit('UPDATE_DIRECTION', 'forward')
            }
            commit('UPDATE_LOADING', true)


            setTimeout(()=>{
                try {
                    //设置右侧按钮
                    dd.biz.navigation.setRight({
                        show: false,//控制按钮显示, true 显示, false 隐藏, 默认true
                    });
                }catch (err){
                    console.error(err);
                }

                next();
            }, 10)
        })
        router.afterEach(() => {
            commit('UPDATE_LOADING', false)
        })
        sync(store, router)
        router.start(App, '#app')

        FastClick.attach(document.body)

        success()
    })
}

然后就可以愉快的写业务代码啦

怎么能不开源呢?我只是把很多开源项目的代码拼到了一起,请谅解... github demo

阅读 23.6k

业务分享
做到的一些业务逻辑 分享
838 声望
32 粉丝
0 条评论
838 声望
32 粉丝
文章目录
宣传栏