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

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

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

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

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

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

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


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

禪工作室 13.0.1
強大的PHP整合開發環境

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

Dreamweaver CS6
視覺化網頁開發工具

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

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具