Bootstrap每天必学之级联下拉菜单


Posted in Javascript onMarch 27, 2016

本文将介绍自定义的bootstrap级联下拉菜单,主要应用场合有省市级关联菜单等等,那么就先拿这个例子来讲,当然其他场景的关联菜单也同样适用。说实话,封装好一个通用的组件还是需要花费很多精力的和时间的,所谓通用,自然要考虑周全,叹!这次整理的Bootstrap关联select,里面也涉及到了很多jquery、ajax、springMVC等等知识点,可谓包罗万象!

首先,请允许我代表该自定义组件做一番小小的介绍。

“hi,你好,我叫yunm.combox.js,主人给我起的名字,其实呢,挺俗的。我主要通过为select组件增加两个自定义属性来完成相应的数据加载,数据请求使用了ajax,后端数据处理使用了springMVC(当然其他方式也可以,只需要返回对应的json数据即可),使用起来呢,就非常非常简单了!”

一、界面效果

Bootstrap每天必学之级联下拉菜单

当然了,从界面上完全看不出来一个组件封装的好坏,但至少,你感觉很简洁漂亮,那么好了,有了这层印象,你是否有兴趣继续看下去?我想答案是肯定的。

二、使用方法

①、procity.jsp

首先呢,在页面上加载yunm.combox.js(稍候介绍,至于其他的bootstrap的css和js,不在本章介绍范围内,略过),同时呢,创建两个select,具体格式见如下:

<script type="text/javascript" src="${ctx}/components/yunm/yunm.combox.js"></script>
<div class="form-group">
 <div class="row">
 <div class="col-md-6">
 <select name="province_code" class="form-control combox" ref="city_select"
 refUrl="${ctx}/procity?pro_code={value}&city_code=HSLY">
 </select>
 </div>
 <div class="col-md-6">
 <select name="city_code" id="city_select" class="form-control">
 </select>
 </div>
 </div>
</div>
<script type="text/javascript">
<!--
 $(function() {
 if ($.fn.combox) {
 $("select.combox", $p).combox();
 }
 });
//-->
</script>

·两个select组件,一个为province_code、一个为city_code。
·省级菜单上增加了两个属性。
      ref指定关联菜单为市级菜单city_select
      refUrl指定菜单获取数据的URL 
                pro_code作为获取市级数据的关键因子
                {value}呢,则为通配符,稍候在介绍组件的时候继续讲到
               city_code=HSLY,主要用于选中指定的省市菜单,诸如上文中的(河南、洛阳),如果不选中,则city_code=为空
·class=”combox” 为该省级下拉框增加jquery选择器
·页面加载完毕后执行combox组件的关键方法,下面详细介绍

②、yunm.combox.js

现在我们来看看关键的组件内容吧!

(function($) {
 var _onchange = function(event) {
 var $ref = $("#" + event.data.ref);
 if ($ref.size() == 0)
 return false;

 var refUrl = event.data.refUrl;
 var value = encodeURIComponent(event.data.$this.val());
 YUNM.debug(value);

 $.ajax({
 type : 'POST',
 dataType : "json",
 url : refUrl.replace("{value}", value),
 cache : false,
 data : {},
 success : function(response) {
 $ref.empty();

 addHtml(response, $ref);
 $ref.trigger("change").combox();
 },
 error : YUNM.ajaxError
 });

 };

 var addHtml = function(response, $this) {
 var json = YUNM.jsonEval(response);
 if (!json)
 return;

 var html = '';
 $.each(json, function(i) {
 if (json[i]) {

 html += '<option value="' + json[i].value + '"';

 if (json[i].selected) {
  html += ' selected="' + json[i].selected;
 }

 html += '">' + json[i].name + '</option>';
 }
 });

 $this.html(html);
 };

 $.extend($.fn, {
 combox : function() {

 return this.each(function(i) {
 var $this = $(this);

 var value = $this.val() || '';
 var ref = $this.attr("ref");

 var refUrl = $this.attr("refUrl") || "";
 if (refUrl) {
  refUrl = refUrl.replace("{value}", encodeURIComponent(value));
 }

 if (refUrl) {
  $.ajax({
  type : 'POST',
  dataType : "json",
  url : refUrl,
  cache : false,
  data : {},
  success : function(response) {
  addHtml(response, $this);

  if (ref && $this.attr("refUrl")) {
  $this.unbind("change", _onchange).bind("change", {
   ref : ref,
   refUrl : $this.attr("refUrl"),
   $this : $this,
  }, _onchange).trigger("change");
  }
  },
  error : YUNM.ajaxError
  });
 }

 });
 }
 });
})(jQuery);

