먼저 Angular에 익숙한 사람들이라면 이 플러그인을 좋아할 것입니다.
00. 말 앞에 수레를 놓는다
저는 학생 시절에는 늦은 숙제부터 먼저 하고, 숙제는 빨리 끝내고, 중요하지 않은 숙제는 천천히 끝내는 걸 좋아하는 사람이었습니다. . 젠장, XX 숙제가 곧 마감이니 서둘러서 보충하세요. 지금 저는 이 프로젝트를 진행하고 있습니다. 적합한 다중 선택 드롭다운 웹 플러그인을 찾을 수 없었고, 제공되는 보기 흉한 <다중 선택> 기능을 사용하고 싶지 않았기 때문입니다. HTML을 사용했기 때문에 하루 종일 HTML을 만들었습니다. 아마도 이런 식으로 주요 기능을 개발하는 데 소요되는 시간은 개발을 더욱 시급하게 만들 것입니다. 나는 CSS와 코드 들여쓰기에 있어서 마조히즘적 경향과 강박 장애를 가진 프로그래머가 된 것 같은 느낌이 듭니다.
01. 불필요한
Angular의 강력한 컨트롤러는 대부분의 UI 요구 사항을 충족할 수 있는 것처럼 보이지만 NodeJS 애플리케이션은 종종 ejs 및 jade와 같은 템플릿 엔진을 사용하여 HTML 페이지를 동적으로 생성하려고 할 때 문제가 발생합니다. Express의 res.render() 매개변수가 인터페이스에 직접 표시되고 해당 ng-model에 바인딩되면 어떻게 될까요?
해결책 1: 모든 작업을 한꺼번에 수행하지 마세요. Angular의 컨트롤러는 게시 요청을 보낸 다음 데이터를 가져올 수 있습니다.
해결책 2, 먼저 템플릿을 사용하여 HTML에 임시 저장한 다음 컨트롤러가 페이지의 데이터를 기반으로 $scope 값을 초기화하도록 합니다
해결책 3. 저는 Angular와 EJS에 대한 지식이 거의 없습니다. 혹시 좋은 방법을 가르쳐 주실 수 있나요?
예를 들어 이제 선택 드롭다운 상자 를 만들고 싶습니다. 옵션은 게시하고 싶지 않습니다. Controller는 로직 처리를 별도로 작성하고 Angular 커뮤니티에는 ui-select 플러그인이 있는 것 같습니다. 데이터는 <에서 직접 가져오는 것이 아닌 것 같습니다. ;option /> 그 당시에는 드롭다운 박스 하나만 있는 것이 아니라 직접 해보면 아주 인기가 많았습니다.
10. 낙관적인 프로그래머
아이디어는 매우 명확합니다. Angular 지시문을 정의합니다. -> 옵션 값 제거 -> 다양한 이벤트 추가 -> 완료
시간은 반나절 정도 걸릴 것으로 예상했지만 실제로 소요된 시간은 대략 짐작할 수 있습니다. 강박적인 CSS가 있고 Angular에 대한 이해가 부족하며(아직 많은 HTML 작업에서 jQuery를 사용함) 이벤트에 대한 고려가 부족합니다. 결국 두 배 이상의 시간이 걸렸습니다.
더 이상 말도 안 되는 일이 아닙니다. 간단하고 실용적입니다. ng-model $scope.xxx를 즉시 바인딩하거나 jQuery의 $("label's id").val()을 직접 조정하여
값을 얻을 수 있습니다.
Git 포털 듀앙: https://git.oschina.net/code2life/easy-select.git
데모 포털 duang~duang: http://ydxxwb.sinaapp.com/easy-select-demo/ (코드가 최신이 아니며 아직 배포되지 않은 버그 수정이 2개 있습니다)
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) { // 코드 }]);
그럼 데모 예시의 사양을 참고하여 선택 상자를 정의해 보세요. 기본 HTML 선택 태그와 매우 친숙하지 않나요?
2. 소스 코드 설명: DOM 작업과 이벤트는 jQuery로 구현되며, 각 단계에는 간단한 설명이 있습니다. 양방향 바인딩을 달성하는 핵심은 태그에 정의된 ng-model을 얻은 다음 범위를 설정하는 것입니다. 이벤트[ng-model] 값에서
$digest() 루프를 호출하여 Angular가 ng-model에 따라 DOM을 업데이트하도록 합니다. $digest는 Angular의 양방향 바인딩의 핵심 중 하나입니다. 원칙은 변경된 범위 값을 필요한 모든 위치에 동기화하는 것입니다. 업데이트되었습니다. 아직 구현 규모가 크지는 않습니다. 시간이 나면 Angular에서 $, $$로 시작하는 내용을 공부하겠습니다.
3. 적응형 및 CSS, 부트스트랩은 적응형, 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. 이것을 본다면 이 작은 것에 관심이 있다는 뜻입니다. 옵션 템플릿 사용자 정의와 옵션 그룹화라는 두 가지 기능은 아직 구현되지 않았습니다. 젊은이여, 오픈소스 군대에 합류하라.
위는 jQuery로 구현된 사용자 정의 Angular 지침과 Bootstrap 스타일 데이터 양방향 바인딩을 사용하여 편집기에서 공유한 단일 선택 및 다중 선택 드롭다운 상자입니다.