页面效果是如此这般的
特别说明:实习方式仿站乐享微信 但又不完全依照!!!
首先介绍下环境配置
wamp环境 + thinkphp框架实现的!
核心:自定义菜单生成到微信端:从数据库取出数据——>生产微信自定义菜单。
这里有三个难点:
1. 数据库的设计:一个表实现(用PID来识别主菜单及子菜单的区别)。
数据库如下(MYSQL):
当然表绝对不止这些内容 但是主要说明一下微信自定义菜单表对应的关系就可以了
--
-- 表的结构 `wx_custom_menu`
--
CREATE TABLE IF NOT EXISTS `wx_custom_menu` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`parentid` mediumint(8) unsigned NOT NULL COMMENT ‘一级菜单ID‘,
`title` char(10) NOT NULL COMMENT ‘菜单名称‘,
`key` varchar(200) NOT NULL COMMENT ‘此关键字字段可URL或关键词,如百度地图链接比够长,需添加200‘,
`isshow` tinyint(1) unsigned NOT NULL COMMENT ‘是否显示菜单‘,
`listsort` tinyint(3) unsigned NOT NULL COMMENT ‘一级菜单ID‘,
PRIMARY KEY (`id`),
KEY `idx_wxid_userid` (`wxid`,`userid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=110 ;
-- 表的结构 `wx_custom_menu`
--
CREATE TABLE IF NOT EXISTS `wx_custom_menu` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`parentid` mediumint(8) unsigned NOT NULL COMMENT ‘一级菜单ID‘,
`title` char(10) NOT NULL COMMENT ‘菜单名称‘,
`key` varchar(200) NOT NULL COMMENT ‘此关键字字段可URL或关键词,如百度地图链接比够长,需添加200‘,
`isshow` tinyint(1) unsigned NOT NULL COMMENT ‘是否显示菜单‘,
`listsort` tinyint(3) unsigned NOT NULL COMMENT ‘一级菜单ID‘,
PRIMARY KEY (`id`),
KEY `idx_wxid_userid` (`wxid`,`userid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=110 ;
首先说明下:wxid,userid这两个字段可不用 但是我这原本是微信开发用来识别微信公众号以及用户的ID。最后也做了个索引!
2. 页面的输出:
Thinkphp框架的写法:
class CustomMenuAction extends UserAction{
public function index() {
$arr = $this->selectDb();
$this->assign(‘arr‘,$arr);
$this->display();
}
public function index() {
$arr = $this->selectDb();
$this->assign(‘arr‘,$arr);
$this->display();
}
//从数据库中查找数据并重组数组
public function selectDb(){
public function selectDb(){
//从表中根据isshow是否显示这个条件查询出数据
$menu=M(‘custom_menu‘)->where(array(‘isshow‘=>1))->select();
$arr = array();
$menu=M(‘custom_menu‘)->where(array(‘isshow‘=>1))->select();
$arr = array();
//这里是重组数据
foreach ($menu as $value){
if($value[‘parentid‘] == 0){
$arr[$value[‘id‘]]=$value;
}else{
$arr[$value[‘parentid‘]][‘sub‘][$value[‘id‘]]=$value;
}
}
foreach ($menu as $value){
if($value[‘parentid‘] == 0){
$arr[$value[‘id‘]]=$value;
}else{
$arr[$value[‘parentid‘]][‘sub‘][$value[‘id‘]]=$value;
}
}
//调用排序 使结果逆向排序
$arr = $this->array_sort($arr,‘listsort‘);
foreach ($arr as $key=>$row){
foreach ($row as $r)
if(is_array($r)){
$arr[$key][‘sub‘] = $this->array_sort($r,‘listsort‘);
}
}
return $arr;
}
$arr = $this->array_sort($arr,‘listsort‘);
foreach ($arr as $key=>$row){
foreach ($row as $r)
if(is_array($r)){
$arr[$key][‘sub‘] = $this->array_sort($r,‘listsort‘);
}
}
return $arr;
}
/* 二维数组按指定的键值排序
* $array 数组
* $key排序键值
* $type排序方式
*/
function array_sort($arr, $keys, $type = ‘desc‘) {
$keysvalue = $new_array = array();
foreach ($arr as $k => $v) {
$keysvalue[$k] = $v[$keys];
}
if ($type == ‘asc‘) {
asort($keysvalue);
} else {
arsort($keysvalue);
}
reset($keysvalue);
foreach ($keysvalue as $k => $v) {
$new_array[$k] = $arr[$k];
}
return $new_array;
}
* $array 数组
* $key排序键值
* $type排序方式
*/
function array_sort($arr, $keys, $type = ‘desc‘) {
$keysvalue = $new_array = array();
foreach ($arr as $k => $v) {
$keysvalue[$k] = $v[$keys];
}
if ($type == ‘asc‘) {
asort($keysvalue);
} else {
arsort($keysvalue);
}
reset($keysvalue);
foreach ($keysvalue as $k => $v) {
$new_array[$k] = $arr[$k];
}
return $new_array;
}
}
必要说明:后续的代码都是写进上面的类。
具体结果格式应该呈现这样的:
好了 到这里class就写好了
那么问题来了!
html怎么搞呢
3. 页面JS 其实JQuery更方便 这里我直接拉取乐享的,然后修改了一下。
页面还有一个增加子菜单的效果,这个用JS解决!
代码直接贴上不多说了 唯一的重点就是一个地方,增加子菜单这里
//替换parentid的value值为主菜单ID
for(var i = 0; i <= typedata.length - 1; i++) {
var cell = row.insertCell(i);
cell.colSpan = typedata[i][0];
var tmp = typedata[i][1];
if(typedata[i][2]) {
cell.className = typedata[i][2];
}
//替换parentid的value值为主菜单ID
tmp = tmp.replace(/\{(n)\}/g, function($1) {return addrowkey;});
tmp = tmp.replace(/\{[0-9]+\}/g, function($1, $2) {return val});
cell.innerHTML = tmp;
}
for(var i = 0; i <= typedata.length - 1; i++) {
var cell = row.insertCell(i);
cell.colSpan = typedata[i][0];
var tmp = typedata[i][1];
if(typedata[i][2]) {
cell.className = typedata[i][2];
}
//替换parentid的value值为主菜单ID
tmp = tmp.replace(/\{(n)\}/g, function($1) {return addrowkey;});
tmp = tmp.replace(/\{[0-9]+\}/g, function($1, $2) {return val});
cell.innerHTML = tmp;
}
这最后3行代码尤其重要!用正则替换掉增加的节点名称 <input type="hidden" name="new[parentid][]" value="{1}" />这个value="{1}"替换成主菜单ID,
这步非常重要 如果不成功则增删改都会出问题
详细代码如下:
<script type="text/JavaScript">
var rowtypedata = [
[
[1,‘<input name="new[listsort][]" value="" style=" width:90%" size="3" type="text" class="px" >‘,
‘td25‘],
[1, ‘<input name="new[title][]" value="" size="15" style=" width:90%" type="text" class="px" >‘],
[1, ‘<input name="new[key][]" value="" size="15" type="text" class="px" style=" width:90%" > <input type="hidden" name="new[parentid][]" value="0" />‘],
[1,‘<input class="checkbox" type="checkbox" name="new[isshow][]" checked="checked" value="1" >‘,‘‘],
[1,‘‘,‘‘]
],
[
[1,‘<input name="new[listsrot][]" value="" size="3" style=" width:90%" type="text" class="px" >‘, ‘td25‘],
[1, ‘<div class=\"board\"><input name="new[title][]" value="" size="15" style=" width:90%" type="text" class="px" ></div>‘],
[1, ‘<input name="new[key][]" value="" size="15" style=" width:90%" type="text" class="px" > <input type="hidden" name="new[parentid][]" value="{1}" />‘] ,
[1,‘<input class="checkbox" type="checkbox" checked="checked" name="new[isshow][]" value="1" >‘,‘‘],
[1,‘‘,‘‘]
]
];
var addrowdirect = 0;
var addrowkey = 0;
function addrow(obj, type ,val) {
var table = obj.parentNode.parentNode.parentNode.parentNode.parentNode;
if(!addrowdirect) {
var row = table.insertRow(obj.parentNode.parentNode.parentNode.rowIndex);
} else {
var row = table.insertRow(obj.parentNode.parentNode.parentNode.rowIndex + 1);
}
var typedata = rowtypedata[type];
for(var i = 0; i <= typedata.length - 1; i++) {
var cell = row.insertCell(i);
cell.colSpan = typedata[i][0];
var tmp = typedata[i][1];
if(typedata[i][2]) {
cell.className = typedata[i][2];
}
//替换parentid的value值为主菜单ID
tmp = tmp.replace(/\{(n)\}/g, function($1) {return addrowkey;});
tmp = tmp.replace(/\{[0-9]+\}/g, function($1, $2) {return val});
cell.innerHTML = tmp;
}
addrowkey ++;
addrowdirect = 0;
}
function deleterow(obj) {
var table = obj.parentNode.parentNode.parentNode.parentNode.parentNode;
var tr = obj.parentNode.parentNode.parentNode;
table.deleteRow(tr.rowIndex);
}
function dropmenu(obj){
showMenu({‘ctrlid‘:obj.id, ‘menuid‘:obj.id + ‘child‘, ‘evt‘:‘mouseover‘});
$(obj.id + ‘child‘).style.top = (parseInt($(obj.id + ‘child‘).style.top) - Math.max(document.body.scrollTop, document.documentElement.scrollTop)) + ‘px‘;
if(BROWSER.ie > 6 || !BROWSER.ie) {
$(obj.id + ‘child‘).style.left = (parseInt($(obj.id + ‘child‘).style.left) - Math.max(document.body.scrollLeft, document.documentElement.scrollLeft)) + ‘px‘;
}
}
var rowtypedata = [
[
[1,‘<input name="new[listsort][]" value="" style=" width:90%" size="3" type="text" class="px" >‘,
‘td25‘],
[1, ‘<input name="new[title][]" value="" size="15" style=" width:90%" type="text" class="px" >‘],
[1, ‘<input name="new[key][]" value="" size="15" type="text" class="px" style=" width:90%" > <input type="hidden" name="new[parentid][]" value="0" />‘],
[1,‘<input class="checkbox" type="checkbox" name="new[isshow][]" checked="checked" value="1" >‘,‘‘],
[1,‘‘,‘‘]
],
[
[1,‘<input name="new[listsrot][]" value="" size="3" style=" width:90%" type="text" class="px" >‘, ‘td25‘],
[1, ‘<div class=\"board\"><input name="new[title][]" value="" size="15" style=" width:90%" type="text" class="px" ></div>‘],
[1, ‘<input name="new[key][]" value="" size="15" style=" width:90%" type="text" class="px" > <input type="hidden" name="new[parentid][]" value="{1}" />‘] ,
[1,‘<input class="checkbox" type="checkbox" checked="checked" name="new[isshow][]" value="1" >‘,‘‘],
[1,‘‘,‘‘]
]
];
var addrowdirect = 0;
var addrowkey = 0;
function addrow(obj, type ,val) {
var table = obj.parentNode.parentNode.parentNode.parentNode.parentNode;
if(!addrowdirect) {
var row = table.insertRow(obj.parentNode.parentNode.parentNode.rowIndex);
} else {
var row = table.insertRow(obj.parentNode.parentNode.parentNode.rowIndex + 1);
}
var typedata = rowtypedata[type];
for(var i = 0; i <= typedata.length - 1; i++) {
var cell = row.insertCell(i);
cell.colSpan = typedata[i][0];
var tmp = typedata[i][1];
if(typedata[i][2]) {
cell.className = typedata[i][2];
}
//替换parentid的value值为主菜单ID
tmp = tmp.replace(/\{(n)\}/g, function($1) {return addrowkey;});
tmp = tmp.replace(/\{[0-9]+\}/g, function($1, $2) {return val});
cell.innerHTML = tmp;
}
addrowkey ++;
addrowdirect = 0;
}
function deleterow(obj) {
var table = obj.parentNode.parentNode.parentNode.parentNode.parentNode;
var tr = obj.parentNode.parentNode.parentNode;
table.deleteRow(tr.rowIndex);
}
function dropmenu(obj){
showMenu({‘ctrlid‘:obj.id, ‘menuid‘:obj.id + ‘child‘, ‘evt‘:‘mouseover‘});
$(obj.id + ‘child‘).style.top = (parseInt($(obj.id + ‘child‘).style.top) - Math.max(document.body.scrollTop, document.documentElement.scrollTop)) + ‘px‘;
if(BROWSER.ie > 6 || !BROWSER.ie) {
$(obj.id + ‘child‘).style.left = (parseInt($(obj.id + ‘child‘).style.left) - Math.max(document.body.scrollLeft, document.documentElement.scrollLeft)) + ‘px‘;
}
}
</script>
4. 增删改管理
直接贴代码
/**
* 添加主菜单到数据库
* title 主菜单名称
* isshow 是否显示
* key 关键字/URL
* parentid 是否是一级菜单--0为主菜单
*/
public function addMenuToDb(){
$wx_menu_db = M(‘custom_menu‘);
$array= array();
//添加新的数据 -- 重新组合数组
foreach ($this->_post(‘new‘) as $value){
foreach ($value as $key=>$val){
$array[$key][]=$val;
}
}
foreach ($array as $v){
//分别赋值,对应表里的5个字段位
$data[‘wxid‘] = $this->wxid;
$data[‘userid‘] = $this->userid;
$data[‘listsort‘] = $v[0];
$data[‘title‘] = $v[1];
$data[‘key‘] = $v[2];
$data[‘parentid‘] = $v[3];
$data[‘isshow‘] = $v[4];
if(!empty($data[‘title‘]) && !empty($data[‘key‘])){
$add = $wx_menu_db->data($data)->add();
}
}
$save = array();
//更新旧数据
foreach ($this->_post(‘ps‘) as $ps){
$temp[‘wxid‘] = $this->wxid;
$temp[‘userid‘] = $this->userid;
$temp[‘id‘] = $ps[‘id‘];
$temp[‘listsort‘] = $ps[‘listsort‘];
$temp[‘title‘] = $ps[‘title‘];
$temp[‘key‘] = $ps[‘key‘];
$temp[‘parentid‘] = $ps[‘parentid‘];
$temp[‘isshow‘] = $ps[‘isshow‘];
$save[] = $wx_menu_db->where(array(‘id‘=>$temp[‘id‘]))->data($temp)->save();
}
//判断是否有修改过
foreach($save as $s){
if($s){
$a=1;
}
}
if($add || $a){
$this->success(‘操作成功,正在返回...‘,U(‘CustomMenu/custommenu‘,array(‘wxid‘=>$this->wxid)));
}else{
$this->error(‘操作无影响!‘,U(‘CustomMenu/custommenu‘,array(‘wxid‘=>$this->wxid)));
}
}
* 添加主菜单到数据库
* title 主菜单名称
* isshow 是否显示
* key 关键字/URL
* parentid 是否是一级菜单--0为主菜单
*/
public function addMenuToDb(){
$wx_menu_db = M(‘custom_menu‘);
$array= array();
//添加新的数据 -- 重新组合数组
foreach ($this->_post(‘new‘) as $value){
foreach ($value as $key=>$val){
$array[$key][]=$val;
}
}
foreach ($array as $v){
//分别赋值,对应表里的5个字段位
$data[‘wxid‘] = $this->wxid;
$data[‘userid‘] = $this->userid;
$data[‘listsort‘] = $v[0];
$data[‘title‘] = $v[1];
$data[‘key‘] = $v[2];
$data[‘parentid‘] = $v[3];
$data[‘isshow‘] = $v[4];
if(!empty($data[‘title‘]) && !empty($data[‘key‘])){
$add = $wx_menu_db->data($data)->add();
}
}
$save = array();
//更新旧数据
foreach ($this->_post(‘ps‘) as $ps){
$temp[‘wxid‘] = $this->wxid;
$temp[‘userid‘] = $this->userid;
$temp[‘id‘] = $ps[‘id‘];
$temp[‘listsort‘] = $ps[‘listsort‘];
$temp[‘title‘] = $ps[‘title‘];
$temp[‘key‘] = $ps[‘key‘];
$temp[‘parentid‘] = $ps[‘parentid‘];
$temp[‘isshow‘] = $ps[‘isshow‘];
$save[] = $wx_menu_db->where(array(‘id‘=>$temp[‘id‘]))->data($temp)->save();
}
//判断是否有修改过
foreach($save as $s){
if($s){
$a=1;
}
}
if($add || $a){
$this->success(‘操作成功,正在返回...‘,U(‘CustomMenu/custommenu‘,array(‘wxid‘=>$this->wxid)));
}else{
$this->error(‘操作无影响!‘,U(‘CustomMenu/custommenu‘,array(‘wxid‘=>$this->wxid)));
}
}
这里主要对新增的,编辑过得一次性处理
5. 生成微信自定义菜单
说明:运用cURL生成微信自定义菜单
//从数据库中取出数据
$array = $this->selectDb();
$arr = array();
//重组数组
foreach($array as $val){
$arr[$val[‘id‘]][‘name‘] = $val[‘title‘];
$arr[$val[‘id‘]][‘key‘] = $val[‘key‘];
if($val[‘sub‘]){
foreach($val as $v){
if(is_array($v)){
foreach($v as $k){
$arr[$val[‘id‘]][‘sub‘][‘name‘]= $k[‘title‘];
$arr[$val[‘id‘]][‘sub‘][‘key‘] = $k[‘key‘];
}
}
}
}
}
//编写Json数据串
$js=‘{"button":[‘;
foreach($arr as $a){
if(!is_array($a[‘sub‘])){
$js.=‘{"type":"click",‘;
$js.=‘"name":"‘.$a[‘name‘].‘",‘;
$js.=‘"key":"‘.$a[‘key‘].‘"},‘;
}else{
$js1.=‘{"name":"‘.$a[‘name‘].‘",‘;
$js1.=‘"sub_button":[‘;
foreach($a as $vo){
foreach($vo as $o){
$js2.=‘{"type":"view",‘;
$js2.=‘"name":"‘.$vo[‘name‘].‘",‘;
$js2.=‘"url":"‘.$vo[‘key‘].‘"},‘;
}
}
$js1.=$js2;
}
}
$js.=$js1;
$js.=‘]}]}‘;
$array = $this->selectDb();
$arr = array();
//重组数组
foreach($array as $val){
$arr[$val[‘id‘]][‘name‘] = $val[‘title‘];
$arr[$val[‘id‘]][‘key‘] = $val[‘key‘];
if($val[‘sub‘]){
foreach($val as $v){
if(is_array($v)){
foreach($v as $k){
$arr[$val[‘id‘]][‘sub‘][‘name‘]= $k[‘title‘];
$arr[$val[‘id‘]][‘sub‘][‘key‘] = $k[‘key‘];
}
}
}
}
}
//编写Json数据串
$js=‘{"button":[‘;
foreach($arr as $a){
if(!is_array($a[‘sub‘])){
$js.=‘{"type":"click",‘;
$js.=‘"name":"‘.$a[‘name‘].‘",‘;
$js.=‘"key":"‘.$a[‘key‘].‘"},‘;
}else{
$js1.=‘{"name":"‘.$a[‘name‘].‘",‘;
$js1.=‘"sub_button":[‘;
foreach($a as $vo){
foreach($vo as $o){
$js2.=‘{"type":"view",‘;
$js2.=‘"name":"‘.$vo[‘name‘].‘",‘;
$js2.=‘"url":"‘.$vo[‘key‘].‘"},‘;
}
}
$js1.=$js2;
}
}
$js.=$js1;
$js.=‘]}]}‘;
$url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=".$access_token;
//发送到微信,接受返回的结果
$result = $this->httpsRequest($url,$js);
$r = json_decode($result,trues);
if($r[‘errcode‘]==0){
$this->success(‘添加成功!‘,U(‘CustomMenu/custommenu‘,array(‘wxid‘=>$this->wxid)));
}
else{
$this->error(‘添加失败‘);
}
//发送到微信,接受返回的结果
$result = $this->httpsRequest($url,$js);
$r = json_decode($result,trues);
if($r[‘errcode‘]==0){
$this->success(‘添加成功!‘,U(‘CustomMenu/custommenu‘,array(‘wxid‘=>$this->wxid)));
}
else{
$this->error(‘添加失败‘);
}
public function httpsRequest($url,$data = null){
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
至此微信自定义菜单功能已实现!