使用asp.net mvc,boostrap及knockout.js开发微信自定义菜单编辑工具(推荐)
前言
微信的接口调试工具可以编辑自定义菜单,不过是提交json格式数据创建菜单,非常的不方便还容易出错。网上的工具不好用,所以就自己写了一个。
正文
先用bootstrap排个页面框架出来,调用自定义菜单接口需要用到accesstoken,放个输入框输入accesstoken。也不排除想直接输入appid和appsecret来获取accesstoken的用户,所以还需要下拉菜单来选择是输入accesstoken还是直接获取accesstoken。为了兼顾微信企业号应用创建菜单还需要agentid,corpid,套件永久授权码,suiteid,suitesecret,suiteticket,参数的输入框大致就是这些。
使用knockout定义好observables监控属性。并绑定到输入框上。
定义菜单展示及菜单编辑模块,排版为微信公众号菜单三个大菜单,每个大菜单下面可以配五个子菜单。大致思路如下,页面排版为六行三列,三个大菜单未配置满时在右侧显示增加菜单按钮,
每个父级菜单的子菜单未配置满时在上方显示增加菜单按钮。未配置满时以空白div占位。
定义个函数生成自定义长度数组
使用knockout定义好菜单监控属性,格式为
{ "button": [ { "name": "父级菜单1", "sub_button": [ { "type": "view", "name": "子菜单1", "url": "" } ] }, { "name": "父级菜单1", "sub_button": [ { "type": "view", "name": "子菜单2", "url": "" }, { "type": "view", "name": "子菜单1", "url": "" } ] } ] }
定义添加,编辑,删除菜单函数,定义添加编辑菜单时临时监控属性,定义当前编辑菜单索引的监控属性。
一个一个编辑菜单还不是很方便,所以还要定义菜单的 上 下 左 右 的移动,及复制粘贴功能。
function menuformvalidate() { $("#menuform").validate({ rules: { name: { required: true }, value: { required: false } }, messages: { name: { required: "请输入名称" }, value: { required: $("#txtmenubuttonvalue").attr("placeholder") } } }); } menusreset:function () { var menus = json.stringify(model.menus()); model.menus(undefined); model.menus(json.parse(menus));//刷新菜单对象 menuformvalidate();//重新绑定验证方法 }, menuindex: ko.observable(), //父级菜单索引 iseditmenu: ko.observable(false), //是否是编辑菜单 bottonindex: ko.observable(-1), //编辑菜单的父级菜单索引 subbottonindex: ko.observable(-1), //编辑菜单的子菜单索引 menu: ko.observable(),//编辑菜单时临时监控属性 copymenu: ko.observable(),//复制的菜单对象 copy: function () { //复制 if (model.menu() != undefined) { var menu = json.stringify(model.menu()); model.copymenu(json.parse(menu)); model.menu(undefined); } }, paste: function () {//粘贴 if (model.copymenu() != undefined) { var menu = json.parse(json.stringify(model.copymenu())); if (model.subbottonindex() !== -1 && menu.sub_button != undefined || (!model.iseditmenu() && model.menuindex() != undefined)) { delete menu.sub_button; } model.menu(menu); menuformvalidate(); } }, up: function () {//向上移动 var bottonindex = model.bottonindex(); var subbottonindex = model.subbottonindex(); var newsubbottonindex = subbottonindex - 1; model.menus().button[bottonindex].sub_button[subbottonindex] = model.menus().button[bottonindex].sub_button[newsubbottonindex]; model.menus().button[bottonindex].sub_button[newsubbottonindex] = model.menu(); model.menusreset(); model.subbottonindex(newsubbottonindex); }, down: function () {//向下移动 var bottonindex = model.bottonindex(); var subbottonindex = model.subbottonindex(); var newsubbottonindex = subbottonindex + 1; model.menus().button[bottonindex].sub_button[subbottonindex] = model.menus().button[bottonindex].sub_button[newsubbottonindex]; model.menus().button[bottonindex].sub_button[newsubbottonindex] = model.menu(); model.menusreset(); model.subbottonindex(newsubbottonindex); }, left: function () {//向左移动 var bottonindex = model.bottonindex(); var subbottonindex = model.subbottonindex(); if (subbottonindex === -1) { var newbottonindex = bottonindex - 1; model.menus().button[bottonindex] = model.menus().button[newbottonindex]; model.menus().button[newbottonindex] = model.menu(); model.menusreset(); model.bottonindex(newbottonindex); } }, right: function () {//向右移动 var bottonindex = model.bottonindex(); var subbottonindex = model.subbottonindex(); if (subbottonindex === -1) { var newbottonindex = bottonindex + 1; model.menus().button[bottonindex] = model.menus().button[newbottonindex]; model.menus().button[newbottonindex] = model.menu(); model.menusreset(); model.bottonindex(newbottonindex); } }, editmenu: function (obj, bottonindex, subbottonindex) {//编辑菜单 model.bottonindex(bottonindex); model.subbottonindex(subbottonindex); model.iseditmenu(true); var data = json.stringify(obj); model.menu(json.parse(data)); menuformvalidate(); }, addmenu: function (index) {//添加菜单 model.bottonindex(-1); model.subbottonindex(-1); model.iseditmenu(false); model.menuindex(index); var menu = { type: "view", name: "", value: "" }; model.menu(menu); menuformvalidate(); }, deletemenu: function () {//删除菜单 $(model.menus().button).each(function (index, item) { if (index === model.bottonindex() && model.subbottonindex() === -1) { model.menus().button.splice(index, 1); } if (item.sub_button instanceof array) { $(item.sub_button).each(function (index1) { if (index === model.bottonindex() && index1 === model.subbottonindex()) { item.sub_button.splice(index1, 1); } }); } }); model.menu(undefined); model.menuindex(undefined); model.bottonindex(-1); model.subbottonindex(-1); model.menusreset(); }, cancelmenusave: function () {//取消编辑,重置参数 model.menu(undefined); model.menuindex(undefined); model.bottonindex(-1); model.subbottonindex(-1); }, menusave: function () {//保存编辑的菜单 if (!$("#menuform").data("validator").form()) { return; } if (model.iseditmenu()) { var menuindex = model.bottonindex(); var submenuindex = model.subbottonindex(); if (submenuindex === -1) { model.menus().button[menuindex] = model.menu(); } else { model.menus().button[menuindex].sub_button[submenuindex] = model.menu(); } } else { if (model.menuindex() != undefined) { if (model.menus().button[model.menuindex()].sub_button == undefined) { model.menus().button[model.menuindex()].sub_button = new array(); } model.menus().button[model.menuindex()].sub_button.unshift(model.menu()); } else { model.menus().button.push(model.menu()); } } model.menu(undefined); model.menuindex(undefined); model.bottonindex(-1); model.subbottonindex(-1); model.menusreset(); },
绑定好监控属性,生成菜单排版
<div class="panel-body" data-bind="with:menus" id="divmenu" style="display: none;"> <div style="height: 200px;" data-bind="foreach:newarray(3)"> <div class="list-group col-xs-4 clearfill bn"> <!--ko if:($parent.button.length>0 && $parent.button[$index()]!=undefined && $parent.button[$index()].sub_button!=undefined ) --> <!--ko foreach:newarray((4-$parent.button[$index()].sub_button.length)) --> <div class="list-group-item bn"></div> <!--/ko--> <!--ko if:$parent.button[$index()].sub_button.length<5 --> <div class="list-group-item" data-bind="click:function (){$root.addmenu($index())}"><i class="fa fa-plus"></i> </div> <!--/ko--> <!--ko foreach:($parent.button[$index()].sub_button) --> <div class="list-group-item" data-bind="text:name,attr:{'bottonindex':$parent.value,'subbottonindex':$index()},click:function (){$root.editmenu($data,$parent.value,$index())}"></div> <!--/ko--> <!--/ko --> <!--ko if: $parent.button[$index()]!=undefined && $parent.button[$index()].sub_button==undefined --> <div class="list-group-item bn"></div> <div class="list-group-item bn"></div> <div class="list-group-item bn"></div> <div class="list-group-item bn"></div> <div class="list-group-item" data-bind="click:function (){$root.addmenu($index())}"><i class="fa fa-plus"></i> </div> <!--/ko--> <!--ko if: $parent.button[$index()]==undefined --> <div class="list-group-item bn"></div> <div class="list-group-item bn"></div> <div class="list-group-item bn"></div> <div class="list-group-item bn"></div> <div class="list-group-item bn"></div> <!--/ko--> </div> </div> <!--ko foreach:button --> <div class="col-xs-4 list-group-item list-group-item-danger" data-bind="text:name,attr:{'bottonindex':$index()},click:function (){$root.editmenu($data,$index(),-1)}"></div> <!--/ko--> <!--ko if:button.length < 3 --> <div class="col-xs-4 list-group-item" data-bind="click:function (){$root.addmenu();}"><i class="fa fa-plus"></i> </div> <!--/ko--> <div class="clearfix"></div> <div class="col-xs-12" style="border: 1px solid #eeeeee; padding-top: 15px; margin-top: 15px;" data-bind="with:$root.menu,visible:($root.menu()!=undefined)"> <form id="menuform" onsubmit="return false;"> <div class="form-group col-xs-4"> <input type="text" class="form-control" name="name" placeholder="请输入名称" data-bind="value:name"> </div> <div class="form-group col-xs-4"> <select class="form-control" onchange="$('#txtmenubuttonvalue') .attr('placeholder', $(this).find('option:selected').attr('pl'))" data-bind="value:type"> <option value="view" pl="请输入url">跳转url</option> <option value="click" pl="请输入key">点击推事件</option> <option value="scancode_push" pl="请输入key">扫码推事件</option> <option value="scancode_waitmsg" pl="请输入key">扫码推事件且弹出“消息接收中”提示框</option> <option value="pic_sysphoto" pl="请输入key">弹出系统拍照发图</option> <option value="pic_photo_or_album" pl="请输入key">弹出拍照或者相册发图</option> <option value="pic_weixin" pl="请输入key"> 弹出微信相册发图器</option> <option value="location_select" pl="请输入key">弹出地理位置选择器</option> </select> </div> <div class="form-group col-xs-8"> <input type="text" id="txtmenubuttonvalue" name="value" class="form-control" placeholder="请输入url" data-bind="value:value"> </div> <div class="form-group col-xs-12"> <button type="submit" class="btn btn-primary" data-bind="click:$root.menusave">确定</button> <button type="submit" class="btn btn-danger" data-bind="visible:$root.iseditmenu,click:$root.deletemenu">删除</button> <button type="button" class="btn btn-default" title="上移" data-bind="visible:$root.iseditmenu(),disable:!$root.isup(),click:$root.up"><i class="fa fa-chevron-circle-up" aria-hidden="true"></i></button> <button type="button" class="btn btn-default" title="下移" data-bind="visible:$root.iseditmenu(),disable:!$root.isdown(),click:$root.down"><i class="fa fa-chevron-circle-down" aria-hidden="true"></i></button> <button type="button" class="btn btn-default" title="左移" data-bind="visible:$root.iseditmenu(),disable:!$root.isleft(),click:$root.left"><i class="fa fa-chevron-circle-left" aria-hidden="true"></i></button> <button type="button" class="btn btn-default" title="右移" data-bind="visible:$root.iseditmenu(),disable:!$root.isright(),click:$root.right"><i class="fa fa-chevron-circle-right" aria-hidden="true"></i></button> <button type="button" class="btn btn-default" title="复制菜单" data-bind="visible:$root.iseditmenu(),click:$root.copy">复制</button> <button type="button" class="btn btn-default" title="粘贴菜单" data-bind="click:$root.paste">粘贴</button> <button type="submit" class="btn btn-default" data-bind="click:$root.cancelmenusave">关闭</button> </div> </form> </div> <div class="clearfix"></div> </div>
最后增加菜单的查询函数及发布函数。因为编辑菜单方便,菜单对象和微信自定义菜单接口所需要的json格式不对应,所以在查询现有菜单和发布菜单时,需要对json数据进行一下格式变化。,
editmenus: function (isquery) { if (isquery == undefined) { var menu = {}; menu.button = new array(); model.menus(menu); } else { var appid = model.appid(); var appsecret = model.appsecret(); var accesstoken = model.accesstoken(); var type = model.type(); var tokentype = model.tokentype(); var corpid = model.corpid(); var permanentcode = model.permanentcode(); var agentid = model.agentid(); var suiteid = model.suiteid(); var suitesecret = model.suitesecret(); var suiteticket = model.suiteticket(); if (type === "1" && tokentype === "2") { if (appid == undefined || $.trim(appid).length === 0) { alert("请输入appid"); return; } if (appsecret == undefined || $.trim(appsecret).length === 0) { alert("请输入appsecret"); return; } } else if (type === "2" && tokentype === "2") { if (corpid == undefined || $.trim(corpid).length === 0) { alert("请输入corpid"); return; } if (permanentcode == undefined || $.trim(permanentcode).length === 0) { alert("请输入永久授权码"); return; } if (agentid == undefined || $.trim(agentid).length === 0) { alert("请输入agentid"); return; } if (suiteid == undefined || $.trim(suiteid).length === 0) { alert("请输入suiteid"); return; } if (suitesecret == undefined || $.trim(suitesecret).length === 0) { alert("请输入suitesecret"); return; } if (suiteticket == undefined || $.trim(suiteticket).length === 0) { alert("请输入suiteticket"); return; } } else if (tokentype === "1") { if (accesstoken == undefined || $.trim(accesstoken).length === 0) { alert("请输入accesstoken"); return; } } $("#btnquerymenu").button("查询中..."); $.ajax({ url: "", datatype: "json", type: "post", async: true, data: json.stringify({ appid: appid, appsecret: appsecret, accesstoken: accesstoken, type: type, tokentype: tokentype, corpid: corpid, permanentcode: permanentcode, agentid: agentid, suiteid: suiteid, suitesecret: suitesecret, suiteticket: suiteticket }), contenttype: "application/json; charset=utf-8", success: function (obj) { $("#btnquerymenu").button("reset"); if (obj.success) { var data = obj.data; var menus = json.parse(data).menu; $(menus.button).each(function (index, item) { if (item.type === "view") { item.value = item.url; delete item.url; } else { item.value = item.key; delete item.key; } if (item.type == undefined) { item.type = "view"; item.value = ""; } if (item.sub_button instanceof array) { $(item.sub_button).each(function (index1, item2) { if (item2.type === "view") { item2.value = item2.url; delete item2.url; } else { item2.value = item2.key; delete item2.key; } }); } }); model.menu(undefined); model.menuindex(undefined); model.bottonindex(-1); model.subbottonindex(-1); model.menus(undefined); model.menus(menus); } else { alert(obj.messages); } }, error: function (xmlhttprequest, textstatus, errorthrown) { $("#btnquerymenu").button("reset"); console.error(errorthrown); } }); } }, savemenus: function () { var menus = json.parse(json.stringify(model.menus())); $(menus.button).each(function (index, item) { if (item.type === "view") { item.url = item.value; delete item.value; } else { item.key = item.value; delete item.value; } if (item.sub_button instanceof array) { $(item.sub_button).each(function (index1, item2) { if (item2.type === "view") { item2.url = item2.value; delete item2.value; } else { item2.key = item2.value; delete item2.value; } }); if (item.sub_button.length > 0) { delete item.key; delete item.url; delete item.type; } else { delete item.sub_button; } } }); console.log(json.stringify(menus)); var appid = model.appid(); var appsecret = model.appsecret(); var accesstoken = model.accesstoken(); var type = model.type(); var tokentype = model.tokentype(); var agentid = model.agentid(); var suiteid = model.suiteid(); var suitesecret = model.suitesecret(); var suiteticket = model.suiteticket(); if (type === "1" && tokentype === "2") { if (appid == undefined || $.trim(appid).length === 0) { alert("请输入appid"); return; } if (appsecret == undefined || $.trim(appsecret).length === 0) { alert("请输入appsecret"); return; } } else if (type === "2" && tokentype === "2") { if (agentid == undefined || $.trim(agentid).length === 0) { alert("请输入agentid"); return; } if (suiteid == undefined || $.trim(suiteid).length === 0) { alert("请输入suiteid"); return; } if (suitesecret == undefined || $.trim(suitesecret).length === 0) { alert("请输入suitesecret"); return; } if (suiteticket == undefined || $.trim(suiteticket).length === 0) { alert("请输入suiteticket"); return; } } else if (tokentype === "1") { if (accesstoken == undefined || $.trim(accesstoken).length === 0) { alert("请输入accesstoken"); return; } } $("#btnsubmitmenu").button("发布中..."); $.ajax({ url: "", datatype: "json", type: "post", async: true, data: json.stringify({ appid: appid, appsecret: appsecret, accesstoken: accesstoken, type: type, tokentype: tokentype, agentid: agentid, suiteid: suiteid, suitesecret: suitesecret, suiteticket: suiteticket, menu: json.stringify(menus) }), contenttype: "application/json; charset=utf-8", success: function (obj) { $("#btnsubmitmenu").button("reset"); if (obj.success) { alert("发布成功"); } else { alert(obj.messages); } }, error: function (xmlhttprequest, textstatus, errorthrown) { $("#btnsubmitmenu").button("reset"); console.error(errorthrown); } }); }
最终效果如下
以上所述是小编给大家介绍的使用asp.net mvc,boostrap及knockout.js开发微信自定义菜单编辑工具,希望对大家有所帮助