微信公众号开发(三)

自定义菜单

资料:https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Creating_Custom-Defined_Menu.html

请注意:

  1. 自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。
  2. 一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。
  3. 创建自定义菜单后,菜单的刷新策略是,在用户进入公众号会话页或公众号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)
})();

 右击执行,重新关注测试号

技术分享图片

 

微信公众号开发(三)

以上是微信公众号开发(三)的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>