Bootstrap每天必學(xué)之級聯(lián)下拉菜單

字號:


    本文將介紹自定義的bootstrap級聯(lián)下拉菜單,主要應(yīng)用場合有省市級關(guān)聯(lián)菜單等等,那么就先拿這個(gè)例子來講,當(dāng)然其他場景的關(guān)聯(lián)菜單也同樣適用。說實(shí)話,封裝好一個(gè)通用的組件還是需要花費(fèi)很多精力的和時(shí)間的,所謂通用,自然要考慮周全,嘆!這次整理的Bootstrap關(guān)聯(lián)select,里面也涉及到了很多jquery、ajax、springMVC等等知識點(diǎn),可謂包羅萬象!
    首先,請?jiān)试S我代表該自定義組件做一番小小的介紹。
    “hi,你好,我叫yunm.combox.js,主人給我起的名字,其實(shí)呢,挺俗的。我主要通過為select組件增加兩個(gè)自定義屬性來完成相應(yīng)的數(shù)據(jù)加載,數(shù)據(jù)請求使用了ajax,后端數(shù)據(jù)處理使用了springMVC(當(dāng)然其他方式也可以,只需要返回對應(yīng)的json數(shù)據(jù)即可),使用起來呢,就非常非常簡單了!”
    一、界面效果
    名單
    當(dāng)然了,從界面上完全看不出來一個(gè)組件封裝的好壞,但至少,你感覺很簡潔漂亮,那么好了,有了這層印象,你是否有興趣繼續(xù)看下去?我想答案是肯定的。
    二、使用方法
    ①、procity.jsp
    首先呢,在頁面上加載yunm.combox.js(稍候介紹,至于其他的bootstrap的css和js,不在本章介紹范圍內(nèi),略過),同時(shí)呢,創(chuàng)建兩個(gè)select,具體格式見如下:
    <script type="text/javascript" src="${ctx}/components/yunm/yunm.combox.js"></script>
    <div>
      <div>
        <div>
          <select name="province_code" ref="city_select"
            refUrl="${ctx}/procity?pro_code={value}&city_code=HSLY">
          </select>
        </div>
        <div>
          <select name="city_code" id="city_select">
          </select>
        </div>
      </div>
    </div>
    <script type="text/javascript">
    <!--
      $(function() {
        if ($.fn.combox) {
          $("select.combox", $p).combox();
        }
      });
    //-->
    </script>
    ·兩個(gè)select組件,一個(gè)為province_code、一個(gè)為city_code。
    ·省級菜單上增加了兩個(gè)屬性。 
    ref指定關(guān)聯(lián)菜單為市級菜單city_select
    refUrl指定菜單獲取數(shù)據(jù)的URL 
    pro_code作為獲取市級數(shù)據(jù)的關(guān)鍵因子
    {value}呢,則為通配符,稍候在介紹組件的時(shí)候繼續(xù)講到
    city_code=HSLY,主要用于選中指定的省市菜單,諸如上文中的(河南、洛陽),如果不選中,則city_code=為空
    ·class=”combox” 為該省級下拉框增加jquery選擇器
    ·頁面加載完畢后執(zhí)行combox組件的關(guān)鍵方法,下面詳細(xì)介紹
    ②、yunm.combox.js
    現(xiàn)在我們來看看關(guān)鍵的組件內(nèi)容吧!
    (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增加一個(gè)叫combox的底層(可以查詢jquery幫助文檔)方法。
    ·通過(function($){_onchange、addHtml})(jQuery);為該組件在頁面初始加載時(shí)創(chuàng)建兩個(gè)方法onchange和addHtml,至于(function($) {})(jQuery);我想你如果不了解的話,趕緊百度吧!
    ·先來看combox 方法 
    獲取ref、refUrl,通過ajax向refUrl請求省級菜單數(shù)據(jù),當(dāng)獲取成功后,通過addHtml方法將json轉(zhuǎn)換后的option綁定到省級菜單select上
    然后呢,為省級菜單select綁定change事件,傳遞的參數(shù)為ref(市級菜單)、refUrl(市級數(shù)據(jù)獲取的url)、$this(省級菜單,便于change事件獲取對應(yīng)選中項(xiàng),如效果圖中的河南)
    通過trigger方法立即執(zhí)行change事件,便于獲取對應(yīng)的市級菜單內(nèi)容。
    ·再來看_onchange方法,主要是點(diǎn)擊省級菜單時(shí)觸發(fā),用于獲取市級菜單列表 
    refUrl,向服務(wù)端請求的URL
    value,用于獲取省級菜單的選中項(xiàng)目,然后通過該value值獲取省級對應(yīng)的市級菜單
    $ref.empty();用于清空市級菜單
    通過ajax繼續(xù)獲取市級菜單內(nèi)容,然后通過addHtml方法添加到市級菜單中。
    ·addHtml方法 
    通過jsonEval方法對服務(wù)端傳遞回來的數(shù)據(jù)進(jìn)行eval(eval('(' + data + ')'),如有不懂,可百度)方法處理,否則會(huì)出錯(cuò)。
    $.each(json, function(i) {遍歷json,通過jquery創(chuàng)建option對象,然后加入到select中。
    ③、ProcityController
    前端介紹完了,我們回到后端進(jìn)行介紹,當(dāng)然了,你也可以忽略本節(jié),因?yàn)椴皇撬玫年P(guān)聯(lián)數(shù)據(jù)都通過springMVC這種方法獲取,那么先預(yù)覽一下代碼吧!
    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);
      /**
       * 當(dāng)傳遞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("獲取所在地區(qū)" + 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();
            // 轉(zhuǎn)換成標(biāo)準(zhǔn)的option屬性(name,value,selected)
            List<Option> options = new ArrayList<Option>(provincials.size());
            // 被選中的省市
            // 則說明是展示頁面,此時(shí)需要為省級菜單和市級菜單設(shè)置選擇項(xiàng)
            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注解,其實(shí)非常好用,這里就不多做解釋,只是推廣一下,固定個(gè)數(shù)的參數(shù),用該注解更易于代碼的維護(hù)。
    ProvincialService類、CityService類就是兩個(gè)單例,盡量把數(shù)據(jù)放置在內(nèi)存當(dāng)中,減少查詢數(shù)據(jù)庫的次數(shù),稍候貼出來一個(gè)例子。
    Option類就是單純的封裝前端option組件的關(guān)鍵屬性,便于組件的通用化。
    renderJson(response, JsonUtil.toJson(options));將數(shù)據(jù)json化后返回,稍候貼上詳細(xì)代碼。
    ④、ProvincialService.java
    只貼出來代碼例子,不做詳細(xì)解釋,畢竟不是本章重點(diǎn)。
    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方法
    /**
     * 如果出錯(cuò)的話,response直接返回404
     */
    protected void renderJson(HttpServletResponse response, Object responseObject) {
      PrintWriter out = null;
      try {
        if (responseObject == null) {
          response.sendError(404);
          return;
        }
        // 將實(shí)體對象轉(zhuǎn)換為JSON Object轉(zhuǎn)換
        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();
        }
      }
    }
    以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。