自定义菜单
资料:https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Creating_Custom-Defined_Menu.html
请注意:
- 自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。
- 一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。
- 创建自定义菜单后,菜单的刷新策略是,在用户进入公众号会话页或公众号profile页时,如果发现上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,如果菜单有更新,就会刷新客户端的菜单。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果。 ?
创建菜单接口调用请求说明:
请求地址: https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
请求方式:POST
删除菜单接口调用请求说明:
请求地址:https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
请求方式:GET
查询菜单接口调用请求说明
请求地址:https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN
请求方式: GET
示例:
// 引入request-promist-native const rp = require(‘request-promise-native‘); // 引入fs方法 const {writeFile, readFile} = require(‘fs‘); var app = function () { return { /** * 用来获取access_token * */ async getAccessToken() { // 定义请求父地址 const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx4cac0ae3b7cb88dc&secret=e895c1174c407d88bed2bf34e705c56b` /* * 发送请求 * request * request-promist-native * 下载:npm i request request-promise-native * */ return new Promise((resolve, reject) => { rp({method: ‘GET‘, url, json: true}).then(res => { // { //获取到的凭证 // access_token: ‘34_4CwWFJkJN8yAvRqm4q4eqH_SozmhKqXqDDJ1gJ9HLWhD9FFnPX-sp5dxTlbhIhsmUFtFb471mCWkWjQREVmVpwewmLW45DD2MMD3tWXEjIWbsnqvB1f5ZN-d7IiXQ_UVgcOKlsx89cdUwVsgSQHgAGAZXO‘, // expires_in: 7200 // 过期时间 // } // 设置access_token的过期时间 res.expires_in = Date.now() + (res.expires_in - 5 * 60) * 1000; // 将promise对象状态改为成功的状态 resolve(res) }).catch(err => { reject(‘getAccessToken方法出了问题:‘ + err) }) }) }, /** * 用来保存access_token的方法 * @param accessToken 要保存的 * */ saveAccessToken(accessToken) { // 保存 return new Promise((resolve, reject) => { writeFile(‘./accessToken‘, JSON.stringify(accessToken), err => { if (!err) { resolve() } else { reject(‘saveAccessToken方法出了问题‘ + err) } }) }) }, /** * 用来读取access_token的方法 * */ readAccessToken() { // 保存 return new Promise((resolve, reject) => { readFile(‘./accessToken‘, (err, date) => { if (!err) { resolve(JSON.parse(date)) } else { reject(‘saveAccessToken方法出了问题‘ + err) } }) }) }, /** * 检查 access_token 是否是有效的 * @param data * */ isValidAccessToken(data) { // 检查传入的参数是否是有效的 if (!data && !data.access_token && !data.expires_in) { return false // 代表access_token无效的 } return data.expires_in > Date.now(); }, /** * 用来获取没有过期的access_token * */ async fetchAccessToken() { if (this.access_token && this.expires_in && this.isValidAccessToken(this)) { // 说明之前保存过access_token,并且它是有效的,直接使用 return Promise.resolve({ access_token: this.access_token, expires_in: this.expires_in }) } return this.readAccessToken() .then(async res => { // 本地文件 // 判断是否过期 if (this.isValidAccessToken(res)) { return Promise.resolve(res); } else { // 无效的:发送请求获取access_token const res = await this.getAccessToken() // 保存下来,直接使用 await this.saveAccessToken(res); // 将请求回来的access_token返回出去 return Promise.resolve(res); } }).catch(async err => { // 没有本地文件 // 发送请求获取access_token const res = await this.getAccessToken() // 保存下来,直接使用 await this.saveAccessToken(res); // 将请求回来的access_token返回出去 return Promise.resolve(res); } ).then(res => { // 将access_token挂载到this中 this.access_token = res.access_token; this.expires_in = res.expires_in; // 返回res包装了一层promise对象 // 是this.readAccessToken()最终的返回值 return Promise.resolve(res); }) }, /* * 创建自定义菜单 * */ createMenu(menu) { return new Promise(async (resolve, reject) => { try { // 获取access_token const data = await this.fetchAccessToken(); // 定义请求地址 const url = `https://api.weixin.qq.com/cgi-bin/menu/create?access_token=${data.access_token}` const result = rp({method: ‘POST‘,url,json:true,body:menu}); resolve(result) } catch (e) { reject(‘createMenu方法:‘ + e) } }) }, /* * 删除自定义菜单 * */ deleteMenu() { return new Promise(async (resolve, reject) => { try { const data = await this.fetchAccessToken(); const url = `https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=${data.access_token}`; const result =await rp({method:‘GET‘,url,json:true}); resolve(result) }catch (e) { reject(‘deleteMenu:‘+ e) } }) }, /* * 查询自定义菜单 * */ getMenu() { return new Promise(async (resolve, reject) => { try { const data = await this.fetchAccessToken(); const url = `https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=${data.access_token}`; const result =await rp({method:‘GET‘,url,json:true}); resolve(result) }catch (e) { reject(‘deleteMenu:‘+ e) } }) } } }; // 菜单 const menu = { "button":[ { "name":"点击事件", "sub_button":[ { "type":"click", "name":"功能说明", "key":"click事件" }, { "type":"click", "name":"菜单模式1", "key":"click1事件" }, { "type":"click", "name":"菜单模式2", "key":"click2事件" } ] }, { "name":"菜单", "sub_button":[ { "type":"view", "name":"搜索", "url":"http://www.soso.com/" }, { "type": "scancode_waitmsg", "name": "扫码带提示", "key": "rselfmenu_0_0", "sub_button": [ ] }, { "type": "scancode_push", "name": "扫码推事件", "key": "rselfmenu_0_1", "sub_button": [ ] } ] },{ "name": "发图", "sub_button": [ { "type": "pic_sysphoto", "name": "系统拍照发图", "key": "rselfmenu_1_0", "sub_button": [ ] }, { "type": "pic_photo_or_album", "name": "拍照或者相册发图", "key": "rselfmenu_1_1", "sub_button": [ ] }, { "type": "pic_weixin", "name": "微信相册发图", "key": "rselfmenu_1_2", "sub_button": [ ] }, { "name": "发送位置", "type": "location_select", "key": "rselfmenu_2_0" }, ] }, ] }; (async () => { // 删除之前的自定义菜单 let result = await app().deleteMenu(); console.log(result) // 创建新的菜单 result = await app().createMenu(menu); console.log(result) // 查询菜单 result = await app().getMenu(); console.log(result) })();
右击执行,重新关注测试号