侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

使用asp.net mvc,boostrap及knockout.js开发微信自定义菜单编辑工具(推荐)

微信(小程序)  /  管理员 发布于 7年前   272

前言

  微信的接口调试工具可以编辑自定义菜单,不过是提交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开发微信自定义菜单编辑工具,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对站的支持!


  • 上一条:
    使用微信PC端的截图dll库实现微信截图功能
    下一条:
    .net微信开发 如何获取AccessToken
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 微信模板消息改版后发送规则记录(微信订阅消息参数值内容限制说明)(1个评论)
    • 微信支付v3对接所需工具及命令(0个评论)
    • 2023年9月1日起:微信小程序必须备案才能上线运营(0个评论)
    • 腾讯官方客服回应了:微信好友上限约10000个!(1个评论)
    • 2023年做微信小程序的老铁注意:新增收费项、微信小程序获取手机号也收费了(2个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2017-10
    • 2018-01
    • 2020-03
    • 2021-06
    • 2021-10
    • 2022-03
    • 2023-02
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-10
    • 2023-11
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客