釘釘微應用 開發體驗及心得

weixin_33806914發表於2016-12-16

開始調研

主要還是看釘釘的官方文件和論壇,釘釘推薦使用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

相關文章