Heim >Web-Frontend >js-Tutorial >Zwei-Wege-Datenbindung im Bootstrap-Stil von Einzelauswahl- und Mehrfachauswahl-Dropdown-Feldern, implementiert durch benutzerdefinierte Angular-Direktiven und jQuery_AngularJS
Lassen Sie uns zunächst ein wenig darüber sprechen. Wer mit Angular vertraut ist, wird dieses Plug-in mögen.
00. Das Pferd von hinten aufzäumen
Ich muss zugeben, dass ich ein Mensch bin, der gerne das Pferd von hinten aufzäumt. Als ich Student war, habe ich gerne die späten Hausaufgaben zuerst gemacht, die fälligen Hausaufgaben bald aufgegeben und dann langsam die unwichtigen Hausaufgaben erledigt . Verdammt, die Hausaufgaben sind bald fällig, also beeilen Sie sich und machen Sie sie nach. Jetzt arbeite ich an diesem Projekt, weil ich kein passendes Multi-Select-Dropdown-Web-Plugin finden konnte und ich das hässliche 83e93235161a78387dfc0b11c4aaaabd18bb6ffaf0152bbe49cd8a3620346341 nicht verwenden wollte mit HTML, also habe ich einen ganzen Tag damit verbracht, eines zu erstellen. Möglicherweise erhöht die Zeit, die die Entwicklung der Hauptfunktionen auf diese Weise in Anspruch nimmt, die Entwicklung. Ich fühle mich wie ein Programmierer mit masochistischen Tendenzen und einer Zwangsstörung in CSS und Code-Einrückungen.
01. Überflüssig
Angulars leistungsstarker Controller scheint in der Lage zu sein, die meisten UI-Anforderungen zu erfüllen, aber NodeJS-Anwendungen verwenden häufig Template-Engines wie EJS und Jade, um HTML-Seiten zu generieren. Dann entsteht das Problem, wenn ich den Hintergrund übergeben möchte Was mache ich, wenn die Parameter von res.render() in Express direkt auf der Schnittstelle angezeigt und an das entsprechende NG-Modell gebunden werden?
Lösung 1: Machen Sie nicht alles auf einmal. Der Controller von Angular kann einfach eine Post-Anfrage senden und dann die Daten abrufen
Jetzt möchte ich zum Beispiel ein Auswahl-Dropdown-Feld erstellen 221f08282418e2996498697df914ce4en5a07473c87748fb1bf73f23d45547ab8xx4afa15d3069109ac30911f04c56f333818bb6ffaf0152bbe49cd8a3620346341. Die Optionen befinden sich im Hintergrund Ich möchte sie auch nicht separat auf die Seite stellen, und die Angular-Community verfügt über ein UI-Select-Plugin. Es scheint, dass die Daten aus $scope und nicht direkt aus < stammen ;option /> war damals sehr beliebt, nicht nur ein Drop-Down-Feld, es selbst zu machen.
10. Optimistische Programmierer
Die Idee ist sehr klar, definieren Sie eine Angular-Direktive -> Nehmen Sie den Optionswert heraus -> Fügen Sie verschiedene Ereignisse hinzu -> Ich habe die Zeit auf einen halben Tag geschätzt, aber ich kann nur vermuten, wie lange es tatsächlich gedauert hat. Ich habe ein zwanghaftes CSS, ein schlechtes Verständnis von Angular (so viele HTML-Operationen verwenden immer noch jQuery) und eine unzureichende Berücksichtigung von Ereignissen Letztendlich hat es mehr als doppelt so viel Zeit gekostet,
Kein Unsinn mehr, es ist einfach und praktisch. Sie können entweder ng-model $scope.xxx im laufenden Betrieb binden oder jQuerys $("label's id").val() direkt anpassen, um den Wert
zu erhalten
Git-Portal hier:
https://git.oschina.net/code2life/easy-select.git
Demoportal duang~duang: http://ydxxwb.sinaapp.com/easy-select-demo/
(Der Code ist nicht der neueste, es gibt zwei Fehlerbehebungen, die noch nicht bereitgestellt wurden)
1. Verwendung: Führen Sie die Bibliotheksdatei Bootstrap, Angular1.x ein, führen Sie die Datei style.css ein (Sie können das CSS ändern, um den gewünschten Stil anzupassen), easy-select.js, definieren Sie Angulars Controller und Verlassen Sie sich auf das easySelect-Modul. So↓
Dann beziehen Sie sich einfach auf die Spezifikation des Demo-Beispiels, um das Auswahlfeld zu definieren. Ist es nicht sehr vertraut mit dem nativen HTML-Auswahl-Tag?
2. Erklärung des Quellcodes: DOM-Operationen und -Ereignisse werden mit jQuery implementiert, und jeder Schritt verfügt über einfache Kommentare. Der Schlüssel zum Erreichen einer bidirektionalen Bindung besteht darin, das für das Tag definierte NG-Modell abzurufen und dann den Bereich festzulegen im Ereignis[ ng-model] Wert,
3. Adaptiv und CSS, Bootstrap ist adaptiv, CSS kann mit verschiedenen Stilen angepasst werden, style.css hat relevante Kommentare
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. Wenn Sie dies sehen, bedeutet dies, dass Sie an dieser kleinen Sache interessiert sind. Lassen Sie es uns gemeinsam auf Git verbessern. Die beiden Funktionen zum Anpassen von Optionsvorlagen und zur Optionsgruppierung wurden noch nicht implementiert. Junger Mann, treten Sie der Open-Source-Armee bei.
Das Obige sind die Dropdown-Felder mit Einzelauswahl und Mehrfachauswahl, die der Editor mit benutzerdefinierten Angular-Anweisungen und der bidirektionalen Bindung von Daten im Bootstrap-Stil durch jQuery geteilt hat. Ich hoffe, es gefällt Ihnen.