自定义菜单能够帮助公众号丰富界面,让用户更好更快地理解公众号的功能。
我这里不一一说明接口内容以及注意事项了,因为官方文档随着更新会有变化,所以没必要一一列明,最好就是随时查看官方文档,会更加准确。下面我们来从当前文档中摘出来我们想要测试的功能。
1.菜单创建接口:http请求方式:POST https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
2.菜单查询接口:http请求方式:GET https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN
3.菜单删除接口:http请求方式:GET https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
4.获取自定义菜单配置接口:GET https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN
我们在wechat.js文件配置一下url变量:
//自定义菜单 menu: { create: prefix + \'menu/create?\', fetch: prefix + \'menu/get?\', del: prefix + \'menu/delete?\', current: prefix + \'get_current_selfmenu_info?\' }
然后依然在wechat.js文件中,添加菜单的相关方法:
//在weChat的原型链上增加createMenu方法 用来创建自定义菜单 weChat.prototype.createMenu = function(menu) { var that = this; return new Promise(function(resolve, reject) { that .fetchAccessToken() .then(function(data) { var url = api.menu.create + \'access_token=\' + data.access_token; //使用request发起请求 request({ method: \'POST\', url: url, body: menu, json: true }) .then(function(response) { var _data = response.body; if (_data) { resolve(_data); } else { throw new Error(\'create menu fail\'); }; }) .catch(function(err) { reject(err); }); }); }); }; //在weChat的原型链上增加getMenu方法 用来获取自定义菜单 weChat.prototype.getMenu = function() { var that = this; return new Promise(function(resolve, reject) { that .fetchAccessToken() .then(function(data) { var url = api.menu.fetch + \'access_token=\' + data.access_token; //使用request发起请求 request({ url: url, json: true }) .then(function(response) { var _data = response.body; if (_data) { resolve(_data); } else { throw new Error(\'get menu fail\'); }; }) .catch(function(err) { reject(err); }); }); }); }; //在weChat的原型链上增加delMenu方法 用来删除自定义菜单 weChat.prototype.delMenu = function() { var that = this; return new Promise(function(resolve, reject) { that .fetchAccessToken() .then(function(data) { var url = api.menu.del + \'access_token=\' + data.access_token; //使用request发起请求 request({ url: url, json: true }) .then(function(response) { var _data = response.body; if (_data) { resolve(_data); } else { throw new Error(\'delete menu fail\'); }; }) .catch(function(err) { reject(err); }); }); }); }; //在weChat的原型链上增加getCurrentMenu方法 用来删除自定义菜单 weChat.prototype.getCurrentMenu = function() { var that = this; return new Promise(function(resolve, reject) { that .fetchAccessToken() .then(function(data) { var url = api.menu.current + \'access_token=\' + data.access_token; //使用request发起请求 request({ url: url, json: true }) .then(function(response) { var _data = response.body; if (_data) { resolve(_data); } else { throw new Error(\'get current menu fail\'); }; }) .catch(function(err) { reject(err); }); }); }); };
在项目的根目录下,新建menu.js文件,用于存放菜单模板:
\'use strict\'; module.exports = { \'button\': [{ \'name\':\'点击事件\', \'type\':\'click\', \'key\':\'menu_click\' },{ \'name\':\'点出菜单1\', \'sub_button\':[{ \'name\':\'跳转URL\', \'type\':\'view\', \'url\':\'https://www.baidu.com\' },{ \'name\':\'扫码推送事件\', \'type\':\'scancode_push\', \'key\':\'qr_scan\' },{ \'name\':\'扫码推送\', \'type\':\'scancode_waitmsg\', \'key\':\'qr_scan_wait\' },{ \'name\':\'弹出系统拍照\', \'type\':\'pic_sysphoto\', \'key\':\'pic_photo\' },{ \'name\':\'弹出拍照或者相册\', \'type\':\'pic_photo_or_album\', \'key\':\'pic_photo_album\' }] },{ \'name\':\'点出菜单2\', \'sub_button\':[{ \'name\':\'微信相册发图\', \'type\':\'pic_weixin\', \'key\':\'pic_weixin\' },{ \'name\':\'地理位置\', \'type\':\'location_select\', \'key\':\'location_select\' } // ,{ // \'name\':\'下发消息(除文本消息)\', // \'type\':\'media_id\', // \'media_id\':\'\' // },{ // \'name\':\'跳转图文消息\', // \'type\':\'view_limited\', // \'media_id\':\'\' // } ] }] }
现在我们来生成菜单,打开weixin.js文件,在文件上方引入menu.js,同时初始化菜单:
var menu = require(\'./menu\'); //初始化weChat 并传入配置信息 var wechatApi = new weChat(config.wechat); //重置并初始化菜单 wechatApi.delMenu().then(function(){ return wechatApi.createMenu(menu); }) .then(function(msg){ console.log(msg); });
之后,回复函数内,在message.MsgType === \'event\'的条件里,添加菜单事件的判断:
//判断用户行为 是事件推送还是普通消息 先判断的是事件推送 if (message.MsgType === \'event\') { //订阅事件 分为搜索订阅和二维码订阅 if (message.Event === \'subscribe\') { if (message.EventKey) { console.log(\'扫描二维码进来\' + message.EventKey + \' \' + message.ticket); } //通过this.body设置回复消息 this.body = \'欢迎订阅我的公众号\'; } //取消订阅事件 else if (message.Event === \'unsubscribe\') { console.log(\'用户取消了关注\'); this.body = \'\'; } //地理位置事件 else if (message.Event === \'LOCATION\') { this.body = \'您上报的位置是:\' + message.Latitude + \'/\' + message.Longitude + \'-\' + message.Precision; } //点击事件 自定义菜单事件 else if (message.Event === \'CLICK\') { this.body = \'您点击了菜单:\' + message.EventKey; } //跳转链接事件 点击菜单跳转链接时的事件推送 else if (message.Event === \'VIEW\') { this.body = \'您点击了菜单中的链接:\' + message.EventKey; } //扫描事件 else if (message.Event === \'SCAN\') { console.log(\'关注后扫描二维码\' + message.EventKey + \' \' + message.Ticket); this.body = \'看到你扫一下哦\'; } //扫码推送事件 else if (message.Event === \'scancode_push\') { console.log(message.ScanCodeInfo.ScanType); console.log(message.ScanCodeInfo.ScanResult); this.body = \'您点击了菜单中的链接:\' + message.EventKey; } //扫码推送 else if (message.Event === \'scancode_waitmsg\') { console.log(message.ScanCodeInfo.ScanType); console.log(message.ScanCodeInfo.ScanResult); this.body = \'您点击了菜单中的:\' + message.EventKey; } //弹出系统拍照 else if (message.Event === \'pic_sysphoto\') { console.log( message.SendPicsInfo.PicList); console.log( message.SendPicsInfo.Count); this.body = \'您点击了菜单中的:\' + message.EventKey; } //弹出拍照或者相册 else if (message.Event === \'pic_photo_or_album\') { console.log( message.SendPicsInfo.PicList); console.log( message.SendPicsInfo.Count); this.body = \'您点击了菜单中的:\' + message.EventKey; } //微信相册发图 else if (message.Event === \'pic_weixin\') { console.log( message.SendPicsInfo.PicList); console.log( message.SendPicsInfo.Count); this.body = \'您点击了菜单中的:\' + message.EventKey; } //地理位置选择器 else if (message.Event === \'location_select\') { console.log(message.SendLocationInfo.Location_X); console.log(message.SendLocationInfo.Location_Y); console.log(message.SendLocationInfo.Scale); console.log(message.SendLocationInfo.Label); console.log(message.SendLocationInfo.Poiname); this.body = \'您点击了菜单中的:\' + message.EventKey; } }
这时我们取消关注,会报两个错误,第一个错误:Cannot read property \'then\' of undefined ,这个错误解决,我们在this.getAccessToken()前面加上return就可以解决。如下图:
第二个错误:TypeError: Cannot read property \'type\' of undefined ,这个错误是因为事件触发时,服务器会推送两条不同类型的事件,解决方法是,打开tools.js文件,在格式化回复体时,对content多加一个判断:
现在我们的自定义菜单就可以跑通啦~