·通过$.extend($.fn, { combox : function() {为jquery增加一个叫combox的底层(可以查询jquery帮助文档)方法。
·通过(function($){_onchange、addHtml})(jQuery);为该组件在页面初始加载时创建两个方法onchange和addHtml,至于(function($) {})(jQuery);我想你如果不了解的话,赶紧百度吧!
·先来看combox 方法 
            获取ref、refUrl,通过ajax向refUrl请求省级菜单数据,当获取成功后,通过addHtml方法将json转换后的option绑定到省级菜单select上
            然后呢,为省级菜单select绑定change事件,传递的参数为ref(市级菜单)、refUrl(市级数据获取的url)、$this(省级菜单,便于change事件获取对应选中项,如效果图中的河南)
            通过trigger方法立即执行change事件,便于获取对应的市级菜单内容。
·再来看_onchange方法,主要是点击省级菜单时触发,用于获取市级菜单列表
            refUrl,向服务端请求的URL
            value,用于获取省级菜单的选中项目,然后通过该value值获取省级对应的市级菜单
            $ref.empty();用于清空市级菜单
            通过ajax继续获取市级菜单内容,然后通过addHtml方法添加到市级菜单中。
·addHtml方法
           通过jsonEval方法对服务端传递回来的数据进行eval(eval('(' + data + ')'),如有不懂,可百度)方法处理,否则会出错。
           $.each(json, function(i) {遍历json,通过jquery创建option对象,然后加入到select中。

③、ProcityController

前端介绍完了,我们回到后端进行介绍,当然了,你也可以忽略本节,因为不是所用的关联数据都通过springMVC这种方法获取,那么先预览一下代码吧!

package com.honzh.spring.controller;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.honzh.biz.database.entity.City;
import com.honzh.biz.database.entity.Option;
import com.honzh.biz.database.entity.Provincial;
import com.honzh.common.util.JsonUtil;
import com.honzh.spring.service.CityService;
import com.honzh.spring.service.ProvincialService;

@Controller
@RequestMapping(value = "/procity")
public class ProcityController extends BaseController {
 private static Logger logger = Logger.getLogger(ProcityController.class);

 /**
 * 当传递city_code,则表明下拉框要被选中,否则不选中
 */
 @RequestMapping("")
 public void index(@RequestParam(value = "city_code", required = false) String city_code,
 @RequestParam(value = "pro_code", required = false) String pro_code, HttpServletResponse response) {
 try {
 logger.debug("获取所在地区" + city_code + ", 省" + pro_code);

 // 如果pro_code为””,则表明要获取城市菜单,否则获取市级菜单
 if (!pro_code.equals("")) {
 Integer pro_id = ProvincialService.getInstance().getByProvincialcode(pro_code).getId();
 List<City> citys = CityService.getInstance().getCitysByProvincialId(pro_id);
 List<Option> coptions = new ArrayList<Option>(citys.size());

 for (City city : citys) {
  Option coption = new Option();
  coption.setId(city.getId());
  coption.setName(city.getCname());
  coption.setValue(city.getCode());

  // 市级菜单被选中
  if (city_code != null && !city_code.equals("")) {
  if (city.getCode().equals(city_code)) {
  coption.setSelected("selected");
  }
  }
  coptions.add(coption);
 }
 renderJson(response, coptions);
 } else {
 List<Provincial> provincials = ProvincialService.getInstance().getProvincials();

 // 转换成标准的option属性(name,value,selected)
 List<Option> options = new ArrayList<Option>(provincials.size());

 // 被选中的省市
 // 则说明是展示页面,此时需要为省级菜单和市级菜单设置选择项
 if (city_code != null && !city_code.equals("")) {
  Provincial selected_provincial = ProvincialService.getInstance().getProvincialByCitycode(city_code);

  pro_code = selected_provincial.getProcode();
 } else {
  pro_code = provincials.get(0) == null ? "" : provincials.get(0).getProcode();
 }

 for (Provincial provincial : provincials) {
  Option option = new Option();
  option.setId(provincial.getId());
  option.setName(provincial.getProname());
  option.setValue(provincial.getProcode());

  if (!pro_code.equals("") && provincial.getProcode().equals(pro_code)) {
  option.setSelected("selected");
  }

  options.add(option);
 }

 renderJson(response, JsonUtil.toJson(options));
 }

 } catch (Exception e) {
 logger.error(e.getMessage());
 logger.error(e.getMessage(), e);

 renderJson(response, null);
 }
 }

}

@RequestParam(value = "city_code", required = false) String city_code,对于RequestParam注解,其实非常好用,这里就不多做解释,只是推广一下,固定个数的参数,用该注解更易于代码的维护。
ProvincialService类、CityService类就是两个单例,尽量把数据放置在内存当中,减少查询数据库的次数,稍候贴出来一个例子。
Option类就是单纯的封装前端option组件的关键属性,便于组件的通用化。
renderJson(response, JsonUtil.toJson(options));将数据json化后返回,稍候贴上详细代码。

④、ProvincialService.java

只贴出来代码例子,不做详细解释,毕竟不是本章重点。

package com.honzh.spring.service;

import java.util.ArrayList;
import java.util.List;

import com.honzh.biz.database.entity.City;
import com.honzh.biz.database.entity.Provincial;
import com.honzh.biz.database.mapper.ProvincialMapper;
import com.honzh.common.spring.SpringContextHolder;

public class ProvincialService {

 private static Object lock = new Object();
 private static ProvincialService config = null;

 private ProvincialService() {
 provincials = new ArrayList<Provincial>();

 ProvincialMapper mapper = SpringContextHolder.getBean(ProvincialMapper.class);
 provincials.addAll(mapper.getProvincials());
 }

 public static ProvincialService getInstance() {
 synchronized (lock) {
 if (null == config) {
 config = new ProvincialService();
 }
 }
 return (config);
 }

 public Provincial getByProvincialcode(String provincial_code) {
 for (Provincial provincial : provincials) {
 if (provincial.getProcode().equals(provincial_code)) {
 return provincial;
 }
 }
 return null;
 }

 private List<Provincial> provincials = null;

 public List<Provincial> getProvincials() {
 return provincials;
 }

 public Provincial getProvincialByCitycode(String city_code) {
 City city = CityService.getInstance().getCityByCode(city_code);

 for (Provincial provincial : provincials) {
 if (provincial.getId().intValue() == city.getProid().intValue()) {
 return provincial;
 }
 }
 return null;
 }

 public Provincial getProvincialByCode(String province_code) {
 for (Provincial provincial : provincials) {
 if (provincial.getProcode().equals(province_code)) {
 return provincial;
 }
 }
 return null;
 }

}

⑤、renderJson方法

/**
 * 如果出错的话,response直接返回404
 */
 protected void renderJson(HttpServletResponse response, Object responseObject) {
 PrintWriter out = null;
 try {
 if (responseObject == null) {
 response.sendError(404);
 return;
 }
 // 将实体对象转换为JSON Object转换
 String responseStr = JsonUtil.toJson(responseObject);
 response.setCharacterEncoding("UTF-8");
 response.setContentType("application/json; charset=utf-8");

 out = response.getWriter();
 out.append(responseStr);

 logger.debug("返回是:" + responseStr);
 } catch (IOException e) {
 logger.error(e.getMessage());
 logger.error(e.getMessage(), e);
 } finally {
 if (out != null) {
 out.close();
 }
 }
 }

如果大家还想深入学习,可以点击jQuery级联菜单特效汇总、Javascript级联菜单特效汇总进行学习。

如果大家还想深入学习Bootstrap,可以点击这里进行学习,再为大家附两个精彩的专题:Bootstrap学习教程 Bootstrap实战教程

本文系列教程整理到:Bootstrap基础教程 专题中,欢迎点击学习。

以上就是本文的全部内容,希望对大家的学习有所帮助。

Javascript 相关文章推荐
javascript解析json实例详解
Nov 05 Javascript
JS简单实现多级Select联动菜单效果代码
Sep 06 Javascript
JavaScript之Vue.js【入门基础】
Dec 06 Javascript
利用Jquery实现几款漂亮实用的时间轴(附示例代码)
Feb 15 Javascript
React Native 搭建开发环境的方法步骤
Oct 30 Javascript
react-redux中connect的装饰器用法@connect详解
Jan 13 Javascript
在Vue中使用Compass的方法
Mar 02 Javascript
TypeScript基础入门教程之三重斜线指令详解
Oct 22 Javascript
小程序关于请求同步的总结
May 05 Javascript
微信小程序登陆注册功能的实现代码
Dec 10 Javascript
vue 组件基础知识总结
Jan 26 Vue.js
微信小程序实现点赞业务
Feb 10 Javascript
详解javascript跨浏览器事件处理程序
Mar 27 #Javascript
js事件处理程序跨浏览器解决方案
Mar 27 #Javascript
基于javascript实现九九乘法表
Mar 27 #Javascript
深入浅析JavaScript中的作用域和上下文
Mar 26 #Javascript
JS中改变this指向的方法(call和apply、bind)
Mar 26 #Javascript
浏览器复制插件zeroclipboard使用指南
Mar 26 #Javascript
jquery中validate与form插件提交的方式小结
Mar 26 #Javascript
You might like
php Mysql日期和时间函数集合
2007/11/16 PHP
php模拟ping命令(php exec函数的使用方法)
2013/10/25 PHP
ThinkPHP实现跨模块调用操作方法概述
2014/06/20 PHP
php查找字符串出现次数的方法
2014/12/01 PHP
php实现中文字符截取防乱码方法汇总
2015/04/29 PHP
jquery表格内容筛选实现思路及代码
2013/04/16 Javascript
js弹出div并显示遮罩层
2014/02/12 Javascript
在JavaScript中使用timer示例
2014/05/08 Javascript
js控制网页前进和后退的方法
2015/06/08 Javascript
js滑动提示效果代码分享
2016/03/10 Javascript
js实现上传图片预览方法
2016/10/25 Javascript
jquery对象与DOM对象转化
2017/02/08 Javascript
利用ES6的Promise.all实现至少请求多长时间的实例
2017/08/28 Javascript
详解 vue.js用法和特性
2017/10/15 Javascript
javascript触发模拟鼠标点击事件
2019/06/26 Javascript
在微信小程序中使用mqtt服务的方法
2019/12/13 Javascript
详解Nuxt内导航栏的两种实现方式
2020/04/16 Javascript
vue打包npm run build时候界面报错的解决
2020/08/13 Javascript
Python中使用md5sum检查目录中相同文件代码分享
2015/02/02 Python
python检查URL是否正常访问的小技巧
2017/02/25 Python
python数据处理实战(必看篇)
2017/06/11 Python
Python实现的快速排序算法详解
2017/08/01 Python
python使用numpy读取、保存txt数据的实例
2018/10/14 Python
python 五子棋如何获得鼠标点击坐标
2019/11/04 Python
用python批量移动文件
2021/01/14 Python
浅析HTML5中header标签的用法
2016/06/24 HTML / CSS
彪马美国官网:PUMA美国
2017/03/09 全球购物
大学生个人总结的自我评价
2013/10/05 职场文书
中药专业大学生医药工作求职信
2013/10/25 职场文书
市场营销专科应届生求职信
2013/11/24 职场文书
会计员岗位职责
2014/03/15 职场文书
群众路线领导对照材料
2014/08/23 职场文书
大学生翘课检讨书范文
2014/10/06 职场文书
公司职员入党自传书
2015/06/26 职场文书
毕业欢送晚会主持词
2019/06/25 职场文书
sql中mod()函数取余数的用法
2021/05/29 SQL Server