亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

自定義Angular指令與jQuery實現的Bootstrap風格數據雙向綁定的單選與多選下拉框

2019-11-20 11:02:03
字體:
來源:轉載
供稿:網友

先說點閑話,熟悉Angular的猿們會喜歡這個插件的。

00.本末倒置

不得不承認我是一個喜歡本末倒置的人,學生時代就喜歡先把晚交的作業先做,留著馬上就要交的作業不做,然后慢悠悠做完不重要的作業,臥槽,XX作業馬上要交了,趕緊補補補。如今做這個項目,因為沒找到合適的多選下拉Web插件,又不想用html自帶的丑陋的<select multiple></select>,自己花了一整天時間做了一個?;蛟S這樣占用的主要功能開發的時間,開發起來會更有緊迫感吧。感覺自己是個抖M自虐傾向,并且伴有css和代碼縮進強迫癥的程序猿。

01.畫蛇添足

Angular強大的控制器似乎已經可以滿足大部分UI上的需求了,但是NodeJS應用往往會使用ejs,jade這樣的模板引擎來動態生成html頁面,那么問題來了,當我想把后臺傳給express中res.render()的參數直接顯示到界面而且綁定到相應的ng-model怎么辦?

解決方法1,不要什么事一次來,Angular的Controller發個post請求再拿數據不就行了

解決方法2,先用模板暫存在html上,再讓Controller根據頁面上的數據來初始化$scope的值

解決方法3,鄙人對Angular和EJS才疏學淺,誰有好辦法教我唄

比如現在要做一個選擇下拉框<select>n個<option>xx</option></select>,選項在后臺,我不想單獨發post拿,也不想放在頁面上,Controller單獨寫邏輯處理,而Angular社區有個ui-select插件,看起來數據是從$scope取的,并不是直接拿的<option />標簽的數據,當時我就火了,不就一個下拉框,自己做唄。

10.樂觀的程序猿

思路很明確,定義一個Angular directive -> 把選項值拿出來 -> 各種事件加加加 -> scope數據綁定 -> 完結撒花
我估計的時間是半天,然而實際花了多久只能呵呵了,css強迫癥,Angular理解不深(所以很多html操作還是在用jQuery),事件考慮不全導致了最終花了超過兩倍的時間做完,
不廢話了,簡單實用,既可以即時綁定ng-model $scope.xxx,也可以直接調jQuery的$("標簽的id").val()也能拿到值,
git傳送門duang:https://git.oschina.net/code2life/easy-select.git
demo傳送門duang~duang:http://ydxxwb.sinaapp.com/easy-select-demo/  (代碼不是最新,有兩個fix的bug還沒有部署上去)

11.放碼

