Przeglądaj źródła

添加搜索框

hfy 5 miesięcy temu
rodzic
commit
ce704fc079

+ 6 - 6
src/main/resources/config/application.yml

@@ -56,13 +56,13 @@ jdbc:
   # Mysql 数据库配置
   type: mysql
   driver: com.mysql.cj.jdbc.Driver
-  url: jdbc:mysql://127.0.0.1:3306/mes_cloud_dy?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
+ # url: jdbc:mysql://127.0.0.1:3306/mes_cloud_dy?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
   #  url: jdbc:mysql://127.0.0.1:3306/mes_cloud_x04c?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
-#  url: jdbc:mysql://192.168.9.181:3306/mes_cloud?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
-#  username: mes_cloud
-#  password: s2ENj7KaEySTC7dW
-  username: root
-  password: root
+  url: jdbc:mysql://192.168.9.181:3306/mes_cloud?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
+  username: mes_cloud
+  password: s2ENj7KaEySTC7dW
+#  username: root
+ # password: root
   testSql: SELECT 1
 
   #  # Oracle 数据库配置(若使用 12c,请修改 /modules/core/pom.xml 文件,打开 12c 依赖,去掉 11g 依赖)

+ 55 - 41
src/main/resources/views/include/sysIndex/topMenu.html

