搜尋
首頁web前端js教程自訂Angular指令與jQuery實作的Bootstrap風格資料雙向綁定的單選與多選下拉框_AngularJS

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

00.本末倒置

我不得不承認我是一個喜歡本末倒置的人,學生時代就喜歡先把晚交的作業先做,留著馬上就要交的作業不做,然後慢悠悠做完不重要的作業,臥槽, XX作業馬上要交了,趕緊補補。如今做這個項目,因為沒找到合適的多選下拉Web插件,又不想用html自帶的醜陋的,自己花了一整天時間做了一個。或許這樣佔用的主要功能開發的時間,開發起來會更有緊迫感。感覺自己是個抖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才疏學淺,誰有好辦法教我唄

例如現在要做一個選擇下拉框,選項在後台,我不想單獨發post拿,也不想放在頁面上,Controller單獨寫邏輯處理,而Angular社群有個ui-select插件,看起來數據是從$scope取的,並不是直接拿的標籤的數據,當時我就火了,不就一個下拉框,自己做唄。

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)&#63;"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 &#63; "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 &#63; "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風格資料雙向綁定的單選與多選下拉框,希望大家喜歡。

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
在JavaScript中替換字符串字符在JavaScript中替換字符串字符Mar 11, 2025 am 12:07 AM

JavaScript字符串替換方法詳解及常見問題解答 本文將探討兩種在JavaScript中替換字符串字符的方法:在JavaScript代碼內部替換和在網頁HTML內部替換。 在JavaScript代碼內部替換字符串 最直接的方法是使用replace()方法: str = str.replace("find","replace"); 該方法僅替換第一個匹配項。要替換所有匹配項,需使用正則表達式並添加全局標誌g: str = str.replace(/fi

構建您自己的Ajax Web應用程序構建您自己的Ajax Web應用程序Mar 09, 2025 am 12:11 AM

因此,在這裡,您準備好了解所有稱為Ajax的東西。但是,到底是什麼? AJAX一詞是指用於創建動態,交互式Web內容的一系列寬鬆的技術。 Ajax一詞,最初由Jesse J創造

10個JQuery Fun and Games插件10個JQuery Fun and Games插件Mar 08, 2025 am 12:42 AM

10款趣味橫生的jQuery遊戲插件,讓您的網站更具吸引力,提升用戶粘性!雖然Flash仍然是開發休閒網頁遊戲的最佳軟件,但jQuery也能創造出令人驚喜的效果,雖然無法與純動作Flash遊戲媲美,但在某些情況下,您也能在瀏覽器中獲得意想不到的樂趣。 jQuery井字棋遊戲 遊戲編程的“Hello world”,現在有了jQuery版本。 源碼 jQuery瘋狂填詞遊戲 這是一個填空遊戲,由於不知道單詞的上下文,可能會產生一些古怪的結果。 源碼 jQuery掃雷遊戲

如何創建和發布自己的JavaScript庫?如何創建和發布自己的JavaScript庫?Mar 18, 2025 pm 03:12 PM

文章討論了創建,發布和維護JavaScript庫,專注於計劃,開發,測試,文檔和促銷策略。

jQuery視差教程 - 動畫標題背景jQuery視差教程 - 動畫標題背景Mar 08, 2025 am 12:39 AM

本教程演示瞭如何使用jQuery創建迷人的視差背景效果。 我們將構建一個帶有分層圖像的標題橫幅,從而創造出令人驚嘆的視覺深度。 更新的插件可與JQuery 1.6.4及更高版本一起使用。 下載

如何在瀏覽器中優化JavaScript代碼以進行性能?如何在瀏覽器中優化JavaScript代碼以進行性能?Mar 18, 2025 pm 03:14 PM

本文討論了在瀏覽器中優化JavaScript性能的策略,重點是減少執行時間並最大程度地減少對頁面負載速度的影響。

Matter.js入門:簡介Matter.js入門:簡介Mar 08, 2025 am 12:53 AM

Matter.js是一個用JavaScript編寫的2D剛體物理引擎。此庫可以幫助您輕鬆地在瀏覽器中模擬2D物理。它提供了許多功能,例如創建剛體並為其分配質量、面積或密度等物理屬性的能力。您還可以模擬不同類型的碰撞和力,例如重力摩擦力。 Matter.js支持所有主流瀏覽器。此外,它也適用於移動設備,因為它可以檢測觸摸並具有響應能力。所有這些功能都使其值得您投入時間學習如何使用該引擎,因為這樣您就可以輕鬆創建基於物理的2D遊戲或模擬。在本教程中,我將介紹此庫的基礎知識,包括其安裝和用法,並提供一

使用jQuery和Ajax自動刷新DIV內容使用jQuery和Ajax自動刷新DIV內容Mar 08, 2025 am 12:58 AM

本文演示瞭如何使用jQuery和ajax自動每5秒自動刷新DIV的內容。 該示例從RSS提要中獲取並顯示了最新的博客文章以及最後的刷新時間戳。 加載圖像是選擇

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具