【jQuery】selectをカスタマイズするプラグイン


セレクトをいい感じにカスタマイズするプラグインを作成してみた。
まずはデモから。
##[DEMO](http://codepen.io/konweb/pen/hugwE)

###使用方法
1 `select`タグに任意の名前のクラスを付ける
2 `$(".class_name").customSelect();` でプラグインの発動

optionの値を取得して`fm-select-value`と`fm-select-value`というクラスの`div`が生成されます。

* .fm-select-value - 選択された値が入る
* .fm-select-list - optionの値をリストにする
* .label - optgroupタグ使用時のラベルに付与される

あとは、cssで装飾してあげれば、完成です。
selectedも付け替えているので、formの機能もしっかりと使えます。

###ブラウザ対応
ie8でも機能したので、多分大丈夫。

###オプション
せっかくプラグインとして作っているので何かオプションをと思ったので、リストの表示方法を設定してみた。

* `display:"show"` - ぱっぱと表示
* `display:"slide"` - スライドで表示
* `speed` - `display:"slide"`選択時のスライドスピード

###HTML

```index.html
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>select custom</title>
	<link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">
	<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
	<form action="" method="GET">
		<div class="select">
		    <select name="select1" class="js-form-select">
		      <option value="りんご" selected>りんご</option>
		      <option value="ばなな">ばなな</option>
		      <option value="オレンジ">オレンジ</option>
		      <option value="みかん">みかん</option>
		      <option value="ピーチ">ピーチ</option>
		    </select>
	    <i class="fa fa-sort-desc"></i>
	  </div>

		<div class="select">
	    <select name="select2" class="js-form-select">
				<optgroup label="果物">
				  <option class="select-desc" label="" value="" selected>選択してください</option>
				  <option label="さくらんぼ" value="sakura" >さくらんぼ</option>
				  <option label="メロン" value="melon">メロン</option>
				  <option label="ぶどう" value="budou">ぶどう</option>
				  <option label="りんご" value="ringo">りんご</option>
				  <option label="みかん" value="mikan">みかん</option>
				</optgroup>
				<optgroup label="動物">
		      <option value="ゴリラ">ゴリラ</option>
		      <option value="ライオン">ライオン</option>
		      <option value="カメ">カメ</option>
		      <option value="キリン">キリン</option>
		      <option value="カバ">カバ</option>
		      <option value="ゾウ">ゾウ</option>
		      <option value="シマウマ">シマウマ</option>
		      <option value="ウサギ">ウサギ</option>
		    </optgroup>
	    </select>
	    <i class="fa fa-sort-desc"></i>
	  </div>

	  <input type="submit" value="送信">
  </form>
</body>
</html>
```

###jquery

```jquery.js
$(function(){
	$(".js-form-select").customSelect({
    display : "slide"
  });
});

$.fn.customSelect = function(op){
	op = $.extend({
		display: "show",
		speed: 500
	},op);

	return this.each(function(){
		var $this = $(this);
		var objParent = $this.parent("div"),
				setVal;

		if($this.find("option:selected").text()){
			setVal = $this.find("option:selected").text();
		}else{
			setVal = $this.find("option:eq(0)").text();
		}

		$this.after('\
			<div class="fm-select-value">'+setVal+'</div>\
			<div class="fm-select-list"></div>\
		');

		$this.hide();
		objParent.find(".fm-select-list").hide();

		var opGroupNum = $this.find("optgroup").length,
				selectIndex = $this.prop('selectedIndex'),
				selected,attr,opNum,label,i,listLabel,list = "";

		if(opGroupNum > 0){
			var count = 0;
			$this.find("optgroup").each(function(index){
				opNum = $(this).find("option").length;
				label = $(this).attr("label");

				list = "";
				listLabel = "<p class='label "+attr+"' disabled='disabled'>"+label+"</p>";
				for(i = 0;i < opNum;i++){
					attr = $this.find("option").eq(count).attr("class") ? $this.find("option").eq(count).attr("class") : "";
					selected = $this.find("option").eq(count).attr("selected");
					if(selected == "selected"){
						list += "<li class='select-active "+attr+"'>"+$this.find("option:eq("+count+")").text()+"</li>";
					}else{
						list += "<li class='"+attr+"'>"+$this.find("option:eq("+count+")").text()+"</li>";
					}
					count++;
				}
				objParent.find(".fm-select-list").append(listLabel + "<ul>" + list + "</ul>");
			});
		}else{
			opNum = $this.find("option").length;
			for(i = 0;i < opNum;i++){
				attr = $this.find("option").eq(i).attr("class") ? $this.find("option").eq(i).attr("class") : "";
				if(i == selectIndex){
					list += "<li class='select-active "+attr+"'>"+$this.find("option:eq("+i+")").text()+"</li>";
				}else{
					list += "<li class='"+attr+"'>"+$this.find("option:eq("+i+")").text()+"</li>";
				}
			}
			objParent.find(".fm-select-list").append("<ul>" + list + "</ul>");
		}

		//リストの表示・非表示
		objParent.find(".fm-select-list li,.fm-select-value , i").on("click",function(){
       if(op.display == "show"){
         objParent.find(".fm-select-list").toggle();  
       }else{
         objParent.find(".fm-select-list").slideToggle(op.speed);
       }
		});

		//値の切り替え
		objParent.find(".fm-select-list li").on("click",function(){
			var index = $(this).index();
			objParent.find(".fm-select-list li").removeClass("select-active");
			$(this).addClass("select-active");
			$this.find("option").removeAttr("selected");
			$this.find("option:eq("+index+")").attr("selected","selected");
			objParent.find(".fm-select-value").text($(this).text());
		});
	});
}
```

###css
```style.sass
.select
  margin-bottom: 30px
  position: relative
    
  i
    position: absolute
    top: 0px
    left: 182px
    background: #ccc
    width: 30px
    height: 30px
    line-height: 22px
    text-align: center

.fm-select-value
  color: #333
  cursor: pointer
  font-size: 1em
  height: 28px
  line-height: 28px
  padding-left: 10px
  width: 200px
  outline: none
  border: 0
  border: solid 1px #666
  background: #fff

.fm-select-list
  font-size: 14px
  width: 210px
  background: #fff
  border: 1px solid #dfdfdf
  box-shadow: 0px 7px 4px rgba(0, 0, 0, 0.1)
  position: absolute
  top: 30px
  left: 0
  z-index: 1
  
  .select-desc
    display: none
        
  .select-active
    color: #dcdcdc
    
  .label
    color: #333
    font-size: 15px
    margin: 0
    padding: 0
    padding: 10px 10px 0
  
  ul
    list-style: none
    margin: 0
    padding: 0
  
  li
    color: #777
    cursor: pointer
    padding: 8px 5px 8px 15px
    border-bottom: solid 1px #d9d9d9
    &+li
      padding-top: 5px
    
    &:hover
      background: #dfdfdf
      transition: .2s
    
input[type="submit"]
  border: none
  font-size: 15px
  background: #67BD5B
  border-bottom: solid 2px #319435
  width: 200px
  padding: 10px
```