@@ -1,41 +1,55 @@
-<nav class="navbar navbar-static-top">
-	<div class="logo" data-toggle="push-menu">
-		<b>${@Global.getConfig('productNamePrefix')}${@Global.getConfig('productName')}</b>
-		<small title="${text('点击缩小侧边栏,右键隐藏侧边栏')}">&nbsp; &nbsp;<i class="fa fa-bars"></i></small>
-	</div>
-	<%/*<!--%><a href="javascript:" class="sidebar-toggle" data-toggle="push-menu" role="button">
-		<span class="sr-only">菜单切换</span><span class="icon-bar"></span>
-		<span class="icon-bar"></span><span class="icon-bar"></span>
-	</a><%-->*/%>
-	<div class="navbar-custom-menu">
-		<ul class="nav navbar-nav">
-			<% include('/include/sysIndex/topMenuCorp.html'){} %>
-			<li><a href="javascript:" id="fullScreen" title="${text('全屏')}" data-placement="bottom" data-container="body"><i class="fa fa-arrows-alt"></i></a></li>
-			<li><a href="javascript:" id="switchSkin" title="${text('切换主题')}" style="margin-top:-1px;" data-placement="bottom" data-container="body" data-layer-width="600" data-layer-height="350"><i class="fa fa-dashboard"></i></a></li>
-			<% include('/include/sysIndex/topMenuLang.html'){} %>
-			<% include('/include/sysIndex/topMenuOnline.html'){} %>
-			<% include('/include/sysIndex/topMenuMsg.html'){} %>
-			<% //include('/include/sysIndex/topMenuNotify.html'){} %>
-			<% //include('/include/sysIndex/topMenuTask.html'){} %>
-			<% include('/include/sysIndex/topMenuUser.html'){} %>
-		</ul>
-	</div>
-	<% if(@Global.getConfig('sys.index.menuStyle', '1') == '2'){ %>
-	<div class="navbar-custom-menu pull-left" id="topMenu">
-		<ul class="nav navbar-nav">
-			<li class="treeview dropdown" id="topMenuMore" style="position:relative;">
-				<a href="javascript:" class="dropdown-toggle" data-toggle="dropdown" data-hover="dropdown">
-					<i class="fa fa-fw icon-options"></i></span>
-				</a>
-				<ul class="treeview-menu dropdown-menu" style="left:0;">
-					<%
-					var p = {parentCode: '0', children: false};
-					menu.tree(p); print(p.html);
-					%>
-				</ul>
-			</li>
-		</ul>
-		<script src="${ctxStatic}/modules/sys/topMenu.js"></script>
-	</div>
-	<% } %>
-</nav>
+<nav class="navbar navbar-static-top"><!-- 顶部导航条开始 -->
+	<div class="logo" data-toggle="push-menu"><!-- 左侧系统名称区域,点击可折叠侧边栏 -->
+		<b>${@Global.getConfig('productNamePrefix')}${@Global.getConfig('productName')}</b><!-- 系统名称 -->
+		<small title="${text('点击缩小侧边栏,右键隐藏侧边栏')}">&nbsp; &nbsp;<i class="fa fa-bars"></i></small><!-- 折叠菜单图标 -->
+	</div><!-- 左侧系统名称区域结束 -->
+	<%/*<!--%><a href="javascript:" class="sidebar-toggle" data-toggle="push-menu" role="button"><!-- 原框架保留的菜单切换按钮,当前被注释 -->
+		<span class="sr-only">菜单切换</span><span class="icon-bar"></span><!-- 菜单切换的无障碍文字和图标线 -->
+		<span class="icon-bar"></span><span class="icon-bar"></span><!-- 菜单切换图标线 -->
+	</a><%-->*/%><!-- 原框架保留按钮注释结束 -->
+	<div class="navbar-menu-search" id="menuSearch"><!-- 顶部菜单搜索容器 -->
+		<div class="menu-search-control"><!-- 搜索框外壳 -->
+			<i class="fa fa-search"></i><!-- 左侧搜索图标 -->
+			<input type="text" id="menuSearchInput" autocomplete="off" placeholder="${text('菜单搜索')}"><!-- 输入关键字 -->
+			<button type="button" id="menuSearchClear" title="${text('清空')}"><i class="fa fa-times"></i></button><!-- 清空按钮 -->
+		</div><!-- 搜索框外壳结束 -->
+		<ul class="menu-search-result" id="menuSearchResult"></ul><!-- 搜索结果列表 -->
+	</div><!-- 顶部菜单搜索容器结束 -->
+	<div class="hide" id="menuSearchSource"><!-- 隐藏的菜单源,给脚本读取,不直接显示在页面上 -->
+		<ul><!-- 菜单树容器 -->
+			<% // 从根菜单开始把完整菜单树输出到隐藏区域,供前端搜索使用 %><!-- 菜单搜索说明 -->
+			<% var menuSearchParam = {parentCode: '0'}; %><!-- 搜索参数:根菜单 -->
+			<% menu.tree(menuSearchParam); print(menuSearchParam.html); %><!-- 输出完整菜单树 -->
+		</ul><!-- 菜单树容器结束 -->
+	</div><!-- 隐藏的菜单源结束 -->
+	<div class="navbar-custom-menu"><!-- 右侧用户、消息、全屏等工具栏 -->
+		<ul class="nav navbar-nav"><!-- 工具栏列表 -->
+			<% include('/include/sysIndex/topMenuCorp.html'){} %><!-- 企业或公司切换菜单 -->
+			<li><a href="javascript:" id="fullScreen" title="${text('全屏')}" data-placement="bottom" data-container="body"><i class="fa fa-arrows-alt"></i></a></li><!-- 全屏按钮 -->
+			<li><a href="javascript:" id="switchSkin" title="${text('切换主题')}" style="margin-top:-1px;" data-placement="bottom" data-container="body" data-layer-width="600" data-layer-height="350"><i class="fa fa-dashboard"></i></a></li><!-- 主题切换按钮 -->
+			<% include('/include/sysIndex/topMenuLang.html'){} %><!-- 多语言菜单 -->
+			<% include('/include/sysIndex/topMenuOnline.html'){} %><!-- 在线用户菜单 -->
+			<% include('/include/sysIndex/topMenuMsg.html'){} %><!-- 消息菜单 -->
+			<% //include('/include/sysIndex/topMenuNotify.html'){} %><!-- 通知菜单预留,当前不启用 -->
+			<% //include('/include/sysIndex/topMenuTask.html'){} %><!-- 任务菜单预留,当前不启用 -->
+			<% include('/include/sysIndex/topMenuUser.html'){} %><!-- 当前用户菜单 -->
+		</ul><!-- 工具栏列表结束 -->
+	</div><!-- 右侧工具栏结束 -->
+	<% if(@Global.getConfig('sys.index.menuStyle', '1') == '2'){ %><!-- 如果配置为顶部根菜单样式,就显示顶部菜单 -->
+	<div class="navbar-custom-menu pull-left" id="topMenu"><!-- 顶部根菜单容器 -->
+		<ul class="nav navbar-nav"><!-- 顶部根菜单列表 -->
+			<li class="treeview dropdown" id="topMenuMore" style="position:relative;"><!-- 更多菜单下拉入口 -->
+				<a href="javascript:" class="dropdown-toggle" data-toggle="dropdown" data-hover="dropdown"><!-- 点击展开更多菜单 -->
+					<i class="fa fa-fw icon-options"></i></span><!-- 更多菜单图标 -->
+				</a><!-- 更多菜单入口结束 -->
+				<ul class="treeview-menu dropdown-menu" style="left:0;"><!-- 更多菜单下拉列表 -->
+					<% // 只输出根菜单给顶部更多菜单使用 %><!-- 顶部菜单说明 -->
+					<% var p = {parentCode: '0', children: false}; %><!-- 顶部菜单参数 -->
+					<% menu.tree(p); print(p.html); %><!-- 输出顶部菜单 -->
+				</ul><!-- 更多菜单下拉列表结束 -->
+			</li><!-- 更多菜单下拉入口结束 -->
+		</ul><!-- 顶部根菜单列表结束 -->
+		<script src="${ctxStatic}/modules/sys/topMenu.js"></script><!-- 顶部菜单自带脚本 -->
+	</div><!-- 顶部根菜单容器结束 -->
+	<% } %><!-- 顶部菜单样式判断结束 -->
+</nav><!-- 顶部导航条结束 -->