1.使用方法: 引入庫文件Bootstrap,Angular1.x,引入style.css文件(可以修改css自定義自己想要的樣式),easy-select.js,定義Angular的Controller,依賴easySelect模塊,像這樣 ↓
angular.module('dataDisplay', ['easySelect']).controller('selectController', ['$scope', '$http',function ($scope, $http) {  // your code }]);

然后參考demo示例的規范定義選擇框就行啦,是不是很有html原生select標簽的親切感

2.源碼解釋:dom操作和事件都是用jQuery實現的,每一步都有簡略的注釋,實現雙向綁定的關鍵在于取得標簽上定義的ng-model,然后在事件中設置scope[ng-model]的值,
并且調用$digest()循環來讓Angular根據ng-model更新DOM,$digest是Angular實現雙向綁定的核心之一,原理是將變化的scope值同步到所有需要更新的地方,實現暫時還不大明白,有空單獨研究一下這些Angular里面$,$$開頭的東西。

3.自適應與css,Bootstrap就是自適應的,css可以自己定制不同的風格,style.css都有相關注釋

easy-select.js

var comDirective = angular.module('easySelect', []);comDirective.directive("easySelect", function () { return {  link: function (scope, element, attrs) {   var ngModel = $(element).attr("ng-model");   if(!ngModel || ngModel.length == 0) {    ngModel = "defaultSelectModel";   }   var status = false; //toggle boolean   var valueMap = "";   var options = $(element).children();   $(element).attr("style", "padding:0");   //hide original options   $.each(options, function (opt) {    $(options[opt]).attr("style", "display:none");   });   //build ul   var html = "<div id='" + attrs.id + "-root' style='width:100%;position: relative;left:-1px'>" +    "<p id='display-"+attrs.id + "' style='padding:6px 12px "+ ((attrs.multiple != undefined)?"4px":"7px")+    " 12px;margin:0;border:none;width:95%;margin-left:2px;background-color: transparent'>" +    "<span style='display: inline-block;padding-bottom: 3px'> </span></p>" + //this is a dummy span    "<ul id='" + attrs.id +    "-container' class='list-group easy-select-container' style='display:none'>"; //options' container   if(attrs.multiple != undefined) {    $.each(options, function (opt) {     html += "<li value='"+ $(options[opt]).val() +"' class='my-li-container list-group-item option-"+     attrs.id+ "'><div style='width:100%;display:inline-block'>" + $(options[opt]).html() +     "</div><span value='"+ $(options[opt]).val() +"' class='my-li-option glyphicon glyphicon-ok'></span></li>";    });   } else {    $.each(options, function (opt) {     if($(options[opt]).attr("default") != undefined) {      scope[ngModel] = $(options[opt]).val();      valueMap = $(options[opt]).html();      html += "<li value='"+ $(options[opt]).val() +"' class='my-li-container list-group-item option-"+ attrs.id+ "'>"      + $(options[opt]).html() + "</li>";     } else {      html += "<li value='"+ $(options[opt]).val() +"' class='my-li-container list-group-item option-"+ attrs.id+ "'>"      + $(options[opt]).html() + "</li>";     }    });   }   //if multiple, add button   if (attrs.multiple != undefined) {    html += "<li class='list-group-item ' for='ensure-li'><button class='btn btn-default'" +    " for='ensure-btn' style='padding: 2px' > 確定 </button></li>";   }   //render ui   html += "</ul></div>";   $(element).append(html);   $(".my-li-option").each(function(){    $(this).fadeOut(0);   });   if(attrs.multiple == undefined)    $($("#display-"+attrs.id).children()[0]).html(valueMap);   //adjust width   $("#" + attrs.id + "-root").width($("#" + attrs.id + "-root").width() + 2);   //mouse leave event   $(element).mouseleave(function(){    $(".my-li-container").each(function(){     $(this).attr("style","");    });    if(status) {     $("#" + attrs.id + "-container").attr("style", "display:none");     status = !status;    }   });   //multiple select seems complex   if (attrs.multiple != undefined) {    //click event    $(element).click(function (e) {     //if click on tags, remove it     if($(e.target).attr("for") == "option-tag") {      // change val and digest change item in angular      scope[ngModel] = $(element).val().replace($(e.target).attr("value"),"").replace(/;+/,";").replace(/^;/,"");      $(element).val(scope[ngModel]);      scope.$digest();      $(e.target).remove();      $(".my-li-option").each(function(){       if($(this).attr("value") == $(e.target).attr("value")) {        $(this).css("opacity","0.01");       }      });     } else if($(this).attr("for") != 'ensure-li') {      //toggle ul      $("#" + attrs.id + "-container").attr("style", status ? "display:none" : "");      status = !status;     }    });    $(".option-"+attrs.id).each(function(){     $(this).on('click',function(){      var selectValue = $(element).val();      var currentValue = $(this).attr("value");      var selected = false;      //if option is selected ,remove it      var temp = selectValue.split(";");      $.each(temp,function(obj){       if(temp[obj].indexOf(currentValue) != -1) {        selected = true;       }      })      if(selected) {       $($(this).children()[1]).fadeTo(300,0.01);       scope[ngModel] = $(element).val().replace(currentValue,"").replace(/;{2}/,";").replace(/^;/,"");       $(element).val(scope[ngModel]);       scope.$digest();       $("#display-"+attrs.id + " span").each(function(){        if($(this).attr("value") == currentValue) {         $(this).remove();        }       });      } else {       //add option to val() and ui       $($(this).children()[1]).fadeTo(300,1);       scope[ngModel] = ($(element).val()+";"+currentValue).replace(/;{2}/,";").replace(/^;/,"");       $(element).val(scope[ngModel]);       scope.$digest();       $("#display-"+attrs.id).append(        "<span for='option-tag' value='"+ $(this).attr("value") +"' class='p-option-tag'>"        +$(this).children()[0].innerHTML+ "</span>");      }      status = !status; // prevent bubble     });     //control background     $(this).mouseenter(function(){      $(".my-li-container").each(function(){       $(this).attr("style","");      });      $(this).attr("style","background-color:#eee");     });    });   } else {    $(".option-"+attrs.id).each(function(){     $(this).mouseenter(function(){      $(".my-li-container").each(function(){       $(this).attr("style","");      });      $(this).attr("style","background-color:#eee");     });    });    //single select ,just add value and remove ul    $(element).click(function () {     $("#" + attrs.id + "-container").attr("style", status ? "display:none" : "");     status = !status;    });    $(".option-"+attrs.id).each(function(){     $(this).on('click',function(){      scope[ngModel] = $(this).attr("value");      $(element).val(scope[ngModel]);      scope.$digest();      console.log(ngModel);      console.log(element.val());      $($("#display-"+attrs.id).children()[0]).html($(this).html());     });    });   }  } }}); 

 100.如果看到了這里,說明對這個小東西有興趣,git上一起完善吧,自定義選項模板,選項分組這兩個功能還沒有實現。少年,加入開源的大軍吧。

以上所述是小編給大家分享的自定義Angular指令與jQuery實現的Bootstrap風格數據雙向綁定的單選與多選下拉框,希望大家喜歡。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品欧美一区二区三区| 91高清视频免费观看| 精品国产电影一区| 欧美国产亚洲视频| 在线观看日韩专区| 欧美亚洲午夜视频在线观看| 不卡伊人av在线播放| 亚洲精品一区av在线播放| 国产精品日韩欧美综合| 91系列在线播放| 中文字幕精品www乱入免费视频| 不用播放器成人网| 欧美日韩精品在线播放| 久久视频在线直播| 久国内精品在线| 久久综合久久美利坚合众国| 在线视频精品一| 久久久久久久久久久免费| 91沈先生在线观看| 夜色77av精品影院| 粉嫩av一区二区三区免费野| 欧美高清视频免费观看| 亚洲人成电影网站色…| 亚洲日本aⅴ片在线观看香蕉| 亚洲男人7777| 成人免费视频在线观看超级碰| 国产精品美女免费视频| 日韩在线中文视频| 久久影院资源网| 国产精品久久国产精品99gif| 91亚洲精华国产精华| 日韩成人中文字幕在线观看| 亚洲欧洲偷拍精品| www.久久久久| 久久视频在线观看免费| 国产精品久久久久秋霞鲁丝| 久久高清视频免费| 亚洲免费电影在线观看| 国产一区二区三区在线| 91久久久久久久一区二区| 国产精品久久久久久久久久东京| 在线观看国产成人av片| 91色精品视频在线| 欧美性生交大片免网| 国产精品视频在线播放| 热久久视久久精品18亚洲精品| 亚洲综合社区网| 亚洲色在线视频| 国产主播精品在线| 欧美日韩美女在线观看| 中文字幕精品av| 成人动漫网站在线观看| 国产亚洲精品久久久优势| 欧美精品电影在线| 亚洲xxxxx电影| 国产精品入口日韩视频大尺度| 日韩精品在线影院| 欧美日韩激情视频| 久久久久久久久国产| 亚洲人成人99网站| 日韩在线视频二区| 色妞色视频一区二区三区四区| 欧美黑人国产人伦爽爽爽| 精品视频—区二区三区免费| 欧美美女15p| 日本在线精品视频| 日韩一区二区三区在线播放| 亚洲精美色品网站| 欧美日韩国产一区二区| 国产精品黄色影片导航在线观看| 欧美日韩国产精品专区| 欧美激情精品久久久久久免费印度| 精品国产欧美一区二区三区成人| 亚洲最大福利视频网| 中文字幕av一区中文字幕天堂| 国产成人97精品免费看片| 性日韩欧美在线视频| 成人av资源在线播放| 4k岛国日韩精品**专区| 国产成人精品亚洲精品| 成人免费视频网| 欧美精品一区在线播放| 欧美成人免费在线观看| 在线视频中文亚洲| 亚洲激情在线观看| 国产精品日韩在线| 国产精品美乳一区二区免费| 欧美成人网在线| 日韩av电影免费观看高清| 97视频在线观看亚洲| 亚洲午夜未满十八勿入免费观看全集| 视频在线观看一区二区| 日韩精品亚洲精品| 亚洲精品www久久久久久广东| 中文字幕亚洲欧美日韩2019| 欧美性xxxxx极品| 国产一区红桃视频| 欧美日韩性视频| 久久久噜噜噜久久久| 亚洲精品国产综合区久久久久久久| 久久久久久久久久久人体| 欧美激情a∨在线视频播放| 日韩精品视频在线| 亚洲香蕉成人av网站在线观看| 日韩欧美国产中文字幕| 欧美成人午夜免费视在线看片| 久久中文字幕一区| 国产精品视频一区国模私拍| 国产精品九九久久久久久久| 欧美日韩黄色大片| 日本不卡视频在线播放| 国产精品无码专区在线观看| 久久av红桃一区二区小说| 亚洲天堂一区二区三区| 久久视频国产精品免费视频在线| 黑人精品xxx一区| 亚洲综合最新在线| 亚洲欧美中文在线视频| 国产啪精品视频| 情事1991在线| 欧美在线xxx| 国产成人综合精品| 色偷偷综合社区| 亚洲aa中文字幕| 亚洲品质视频自拍网| 日韩在线观看免费| 色妞在线综合亚洲欧美| 亚洲男人天堂视频| 国产精品亚洲第一区| 91成品人片a无限观看| 97久久超碰福利国产精品…| 欧美一性一乱一交一视频| 国产精品免费看久久久香蕉| 成人国产精品日本在线| 亚洲第一国产精品| 国产精品丝袜高跟| 色系列之999| 97色在线播放视频| 欧美高清视频在线播放| 欧美日韩国产精品一区二区三区四区| 福利一区福利二区微拍刺激| www.欧美三级电影.com| 国产精品一区二区三区久久久| 亚洲国产一区二区三区在线观看| 91麻豆国产精品| 亚洲欧美日韩精品久久亚洲区| 欧美专区福利在线| 亚洲国产精品大全| 精品动漫一区二区| 俺去亚洲欧洲欧美日韩| 国产欧美日韩综合精品| 宅男66日本亚洲欧美视频| 国产精品91一区| 成人美女免费网站视频| 国产精品成久久久久三级| 波霸ol色综合久久| zzijzzij亚洲日本成熟少妇| 91久久在线视频| 黑人巨大精品欧美一区二区一视频| 国模精品系列视频| 日韩av一区二区在线观看| 色婷婷亚洲mv天堂mv在影片| 精品高清一区二区三区| 欧美福利小视频|