国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 語言 > JavaScript > 正文

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

2024-05-06 16:26:08
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了自定義Angular指令與jQuery實現的Bootstrap風格數據雙向綁定的單選與多選下拉框 的相關資料,需要的朋友可以參考下
 

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

00.本末倒置

不得不承認我是一個喜歡本末倒置的人,學生時代就喜歡先把晚交的作業先做,留著馬上就要交的作業不做,然后慢悠悠做完不重要的作業,臥槽,XX作業馬上要交了,趕緊補補補。如今做這個項目,因為沒找到合適的多選下拉Web插件,又不想用html自帶的丑陋的<select multiple></select>,自己花了一整天時間做了一個。或許這樣占用的主要功能開發的時間,開發起來會更有緊迫感吧。感覺自己是個抖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風格數據雙向綁定的單選與多選下拉框,希望大家喜歡。



注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

主站蜘蛛池模板: 宿松县| 安溪县| 揭阳市| 恩平市| 来安县| 黄山市| 余干县| 曲沃县| 长岛县| 自治县| 昌黎县| 清水河县| 通化县| 望江县| 浑源县| 贵州省| 洛阳市| 吉安县| 赤城县| 绥江县| 阜南县| 仁布县| 阿巴嘎旗| 青海省| 惠东县| 屏东市| 吉林省| 娄底市| 沾益县| 扎囊县| 上思县| 宜黄县| 保德县| 和平区| 若羌县| 普宁市| 独山县| 方正县| 桐柏县| 什邡市| 青神县|