+ 225 - 22
src/main/resources/views/themes/default/modules/sys/sysIndex.html

@@ -1,26 +1,229 @@
 <%
 // 侧边栏的默认显示样式:1:默认显示侧边栏;2:默认折叠侧边栏
-var sidebarStyle = @Global.getConfig('sys.index.sidebarStyle', '1');
-var sidebarCollapse = (sidebarStyle == '2' ? 'sidebar-collapse' : '');
-var bodyClass = 'fixed noscroll2 sidebar-mini ' + sidebarCollapse;
+var sidebarStyle = @Global.getConfig('sys.index.sidebarStyle', '1'); // 读取侧边栏默认样式配置
+var sidebarCollapse = (sidebarStyle == '2' ? 'sidebar-collapse' : ''); // 根据配置决定是否默认折叠
+var bodyClass = 'fixed noscroll2 sidebar-mini ' + sidebarCollapse; // 拼接页面 body 使用的 class
 %>
-<% layout('/layouts/default.html', {title: '', bodyClass: bodyClass, libs: ['tabPage']}){ %>
-<!--[if lte IE 8]><script>window.location.href='${ctxStatic}/upbw/index.html';</script><![endif]-->
-<link rel="stylesheet" href="${ctxStatic}/jquery-toastr/2.1/toastr.min.css?${_version}">
-<link rel="stylesheet" href="${ctxStatic}/modules/sys/sysIndex.css?${_version}">
-<header class="main-header">
-	<% include('/include/sysIndex/topMenu.html'){} %>
-</header>
-<aside class="main-sidebar">
-	<% include('/include/sysIndex/leftMenu.html'){} %>
-</aside>
-<div class="content-wrapper">
-	<div id="tabpanel"></div>
-</div>
-<% } %>
+<% layout('/layouts/default.html', {title: '', bodyClass: bodyClass, libs: ['tabPage']}){ %><!-- 使用默认布局,并启用 tabPage 页签库 -->
+<!--[if lte IE 8]><script>window.location.href='${ctxStatic}/upbw/index.html';</script><![endif]--><!-- 低版本 IE 跳转提示页 -->
+<link rel="stylesheet" href="${ctxStatic}/jquery-toastr/2.1/toastr.min.css?${_version}"><!-- 消息提示样式 -->
+<link rel="stylesheet" href="${ctxStatic}/modules/sys/sysIndex.css?${_version}"><!-- 主框架原有样式 -->
+<style>/* 顶部搜索框样式开始 */
+.navbar-menu-search{position:absolute;top:8px;right:430px;width:280px;z-index:1050}/* 搜索框固定在顶部右侧 */
+.menu-search-control{height:34px;border-radius:3px;background:rgba(255,255,255,.18);border:1px solid rgba(255,255,255,.28);display:flex;align-items:center;color:#fff}/* 搜索输入框外壳 */
+.menu-search-control .fa-search{width:34px;text-align:center;font-size:14px;opacity:.9}/* 左侧放大镜 */
+.menu-search-control input{flex:1;min-width:0;height:32px;border:0;background:transparent;color:#fff;outline:0;font-size:13px}/* 输入框本体 */
+.menu-search-control input::placeholder{color:rgba(255,255,255,.78)}/* 提示文字颜色 */
+.menu-search-control button{display:none;width:30px;height:32px;border:0;background:transparent;color:rgba(255,255,255,.85);outline:0}/* 清空按钮默认隐藏 */
+.menu-search-control.has-value button{display:block}/* 有内容时显示清空按钮 */
+.menu-search-control:focus-within{background:#fff;color:#3c8dbc;border-color:#fff;box-shadow:0 2px 10px rgba(0,0,0,.18)}/* 聚焦时高亮 */
+.menu-search-control:focus-within input{color:#333}/* 聚焦后输入文字变深色 */
+.menu-search-control:focus-within input::placeholder{color:#999}/* 聚焦后提示文字变灰 */
+.menu-search-control:focus-within button{color:#777}/* 聚焦后清空按钮变灰 */
+.menu-search-result{display:none;position:absolute;top:38px;left:0;right:0;max-height:360px;overflow:auto;margin:0;padding:6px 0;list-style:none;background:#fff;border:1px solid #d2d6de;border-radius:3px;box-shadow:0 4px 14px rgba(0,0,0,.18)}/* 下拉结果面板 */
+.menu-search-result li{padding:8px 12px;line-height:18px;cursor:pointer;color:#333}/* 单条结果样式 */
+.menu-search-result li:hover,.menu-search-result li.active{background:#f3f7fb;color:#1f6fb2}/* 鼠标悬停和键盘选中 */
+.menu-search-result .menu-title{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}/* 菜单标题,只显示最后一级 */
+.menu-search-result .empty{cursor:default;color:#999}/* 没结果时的提示 */
+@media (max-width:1200px){.navbar-menu-search{right:330px;width:240px}}/* 中等屏幕收窄 */
+@media (max-width:992px){.navbar-menu-search{display:none}}/* 小屏隐藏 */
+</style><!-- 顶部搜索框样式结束 -->
+<header class="main-header"><!-- 顶部栏容器 -->
+	<% include('/include/sysIndex/topMenu.html'){} %><!-- 引入顶部菜单模板 -->
+</header><!-- 顶部栏容器结束 -->
+<aside class="main-sidebar"><!-- 左侧菜单容器 -->
+	<% include('/include/sysIndex/leftMenu.html'){} %><!-- 引入左侧菜单模板 -->
+</aside><!-- 左侧菜单容器结束 -->
+<div class="content-wrapper"><!-- 主内容区域 -->
+	<div id="tabpanel"></div><!-- 页签容器,菜单打开后会显示在这里 -->
+</div><!-- 主内容区域结束 -->
+<% } %><!-- 默认布局结束 -->
+<!-- 隐藏的首页页签配置 -->
 <div class="hide" id="desktopTabPage" data-title="${text('仪表盘')}"
-	data-url="${ctx}${@Global.getConfig('sys.index.desktopUrl')}"></div>
-<div class="hide" id="modifyPasswordTip" data-message="${modifyPasswordTip!}"></div>
-<script src="${ctxStatic}/jquery-toastr/2.1/toastr.min.js?${_version}"></script>
-<script src="${ctxStatic}/jquery-plugins/jquery.slimscroll.js"></script>
-<script src="${ctxStatic}/modules/sys/sysIndex.js?${_version}"></script>
+	data-url="${ctx}${@Global.getConfig('sys.index.desktopUrl')}"></div><!-- 首页页签地址 -->
+<div class="hide" id="modifyPasswordTip" data-message="${modifyPasswordTip!}"></div><!-- 修改密码提醒配置 -->
+<script src="${ctxStatic}/jquery-toastr/2.1/toastr.min.js?${_version}"></script><!-- 消息提示脚本 -->
+<script src="${ctxStatic}/jquery-plugins/jquery.slimscroll.js"></script><!-- 滚动条插件 -->
+<script src="${ctxStatic}/modules/sys/sysIndex.js?${_version}"></script><!-- 主框架原有脚本 -->
+<script>// 菜单搜索脚本开始
+(function($){// 让脚本只依赖 jQuery
+	$(function(){// 页面加载完成后再执行
+		var $box = $('#menuSearch');// 搜索框外层
+		var $input = $('#menuSearchInput');// 输入框
+		var $clear = $('#menuSearchClear');// 清空按钮
+		var $result = $('#menuSearchResult');// 下拉结果列表
+		var menuItems = [];// 叶子菜单数据,只保存最后一级菜单
+		var activeIndex = -1;// 当前高亮的结果下标
+		var maxResultSize = 12;// 最多显示多少条
+		if (!$box.length || !$input.length || !$result.length){// 找不到页面元素就退出
+			return;// 防止报错
+		}// 初始化检查结束
+		function cleanText(text){// 清洗文本
+			return $.trim(String(text || '').replace(/\s+/g, ' '));// 去掉多余空格
+		}// 清洗文本结束
+		function normalize(text){// 转成统一格式,方便模糊匹配
+			return cleanText(text).toLowerCase();// 统一成小写
+		}// 统一格式结束
+		function html(text){// 把内容转成安全的 HTML
+			return $('<div/>').text(text || '').html();// 防止标签注入
+		}// 安全转义结束
+		function getLinkTitle($link){// 取菜单名称
+			return cleanText($link.attr('data-title') || $link.children('span').first().text() || $link.text());// 优先取标题属性
+		}// 取菜单名称结束
+		function getLinkHref($link){// 取菜单地址
+			var href = $link.attr('data-href') || $link.attr('href') || '';// 先找 data-href
+			return cleanText(href);// 再做清洗
+		}// 取菜单地址结束
+		function isLeafMenu($link){// 判断是不是最后一级菜单
+			var $li = $link.closest('li');// 找到当前菜单的 li
+			if (!$li.length){// 没有 li 就不是菜单
+				return false;// 直接排除
+			}// li 判断结束
+			if ($li.find('ul.treeview-menu, ul.menu-open, ul').length){// 还有子菜单就不是叶子
+				return false;// 直接排除
+			}// 子菜单判断结束
+			return true;// 剩下的就是叶子菜单
+		}// 判断叶子菜单结束
+		function canOpenHref(href){// 判断地址是否可直接打开
+			return href && href !== '#' && href !== 'javascript:' && href.indexOf('javascript:void') !== 0;// 排除空地址和占位地址
+		}// 判断地址结束
+		function collectMenus(){// 收集可搜索的叶子菜单
+			var exists = {};// 用来去重
+			$('#menuSearchSource a, #leftMenu a, #topMenu a').each(function(){// 遍历页面里的菜单链接
+				var $link = $(this);// 当前链接对象
+				var title = getLinkTitle($link);// 当前链接标题
+				var href = getLinkHref($link);// 当前链接地址
+				if (!title || !canOpenHref(href) || !isLeafMenu($link)){// 只保留最后一级且可打开的菜单,避免父级菜单 404
+					return;// 不符合就跳过
+				}// 过滤条件结束
+				var key = title + '|' + href;// 组合去重键
+				if (exists[key]){// 如果已经收集过
+					return;// 直接跳过
+				}// 去重判断结束
+				exists[key] = true;// 标记已收集
+				menuItems.push({// 记录到搜索列表
+					title: title,// 只显示最后一级菜单名
+					href: href,// 点击后跳转的地址
+					text: normalize(title + ' ' + href)// 搜索时使用的文本
+				});// 一条菜单记录结束
+			});// 遍历结束
+		}// 收集菜单结束
+		function fuzzyMatch(text, keyword){// 模糊匹配
+			if (!keyword){// 关键词为空时不匹配
+				return false;// 直接返回
+			}// 空关键词判断结束
+			if (text.indexOf(keyword) > -1){// 先做普通包含匹配
+				return true;// 包含就算命中
+			}// 包含匹配结束
+			var index = 0;// 记录关键词匹配到哪一位
+			for (var i = 0; i < text.length && index < keyword.length; i++){// 按字符顺序尝试匹配
+				if (text.charAt(i) === keyword.charAt(index)){// 当前字符相等就往后走
+					index++;// 命中下一位
+				}// 单字符判断结束
+			}// 循环结束
+			return index === keyword.length;// 所有关键字都按顺序命中才算成功
+		}// 模糊匹配结束
+		function search(keyword){// 执行搜索
+			keyword = normalize(keyword);// 搜索词先统一格式
+			if (!keyword){// 没有搜索词时
+				return [];// 返回空数组
+			}// 空搜索词判断结束
+			var list = [];// 搜索结果数组
+			$.each(menuItems, function(_, item){// 遍历所有叶子菜单
+				if (fuzzyMatch(item.text, keyword)){// 命中就加入结果
+					list.push(item);// 保存结果
+				}// 命中判断结束
+			});// 遍历结束
+			list.sort(function(a, b){// 结果简单排序
+				var aTitle = normalize(a.title);// 取当前标题
+				var bTitle = normalize(b.title);// 取对比标题
+				var aScore = aTitle.indexOf(keyword) === 0 ? 0 : (aTitle.indexOf(keyword) > -1 ? 1 : 2);// 更靠前的关键词排前面
+				var bScore = bTitle.indexOf(keyword) === 0 ? 0 : (bTitle.indexOf(keyword) > -1 ? 1 : 2);// 同样计算另一个结果
+				return aScore - bScore || a.title.length - b.title.length;// 先比命中位置,再比长度
+			});// 排序结束
+			return list.slice(0, maxResultSize);// 最多显示固定条数
+		}// 搜索结束
+		function setActive(index){// 设置当前高亮项
+			var $items = $result.children('li[data-index]');// 取所有结果项
+			activeIndex = index;// 保存当前下标
+			$items.removeClass('active');// 先清掉旧高亮
+			if (activeIndex >= 0 && activeIndex < $items.length){// 下标合法时
+				$items.eq(activeIndex).addClass('active');// 给当前项加高亮
+			}// 高亮判断结束
+		}// 设置高亮结束
+		function render(list){// 渲染结果列表
+			$result.empty();// 先清空旧结果
+			activeIndex = -1;// 重置高亮
+			if (!list.length){// 没有结果时
+				$result.append('<li class="empty">未找到匹配菜单</li>').show();// 显示空提示
+				return;// 结束渲染
+			}// 空结果判断结束
+			$.each(list, function(index, item){// 遍历结果
+				$result.append(// 追加每一条结果
+					'<li data-index="' + index + '">' +// 结果项
+					'<div class="menu-title">' + html(item.title) + '</div>' +// 只显示最后一级菜单名
+					'</li>'// 结束结果项
+				);// 追加完成
+			});// 遍历结束
+			$result.data('items', list).show();// 保存结果并显示
+			setActive(0);// 默认高亮第一条
+		}// 渲染结束
+		function hideResult(){// 隐藏结果
+			$result.hide().empty().removeData('items');// 收起面板并清空缓存
+			activeIndex = -1;// 重置高亮
+		}// 隐藏结束
+		function openMenu(item){// 打开菜单
+			if (!item){// 没有选中项时
+				return;// 不处理
+			}// 空值判断结束
+			$input.val('');// 清空输入框
+			$input.closest('.menu-search-control').removeClass('has-value');// 移除按钮显示状态
+			hideResult();// 关闭结果面板
+			if (window.js && $.isFunction(window.js.addTabPage)){// 如果框架支持打开页签
+				window.js.addTabPage(null, item.title, item.href);// 用页签打开
+			}else{// 如果没有页签能力
+				window.location.href = item.href;// 直接跳转
+			}// 打开方式判断结束
+		}// 打开菜单结束
+		collectMenus();// 初始化时收集菜单
+		$input.on('input', function(){// 输入时实时搜索
+			var value = this.value;// 当前输入值
+			$input.closest('.menu-search-control').toggleClass('has-value', !!value);// 控制清空按钮显示
+			if (!value){// 为空就收起结果
+				hideResult();// 隐藏结果
+				return;// 结束
+			}// 为空判断结束
+			render(search(value));// 执行搜索并渲染
+		}).on('keydown', function(e){// 键盘控制上下选择和回车打开
+			var items = $result.data('items') || [];// 取当前结果列表
+			if (e.keyCode === 38 || e.keyCode === 40){// 上下方向键
+				if (!items.length){// 没有结果就不处理
+					return;// 直接返回
+				}// 结果为空判断结束
+				e.preventDefault();// 阻止光标移动
+				setActive(e.keyCode === 38/* 按上方向键 */
+					? (activeIndex <= 0 ? items.length - 1 : activeIndex - 1)/* 上一条 */
+					: (activeIndex >= items.length - 1 ? 0 : activeIndex + 1));/* 下一条 */
+			}else if (e.keyCode === 13){// 回车键
+				e.preventDefault();// 阻止表单提交
+				openMenu(items[activeIndex] || items[0]);// 打开当前项或第一项
+			}else if (e.keyCode === 27){// Esc 键
+				hideResult();// 直接关闭
+			}// 键盘分支结束
+		});// 键盘绑定结束
+		$clear.on('click', function(){// 点击清空按钮
+			$input.val('').trigger('input').focus();// 清空并重新聚焦
+		});// 清空按钮结束
+		$result.on('mousedown', 'li[data-index]', function(e){// 点击某一条结果
+			e.preventDefault();// 防止输入框失焦过早
+			var items = $result.data('items') || [];// 取结果数组
+			openMenu(items[$(this).data('index')]);// 打开对应菜单
+		});// 结果点击结束
+		$(document).on('mousedown', function(e){// 点击页面其他地方时
+			if (!$(e.target).closest('#menuSearch').length){// 如果点的不是搜索框内部
+				hideResult();// 就关闭结果
+			}// 点击区域判断结束
+		});// 文档点击结束
+	});// 页面加载结束
+})(jQuery);// 立即执行结束
+</script><!-- 菜单搜索脚本结束 -->