• 专门用于微信公众平台的Javascript API


      1 /**!
      2  * 微信内置浏览器的Javascript API,功能包括:
      3  *
      4  * 1、分享到微信朋友圈
      5  * 2、分享给微信好友
      6  * 3、分享到腾讯微博
      7  * 4、新的分享接口,包含朋友圈、好友、微博的分享(for iOS)
      8  * 5、隐藏/显示右上角的菜单入口
      9  * 6、隐藏/显示底部浏览器工具栏
     10  * 7、获取当前的网络状态
     11  * 8、调起微信客户端的图片播放组件
     12  * 9、关闭公众平台Web页面
     13  * 10、判断当前网页是否在微信内置浏览器中打开
     14  * 11、增加打开扫描二维码
     15  * 12、支持WeixinApi的错误监控
     16  * 13、检测应用程序是否已经安装(需要官方开通权限)
     17  * 14、发送电子邮件
     18  * 15、禁止用户分享
     19  *
     20  * @author guanguoxiang(http://www.ggxapp.com)
     21  */
     22 (function (window) {
     23 
     24     "use strict";
     25 
     26     /**
     27      * 定义WeixinApi
     28      */
     29     var WeixinApi = {
     30         version: 4.1
     31     };
     32 
     33     // 将WeixinApi暴露到window下:全局可使用,对旧版本向下兼容
     34     window.WeixinApi = WeixinApi;
     35 
     36     /////////////////////////// CommonJS /////////////////////////////////
     37     if (typeof define === 'function' && (define.amd || define.cmd)) {
     38         if (define.amd) {
     39             // AMD 规范,for:requirejs
     40             define(function () {
     41                 return WeixinApi;
     42             });
     43         } else if (define.cmd) {
     44             // CMD 规范,for:seajs
     45             define(function (require, exports, module) {
     46                 module.exports = WeixinApi;
     47             });
     48         }
     49     }
     50 
     51     /**
     52      * 对象简单继承,后面的覆盖前面的,继承深度:deep=1
     53      * @private
     54      */
     55     var _extend = function () {
     56         var result = {}, obj, k;
     57         for (var i = 0, len = arguments.length; i < len; i++) {
     58             obj = arguments[i];
     59             if (typeof obj === 'object') {
     60                 for (k in obj) {
     61                     obj[k] && (result[k] = obj[k]);
     62                 }
     63             }
     64         }
     65         return result;
     66     };
     67 
     68     /**
     69      * 内部私有方法,分享用
     70      * @private
     71      */
     72     var _share = function (cmd, data, callbacks) {
     73         callbacks = callbacks || {};
     74 
     75         // 分享过程中的一些回调
     76         var progress = function (resp) {
     77             switch (true) {
     78                 // 用户取消
     79                 case /\:cancel$/i.test(resp.err_msg) :
     80                     callbacks.cancel && callbacks.cancel(resp);
     81                     break;
     82                 // 发送成功
     83                 case /\:(confirm|ok)$/i.test(resp.err_msg):
     84                     callbacks.confirm && callbacks.confirm(resp);
     85                     break;
     86                 // fail 发送失败
     87                 case /\:fail$/i.test(resp.err_msg) :
     88                 default:
     89                     callbacks.fail && callbacks.fail(resp);
     90                     break;
     91             }
     92             // 无论成功失败都会执行的回调
     93             callbacks.all && callbacks.all(resp);
     94         };
     95 
     96         // 执行分享,并处理结果
     97         var handler = function (theData, argv) {
     98 
     99             // 加工一下数据
    100             if (cmd.menu == 'menu:share:timeline' ||
    101                 (cmd.menu == 'general:share' && argv.shareTo == 'timeline')) {
    102 
    103                 var title = theData.title;
    104                 theData.title = theData.desc || title;
    105                 theData.desc = title || theData.desc;
    106             }
    107 
    108             // 新的分享接口,单独处理
    109             if (cmd.menu === 'general:share') {
    110                 // 如果是收藏操作,并且在wxCallbacks中配置了favorite为false,则不执行回调
    111                 if (argv.shareTo == 'favorite' || argv.scene == 'favorite') {
    112                     if (callbacks.favorite === false) {
    113                         return argv.generalShare(theData, function () {
    114                         });
    115                     }
    116                 }
    117                 if (argv.shareTo === 'timeline') {
    118                     WeixinJSBridge.invoke('shareTimeline', theData, progress);
    119                 } else if (argv.shareTo === 'friend') {
    120                     WeixinJSBridge.invoke('sendAppMessage', theData, progress);
    121                 } else if (argv.shareTo === 'QQ') {
    122                     WeixinJSBridge.invoke('shareQQ', theData, progress);
    123                 }else if (argv.shareTo === 'weibo') {
    124                     WeixinJSBridge.invoke('shareWeibo', theData, progress);
    125                 }
    126             } else {
    127                 WeixinJSBridge.invoke(cmd.action, theData, progress);
    128             }
    129         };
    130 
    131         // 监听分享操作
    132         WeixinJSBridge.on(cmd.menu, function (argv) {
    133             callbacks.dataLoaded = callbacks.dataLoaded || new Function();
    134             if (callbacks.async && callbacks.ready) {
    135                 WeixinApi["_wx_loadedCb_"] = callbacks.dataLoaded;
    136                 if (WeixinApi["_wx_loadedCb_"].toString().indexOf("_wx_loadedCb_") > 0) {
    137                     WeixinApi["_wx_loadedCb_"] = new Function();
    138                 }
    139                 callbacks.dataLoaded = function (newData) {
    140                     callbacks.__cbkCalled = true;
    141                     var theData = _extend(data, newData);
    142                     theData.img_url = theData.imgUrl || theData.img_url;
    143                     delete theData.imgUrl;
    144                     WeixinApi["_wx_loadedCb_"](theData);
    145                     handler(theData, argv);
    146                 };
    147                 // 然后就绪
    148                 if (!(argv && (argv.shareTo == 'favorite' || argv.scene == 'favorite') && callbacks.favorite === false)) {
    149                     callbacks.ready && callbacks.ready(argv, data);
    150                     // 如果设置了async为true,但是在ready方法中并没有手动调用dataLoaded方法,则自动触发一次
    151                     if (!callbacks.__cbkCalled) {
    152                         callbacks.dataLoaded({});
    153                         callbacks.__cbkCalled = false;
    154                     }
    155                 }
    156             } else {
    157                 // 就绪状态
    158                 var theData = _extend(data);
    159                 if (!(argv && (argv.shareTo == 'favorite' || argv.scene == 'favorite') && callbacks.favorite === false)) {
    160                     callbacks.ready && callbacks.ready(argv, theData);
    161                 }
    162                 handler(theData, argv);
    163             }
    164         });
    165     };
    166 
    167     /**
    168      * 分享到微信朋友圈
    169      * @param       {Object}    data       待分享的信息
    170      * @p-config    {String}    appId      公众平台的appId(服务号可用)
    171      * @p-config    {String}    imgUrl     图片地址
    172      * @p-config    {String}    link       链接地址
    173      * @p-config    {String}    desc       描述
    174      * @p-config    {String}    title      分享的标题
    175      *
    176      * @param       {Object}    callbacks  相关回调方法
    177      * @p-config    {Boolean}   async                   ready方法是否需要异步执行,默认false
    178      * @p-config    {Function}  ready(argv, data)       就绪状态
    179      * @p-config    {Function}  dataLoaded(data)        数据加载完成后调用,async为true时有用,也可以为空
    180      * @p-config    {Function}  cancel(resp)    取消
    181      * @p-config    {Function}  fail(resp)      失败
    182      * @p-config    {Function}  confirm(resp)   成功
    183      * @p-config    {Function}  all(resp)       无论成功失败都会执行的回调
    184      */
    185     WeixinApi.shareToTimeline = function (data, callbacks) {
    186         _share({
    187             menu: 'menu:share:timeline',
    188             action: 'shareTimeline'
    189         }, {
    190             "appid": data.appId ? data.appId : '',
    191             "img_url": data.imgUrl,
    192             "link": data.link,
    193             "desc": data.desc,
    194             "title": data.title,
    195             "img_width": "640",
    196             "img_height": "640"
    197         }, callbacks);
    198     };
    199 
    200     /**
    201      * 发送给微信上的好友
    202      * @param       {Object}    data       待分享的信息
    203      * @p-config    {String}    appId      公众平台的appId(服务号可用)
    204      * @p-config    {String}    imgUrl     图片地址
    205      * @p-config    {String}    link       链接地址
    206      * @p-config    {String}    desc       描述
    207      * @p-config    {String}    title      分享的标题
    208      *
    209      * @param       {Object}    callbacks  相关回调方法
    210      * @p-config    {Boolean}   async                   ready方法是否需要异步执行,默认false
    211      * @p-config    {Function}  ready(argv, data)       就绪状态
    212      * @p-config    {Function}  dataLoaded(data)        数据加载完成后调用,async为true时有用,也可以为空
    213      * @p-config    {Function}  cancel(resp)    取消
    214      * @p-config    {Function}  fail(resp)      失败
    215      * @p-config    {Function}  confirm(resp)   成功
    216      * @p-config    {Function}  all(resp)       无论成功失败都会执行的回调
    217      */
    218     WeixinApi.shareToFriend = function (data, callbacks) {
    219         _share({
    220             menu: 'menu:share:appmessage',
    221             action: 'sendAppMessage'
    222         }, {
    223             "appid": data.appId ? data.appId : '',
    224             "img_url": data.imgUrl,
    225             "link": data.link,
    226             "desc": data.desc,
    227             "title": data.title,
    228             "img_width": "640",
    229             "img_height": "640"
    230         }, callbacks);
    231     };
    232 
    233 
    234     /**
    235      * 分享到腾讯微博
    236      * @param       {Object}    data       待分享的信息
    237      * @p-config    {String}    link       链接地址
    238      * @p-config    {String}    desc       描述
    239      *
    240      * @param       {Object}    callbacks  相关回调方法
    241      * @p-config    {Boolean}   async                   ready方法是否需要异步执行,默认false
    242      * @p-config    {Function}  ready(argv, data)       就绪状态
    243      * @p-config    {Function}  dataLoaded(data)        数据加载完成后调用,async为true时有用,也可以为空
    244      * @p-config    {Function}  cancel(resp)    取消
    245      * @p-config    {Function}  fail(resp)      失败
    246      * @p-config    {Function}  confirm(resp)   成功
    247      * @p-config    {Function}  all(resp)       无论成功失败都会执行的回调
    248      */
    249     WeixinApi.shareToWeibo = function (data, callbacks) {
    250         _share({
    251             menu: 'menu:share:weibo',
    252             action: 'shareWeibo'
    253         }, {
    254             "content": data.desc,
    255             "url": data.link
    256         }, callbacks);
    257     };
    258 
    259     /**
    260      * 新的分享接口
    261      * @param       {Object}    data       待分享的信息
    262      * @p-config    {String}    appId      公众平台的appId(服务号可用)
    263      * @p-config    {String}    imgUrl     图片地址
    264      * @p-config    {String}    link       链接地址
    265      * @p-config    {String}    desc       描述
    266      * @p-config    {String}    title      分享的标题
    267      *
    268      * @param       {Object}    callbacks  相关回调方法
    269      * @p-config    {Boolean}   async                   ready方法是否需要异步执行,默认false
    270      * @p-config    {Function}  ready(argv, data)       就绪状态
    271      * @p-config    {Function}  dataLoaded(data)        数据加载完成后调用,async为true时有用,也可以为空
    272      * @p-config    {Function}  cancel(resp)    取消
    273      * @p-config    {Function}  fail(resp)      失败
    274      * @p-config    {Function}  confirm(resp)   成功
    275      * @p-config    {Function}  all(resp)       无论成功失败都会执行的回调
    276      */
    277     WeixinApi.generalShare = function (data, callbacks) {
    278         _share({
    279             menu: 'general:share'
    280         }, {
    281             "appid": data.appId ? data.appId : '',
    282             "img_url": data.imgUrl,
    283             "link": data.link,
    284             "desc": data.desc,
    285             "title": data.title,
    286             "img_width": "640",
    287             "img_height": "640"
    288         }, callbacks);
    289     };
    290 
    291     /**
    292      * 设置页面禁止分享:包括朋友圈、好友、腾讯微博、qq
    293      * @param callback
    294      */
    295     WeixinApi.disabledShare = function (callback) {
    296         callback = callback || function () {
    297             alert('当前页面禁止分享!');
    298         };
    299         ['menu:share:timeline', 'menu:share:appmessage', 'menu:share:qq',
    300             'menu:share:weibo', 'general:share'].forEach(function (menu) {
    301                 WeixinJSBridge.on(menu, function () {
    302                     callback();
    303                     return false;
    304                 });
    305             });
    306     };
    307 
    308     /**
    309      * 加关注(此功能只是暂时先加上,不过因为权限限制问题,不能用,如果你的站点是部署在*.qq.com下,也许可行)
    310      * @param       {String}    appWeixinId     微信公众号ID
    311      * @param       {Object}    callbacks       回调方法
    312      * @p-config    {Function}  fail(resp)      失败
    313      * @p-config    {Function}  confirm(resp)   成功
    314      */
    315     WeixinApi.addContact = function (appWeixinId, callbacks) {
    316         callbacks = callbacks || {};
    317         WeixinJSBridge.invoke("addContact", {
    318             webtype: "1",
    319             username: appWeixinId
    320         }, function (resp) {
    321             var success = !resp.err_msg || "add_contact:ok" == resp.err_msg
    322                 || "add_contact:added" == resp.err_msg;
    323             if (success) {
    324                 callbacks.success && callbacks.success(resp);
    325             } else {
    326                 callbacks.fail && callbacks.fail(resp);
    327             }
    328         })
    329     };
    330 
    331     /**
    332      * 调起微信Native的图片播放组件。
    333      * 这里必须对参数进行强检测,如果参数不合法,直接会导致微信客户端crash
    334      *
    335      * @param {String} curSrc 当前播放的图片地址
    336      * @param {Array} srcList 图片地址列表
    337      */
    338     WeixinApi.imagePreview = function (curSrc, srcList) {
    339         if (!curSrc || !srcList || srcList.length == 0) {
    340             return;
    341         }
    342         WeixinJSBridge.invoke('imagePreview', {
    343             'current': curSrc,
    344             'urls': srcList
    345         });
    346     };
    347 
    348     /**
    349      * 显示网页右上角的按钮
    350      */
    351     WeixinApi.showOptionMenu = function () {
    352         WeixinJSBridge.call('showOptionMenu');
    353     };
    354 
    355 
    356     /**
    357      * 隐藏网页右上角的按钮
    358      */
    359     WeixinApi.hideOptionMenu = function () {
    360         WeixinJSBridge.call('hideOptionMenu');
    361     };
    362 
    363     /**
    364      * 显示底部工具栏
    365      */
    366     WeixinApi.showToolbar = function () {
    367         WeixinJSBridge.call('showToolbar');
    368     };
    369 
    370     /**
    371      * 隐藏底部工具栏
    372      */
    373     WeixinApi.hideToolbar = function () {
    374         WeixinJSBridge.call('hideToolbar');
    375     };
    376 
    377     /**
    378      * 返回如下几种类型:
    379      *
    380      * network_type:wifi     wifi网络
    381      * network_type:edge     非wifi,包含3G/2G
    382      * network_type:fail     网络断开连接
    383      * network_type:wwan     2g或者3g
    384      *
    385      * 使用方法:
    386      * WeixinApi.getNetworkType(function(networkType){
    387      *
    388      * });
    389      *
    390      * @param callback
    391      */
    392     WeixinApi.getNetworkType = function (callback) {
    393         if (callback && typeof callback == 'function') {
    394             WeixinJSBridge.invoke('getNetworkType', {}, function (e) {
    395                 // 在这里拿到e.err_msg,这里面就包含了所有的网络类型
    396                 callback(e.err_msg);
    397             });
    398         }
    399     };
    400 
    401     /**
    402      * 关闭当前微信公众平台页面
    403      * @param       {Object}    callbacks       回调方法
    404      * @p-config    {Function}  fail(resp)      失败
    405      * @p-config    {Function}  success(resp)   成功
    406      */
    407     WeixinApi.closeWindow = function (callbacks) {
    408         callbacks = callbacks || {};
    409         WeixinJSBridge.invoke("closeWindow", {}, function (resp) {
    410             switch (resp.err_msg) {
    411                 // 关闭成功
    412                 case 'close_window:ok':
    413                     callbacks.success && callbacks.success(resp);
    414                     break;
    415 
    416                 // 关闭失败
    417                 default :
    418                     callbacks.fail && callbacks.fail(resp);
    419                     break;
    420             }
    421         });
    422     };
    423 
    424     /**
    425      * 当页面加载完毕后执行,使用方法:
    426      * WeixinApi.ready(function(Api){
    427      *     // 从这里只用Api即是WeixinApi
    428      * });
    429      * @param readyCallback
    430      */
    431     WeixinApi.ready = function (readyCallback) {
    432 
    433         /**
    434          * 加一个钩子,同时解决Android和iOS下的分享问题
    435          * @private
    436          */
    437         var _hook = function () {
    438             var _WeixinJSBridge = {};
    439             Object.keys(WeixinJSBridge).forEach(function (key) {
    440                 _WeixinJSBridge[key] = WeixinJSBridge[key];
    441             });
    442             Object.keys(WeixinJSBridge).forEach(function (key) {
    443                 if (typeof WeixinJSBridge[key] === 'function') {
    444                     WeixinJSBridge[key] = function () {
    445                         try {
    446                             var args = arguments.length > 0 ? arguments[0] : {},
    447                                 runOn3rd_apis = args.__params ? args.__params.__runOn3rd_apis || [] : [];
    448                             ['menu:share:timeline', 'menu:share:appmessage', 'menu:share:weibo',
    449                                 'menu:share:qq', 'general:share'].forEach(function (menu) {
    450                                     runOn3rd_apis.indexOf(menu) === -1 && runOn3rd_apis.push(menu);
    451                                 });
    452                         } catch (e) {
    453                         }
    454                         return _WeixinJSBridge[key].apply(WeixinJSBridge, arguments);
    455                     };
    456                 }
    457             });
    458         };
    459 
    460         if (readyCallback && typeof readyCallback == 'function') {
    461             var Api = this;
    462             var wxReadyFunc = function () {
    463                 _hook();
    464                 readyCallback(Api);
    465             };
    466             if (typeof window.WeixinJSBridge == "undefined") {
    467                 if (document.addEventListener) {
    468                     document.addEventListener('WeixinJSBridgeReady', wxReadyFunc, false);
    469                 } else if (document.attachEvent) {
    470                     document.attachEvent('WeixinJSBridgeReady', wxReadyFunc);
    471                     document.attachEvent('onWeixinJSBridgeReady', wxReadyFunc);
    472                 }
    473             } else {
    474                 wxReadyFunc();
    475             }
    476         }
    477     };
    478 
    479     /**
    480      * 判断当前网页是否在微信内置浏览器中打开
    481      */
    482     WeixinApi.openInWeixin = function () {
    483         return /MicroMessenger/i.test(navigator.userAgent);
    484     };
    485 
    486     /*
    487      * 打开扫描二维码
    488      * @param       {Object}    callbacks       回调方法
    489      * @p-config    {Boolean}   needResult      是否直接获取分享后的内容
    490      * @p-config    {String}    desc            扫描二维码时的描述
    491      * @p-config    {Function}  fail(resp)      失败
    492      * @p-config    {Function}  success(resp)   成功
    493      */
    494     WeixinApi.scanQRCode = function (callbacks) {
    495         callbacks = callbacks || {};
    496         WeixinJSBridge.invoke("scanQRCode", {
    497             needResult: callbacks.needResult ? 1 : 0,
    498             desc: callbacks.desc || 'WeixinApi Desc'
    499         }, function (resp) {
    500             switch (resp.err_msg) {
    501                 // 打开扫描器成功
    502                 case 'scanQRCode:ok':
    503                 case 'scan_qrcode:ok':
    504                     callbacks.success && callbacks.success(resp);
    505                     break;
    506 
    507                 // 打开扫描器失败
    508                 default :
    509                     callbacks.fail && callbacks.fail(resp);
    510                     break;
    511             }
    512         });
    513     };
    514 
    515     /**
    516      * 检测应用程序是否已安装
    517      *         by mingcheng 2014-10-17
    518      *
    519      * @param       {Object}    data               应用程序的信息
    520      * @p-config    {String}    packageUrl      应用注册的自定义前缀,如 xxx:// 就取 xxx
    521      * @p-config    {String}    packageName        应用的包名
    522      *
    523      * @param       {Object}    callbacks       相关回调方法
    524      * @p-config    {Function}  fail(resp)      失败
    525      * @p-config    {Function}  success(resp)   成功,如果有对应的版本信息,则写入到 resp.version 中
    526      * @p-config    {Function}  all(resp)       无论成功失败都会执行的回调
    527      */
    528     WeixinApi.getInstallState = function (data, callbacks) {
    529         callbacks = callbacks || {};
    530 
    531         WeixinJSBridge.invoke("getInstallState", {
    532             "packageUrl": data.packageUrl || "",
    533             "packageName": data.packageName || ""
    534         }, function (resp) {
    535             var msg = resp.err_msg, match = msg.match(/state:yes_?(.*)$/);
    536             if (match) {
    537                 resp.version = match[1] || "";
    538                 callbacks.success && callbacks.success(resp);
    539             } else {
    540                 callbacks.fail && callbacks.fail(resp);
    541             }
    542 
    543             callbacks.all && callbacks.all(resp);
    544         });
    545     };
    546 
    547     /**
    548      * 发送邮件
    549      * @param       {Object}  data      邮件初始内容
    550      * @p-config    {String}  subject   邮件标题
    551      * @p-config    {String}  body      邮件正文
    552      *
    553      * @param       {Object}    callbacks       相关回调方法
    554      * @p-config    {Function}  fail(resp)      失败
    555      * @p-config    {Function}  success(resp)   成功
    556      * @p-config    {Function}  all(resp)       无论成功失败都会执行的回调
    557      */
    558     WeixinApi.sendEmail = function (data, callbacks) {
    559         callbacks = callbacks || {};
    560         WeixinJSBridge.invoke("sendEmail", {
    561             "title": data.subject,
    562             "content": data.body
    563         }, function (resp) {
    564             if (resp.err_msg === 'send_email:sent') {
    565                 callbacks.success && callbacks.success(resp);
    566             } else {
    567                 callbacks.fail && callbacks.fail(resp);
    568             }
    569             callbacks.all && callbacks.all(resp);
    570         })
    571     };
    572 
    573     /**
    574      * 开启Api的debug模式,比如出了个什么错误,能alert告诉你,而不是一直很苦逼的在想哪儿出问题了
    575      * @param    {Function}  callback(error) 出错后的回调,默认是alert
    576      */
    577     WeixinApi.enableDebugMode = function (callback) {
    578         /**
    579          * @param {String}  errorMessage   错误信息
    580          * @param {String}  scriptURI      出错的文件
    581          * @param {Long}    lineNumber     出错代码的行号
    582          * @param {Long}    columnNumber   出错代码的列号
    583          */
    584         window.onerror = function (errorMessage, scriptURI, lineNumber, columnNumber) {
    585 
    586             // 有callback的情况下,将错误信息传递到options.callback中
    587             if (typeof callback === 'function') {
    588                 callback({
    589                     message: errorMessage,
    590                     script: scriptURI,
    591                     line: lineNumber,
    592                     column: columnNumber
    593                 });
    594             } else {
    595                 // 其他情况,都以alert方式直接提示错误信息
    596                 var msgs = [];
    597                 msgs.push("额,代码有错。。。");
    598                 msgs.push("\n错误信息:", errorMessage);
    599                 msgs.push("\n出错文件:", scriptURI);
    600                 msgs.push("\n出错位置:", lineNumber + '行,' + columnNumber + '列');
    601                 alert(msgs.join(''));
    602             }
    603         }
    604     };
    605 
    606 })(window);
  • 相关阅读:
    总结随笔
    Beta冲刺第七天
    Beta冲刺第六天
    Beta冲刺第五天
    Beta冲刺第四天
    Beta冲刺第三天
    POJ 2240 Arbitrage
    POJ 3660 Cow Contest
    POJ 1797 Heavy Transportation
    LightOJ 1123 Trail Maintenance
  • 原文地址:https://www.cnblogs.com/guanguan/p/4211550.html
Copyright © 2020-2023  润新知