从数据库动态加载菜单栏
最近组内有个技术学习项目—用Python写一个Web站点,我领取的任务是将站点菜单可配置,从数据库中读取数据,然后动态构建。
基本的思路是这样:把需要显示的菜单数据存储在数据库,页面加载的时候,JS从后台读取数据,在前端构建Dome并正确显示。
第一步:设计数据库
1.1.数据库字段设计
ID:菜单节点记录唯一识别字段,设为主键
Name:菜单节点的名称
ShowName:菜单节点在前端显示的名称
IshasSon:是否有子节点,为了处理菜单层级不确定的问题
ParentId:父节点的ID
NodeUrl:菜单节点对应的跳转URL
IsNewBlank:是否在新窗口打开,内/外站点打开的方式不同
CreatTime:菜单记录的创建时间
menu数据库设计图:
1.2 数据库读取:
创建py文件dbMenu,导入数据库连接方法(具体方法可参见我的另一篇博客
Python连接MySql数据库),获取数据库连接句柄后查询数据库,获取所有的数据库记录。代码如下:
from config import Config
from app.db.dbBase import DBConnect
import pymysql.cursors
class DBMenu:
@staticmethod
def get_nodes():
conn = DBConnect().db_connect(Config().DATABASE_MAIN)
cursor = conn.cursor(pymysql.cursors.DictCursor)
cursor.execute("select * from menu")
menus = cursor.fetchall()
cursor.close()
conn.close()
return menus
@staticmethod
def get_sonnodes(node_id):
conn = DBConnect().db_connect(Config().DATABASE_MAIN)
cursor = conn.cursor(pymysql.cursors.DictCursor)
cursor.execute("select * from menu where `parent_id` = %s", node_id)
sonmenus = cursor.fetchall()
cursor.close()
conn.close()
return sonmenus
get_nodes()是一个获取所有菜单节点的方法,用来构建根菜单;get_sonnodes()是一个根据当前节点ID获取其子节点菜单的方法,用来构建子菜单
第二步:读取数据库菜单记录,动态构建菜单
2.1 Controler 层实现获取数据方法:
创建py文件cMenu,实现获取数据方法,封装数据源,代码如下:
from app.db.dbMenu import DBMenu
class CMenu:
@staticmethod
def get_menu():
menus = DBMenu.get_nodes()
return menus
@staticmethod
def get_sonmenu(node_id):
sonmenu = DBMenu.get_sonnodes(node_id)
return sonmenu
2.2 View层把数据传递给Html模版文件:
创建py文件menu,把封装好的数据传递给模版文件,代码如下:
# This Python file uses the following encoding: utf-8
from flask import request
from app.controler.cMenu import CMenu
from flask import Blueprint
from flask import jsonify
commonBp = Blueprint('common', __name__, url_prefix='/common')
@commonBp.route('/getSonMenu', methods=['GET'])
def get_sonmenu():
parentid = request.args.get('parentId')
node = CMenu.get_sonmenu(int(parentid))
return jsonify(node)
@commonBp.route('/getmenu')
def base():
menus_node = CMenu.get_menu()
size = len(menus_node)
return jsonify(menus_node=menus_node, size=size)
2.3 Html模版文件前端构建页面内容:
创建base.html文件,构建前端Html,代码如下:
<nav id="Hui-nav" class="nav navbar-nav">
<ul class="cl" id="ulmenu">
</ul>
</nav>
2.4 JS动态加载菜单:
创建my.js,JS脚本动态加载菜单,代码如下:
$(document).ready(function () {
function getRootmenu() {
$.ajax({
type: "get",
dataType: "json",
url: "/common/getmenu",
success: function (data) {
var m = "";
if (data.size > 0) {
for (j = 0; j < data.size; j++) {
if (data.menus_node[j].parent_id == -1) {
if (data.menus_node[j].ishas_son == 1) {
m = m + "<li roletype='2' id='" + data.menus_node[j].node_id + "' class='dropDown dropDown_hover'>" +
"<a class='dropDown_A' href='" + data.menus_node[j].node_url + "'>" + data.menus_node[j].node_showname + "<i class='Hui-iconfont' >" + '' + "</i></a></li>";
}
else {
m = m + "<li roletype='2' id='" + data.menus_node[j].node_id + "' class='dropDown dropDown_hover'>" +
"<a class='dropDown_A' href='" + data.menus_node[j].node_url + "'>" + data.menus_node[j].node_showname + "</a></li>";
}
}
}
}
$('#ulmenu').html(m);
$("#ulmenu li").bind('mouseover', function (e) {
getSonMenu(this, e)
});
}
});
}
getRootmenu();
function getSonMenu(event) {
var parentId = $(event).attr("id");
var roletype = $(event).attr("roletype");
if (roletype == "2")
$(event).addClass("hover open");
if (roletype == "1")
$(event).addClass("open");
if ($(event).find("li").length > 0 || roletype == "0") return;
$.ajax({
type: "get",
dataType: "json",
url: "/common/getSonMenu?parentId=" + parentId,
success: function (result) {
var parentId = $(event).attr("id");
$('#' + parentId).html($('#' + parentId + ' >a'))
// $('#'+parentId).html("");
var a = "<ul class='dropDown-menu menu radius box-shadow'>";
var b = "</ul>";
var c = "";
$.each(result, function (i) {
if(result[i].isnewblank == 1 && result[i].ishas_son == 1)
{
c = c + "<li roletype='" + result[i].ishas_son + "' id=" + result[i].node_id + "><a href='" + result[i].node_url + "' target='_blank'>" + result[i].node_showname + "<i class='arrow Hui-iconfont'></i></a></li>";
}
if(result[i].isnewblank == 1 && result[i].ishas_son == 0){
c = c + "<li roletype='" + result[i].ishas_son + "' id=" + result[i].node_id + "><a href='" + result[i].node_url + "' target='_blank'>" + result[i].node_showname + "</a></li>";
}
if(result[i].isnewblank == 0 && result[i].ishas_son == 1){
c = c + "<li roletype='" + result[i].ishas_son + "' id=" + result[i].node_id + "><a href='" + result[i].node_url + "'>" + result[i].node_showname + "<i class='arrow Hui-iconfont'></i></a></li>";
}
if(result[i].isnewblank == 0 && result[i].ishas_son == 0){
c = c + "<li roletype='" + result[i].ishas_son + "' id=" + result[i].node_id + "><a href='" + result[i].node_url + "'>" + result[i].node_showname + "</a></li>";
}
});
$('#' + parentId).append(a + c + b);
$("#ulmenu li").unbind('mouseover');
$("#ulmenu li").bind('mouseover', function (e) {
getSonMenu(this, e)
});
}, error: function (result) {
alert(result.responseText);
}
});
}
});
记得要在Html文件中引用一下Js
<script type="text/javascript" src="/static/js/my.js"></script>
第三步:运行项目,打开浏览器看下效果:
Done!