1. 서문
이전 주제에서 나는 Knockoutjs와 관련된 지식 포인트를 빠르게 소개하고 간단한 예를 썼습니다. 이 예를 통해 Knockoutjs를 신속하게 시작할 수 있기를 바랍니다. 모든 사람이 실제 프로젝트에서 Knockoutjs의 적용을 명확하게 볼 수 있도록이 주제는 Webapi+Bootstrap+Knockoutjs+ASP.NET MVC를 사용하여 단일 페이지 웹 프로그램을 만드는 방법을 소개합니다. 이 모델은 현재 대부분의 회사의 실제 프로젝트에서도 사용됩니다.
2. 스파 (단일 페이지) 혜택
특정 구현을 도입하기 전에 스파를 자세히 도입해야한다고 생각합니다. 단일 페이지 웹 응용 프로그램의 약어 인 SPA는 단일 HTML 페이지를로드하고 사용자가 응용 프로그램과 상호 작용할 때 페이지를 동적으로 업데이트하는 웹 응용 프로그램입니다. 브라우저는 처음에 필요한 HTML, CSS 및 JavaScript를로드합니다. 모든 작업은이 페이지에서 완료되며 JavaScript에 의해 제어됩니다.
단일 페이지 프로그램의 이점은 다음과 같습니다.
더 나은 사용자 경험을 통해 사용자는 웹 앱에서 기본 앱의 속도와 부드러움을 경험할 수 있습니다.
프론트 엔드 및 백엔드 문제를 분리하고 프론트 엔드는 인터페이스 디스플레이를 담당하며 백엔드는 데이터 저장 및 컴퓨팅을 담당하며 각각의 직무를 수행하며 전면 및 후면 끝의 논리를 혼합하지 않습니다.
서버의 압력을 줄이기 위해 서버는 디스플레이 로직 및 페이지 로직에 관계없이 데이터를 생성하고 서버 처리량을 늘리면됩니다. MVC의 Razor 구문으로 작성된 프론트 엔드는 서버가 페이지의 합성을 완료 한 다음 출력해야합니다.
동일한 백엔드 프로그램 세트는 웹 인터페이스, 휴대 전화, 태블릿 등과 같은 여러 클라이언트에서 직접 사용할 수 있습니다.
물론, 위에 나열된 장점 외에도 단일 페이지 프로그램도 마찬가지입니다.
SEO에게 도움이되지 않습니다. 이것이 관리 시스템 인 경우 영향을 미치지 않습니다.
초기 로딩 시간이 상대적으로 증가합니다. 모든 JS 및 CSS 리소스가 처음으로로드되므로 후속 페이지를 매끄럽게 만듭니다. 이를 위해 ASP.NET MVC에서 번들을 사용하여 파일 바인딩 할 수 있습니다. 번들을 자세히 사용하려면 http://www.vevb.com/article/84329.htm, http://www.vevb.com/article/84329.htm 및 http://www.vevb.com/artvic/82174.htm을 참조하십시오.
내비게이션을 사용할 수 없습니다. 탐색 해야하는 경우 혼자서 전진하고 후퇴해야합니다. 이를 위해, 당신은 그것을 보충하기 위해 직접 앞뒤 기능을 깨달을 수 있습니다. 실제로 이것은 모바일 웹 페이지가 지금하는 일이며 이제는 여전히 위의 내비게이션이어야합니다. 이는 일부 엔터프라이즈 백엔드 관리 시스템에서도 수행 할 수 있습니다.
개발자를위한 높은 개발 비용. 이것은 문제가 아닙니다. 프로그래머는 계속 청구하는 법을 배워야합니다. 다행히도 일부 프론트 엔드 프레임 워크는 사용하기가 매우 쉽습니다.
3. asp.net mvc+webapi+bootstrap+knockoutjs를 사용하여 스파를 구현하십시오
SPA의 장점과 단점은 이전에 자세히 도입되었습니다. 다음으로 ASP.NET MVC+WEBAPI+BS+KO를 사용하여 단일 페이지 프로그램을 구현하여 스파의 부드러움을 경험하고 원래 ASP.NET MVC+Razor의 페이지의 효과를 비교해 보겠습니다.
1. VS2013을 사용하여 ASP.NET 웹 응용 프로그램 프로젝트를 작성하고 MVC 및 WebAPI 라이브러리를 확인하십시오. 자세한 내용은 아래 그림을 참조하십시오.
2. 해당 창고 및 모델 생성. 간단한 작업 관리 시스템은 다음과 같습니다. 특정 모델 및 창고 코드는 다음과 같습니다.
작업 엔티티 클래스 구현 :
public enum taskstate {active = 1, 완료 = 2} /// <summary> /// 작업 엔티티 /// </summary> 공개 클래스 작업 {public int id {get; 세트; } 공개 문자열 이름 {get; 세트; } 공개 문자열 설명 {get; 세트; } public DateTime CreationTime {get; 세트; } public dateTime finishtime {get; 세트; } 공개 문자열 소유자 {get; 세트; } public taskstate state {get; 세트; } public task () {creationtime = dateTime.parse (dateTime.now.tolongDatestring ()); state = taskstate.active; }}작업 창고 클래스 구현 :
/// <summary> /// 여기서 창고는 샘플 데이터를 데모로 사용합니다. 실제 프로젝트는 데이터베이스 /// </summary> public class taskrepository {#region static 제출 된 private static lazy <taskrepository> _taskRepository = new Lazy <taskrepository> () => new taskrepository ())에서 동적으로로드해야합니다. public static taskrepository current {get {return _taskrepository.value; }}} #endregion #region fields 개인 readonly list <atoding> _tasks = new List <aveSt> () {new Task {id = 1, name = "spa 프로그램 만들기", description = "Spa (단일 페이지 웹 응용 프로그램), 스파의 장점은 소량의 대역폭 및 매끄러운 경험", 소유자 = "하드 홀드 =" datetime.parse (datetime.now.adddays (1) .tostring (culture (cultureinfo.invariantculture))}, new task {id = 2, name = "learning knockoutjs", description = "knockoutjs는 양방향 바인딩을 지원하는 mvvm 클래스 라이브러리입니다. datetime.parse (datetime.now.adddays (2) .toString (cultureInfo.invariantculture))}, new task {id = 3, name = "warm angularjs", description = "angularjs는 mvvm과 mvc를 하나와 통합하는 mvvm 프레임 워크입니다. datetime.parse (datetime.now.adddays (3) .tostring (cultureNfo.invariantculture))}, new task {id = 4, name = "charn asp.net mvc 웹 사이트", description = "glimpse는 asp.net, asp.net mvc, asp.net mvc, ef를 지원하는 성능 테스트 도구입니다. 프로젝트 및 코드 실행의 각 링크 실행 시간을 출력 할 수 있습니다. #endregion #region public methods public ienumerable <asking> getall () {return _tasks; } 공개 작업 get (int id) {return _tasks.find (p => p.id == id); } public task add (작업 항목) {if (item == null) {throw new argumentNullexception ( "Item"); } item.id = _tasks.count + 1; _tasks.add (항목); 반품 항목; } public void remove (int id) {_tasks.removeall (p => p.id == id); } public bool update (작업 항목) {if (item == null) {새로운 ArgumentNullexception ( "항목"); } var taskitem = get (item.id); if (taskitem == null) {return false; } _tasks.remove (taskItem); _tasks.add (항목); 진실을 반환하십시오. } #endregion}3. Nuget을 통해 부트 스트랩 및 Knockoutjs 라이브러리를 추가하십시오.
4. 백엔드 데이터 서비스를 구현하십시오. 여기서 백엔드 서비스는 ASP.NET WebAPI를 사용하여 구현됩니다. 특정 구현 코드는 다음과 같습니다.
/// <summary> /// task webapi, 데이터 서비스 제공 /// </summary> public class taskscontroller : apicontroller {private readonly taskrepository _taskrepository = taskrepository.current; public ienumerable <asking> getall () {return _taskrepository.getall (). Orderby (a => a.id); } 공개 작업 get (int id) {var item = _taskRepository.get (id); if (item == null) {throw new httpresponseException (httpstatuscode.notfound); } 반환 항목; } [Route ( "API/TASKSS/GETBYSTATE")] PUBLIC IENUMERABLE <ASPIRE> GETBYSTATE (String State) {IENUMERABLE <asking> results = New List <태스크> (); switch (state.tolower ()) {case "": case "all": results = _taskRepository.getall (); 부서지다; "Active": results = _taskRepository.getall (). 여기서 (t => t.state == taskstate.active); 부서지다; "완료": results = _taskRepository.getall (). 여기서 (t => t.state == taskstate.completed); 부서지다; } results = results.orderby (t => t.id); 반환 결과; } [httppost] 공개 작업 작성 (작업 항목) {return _taskRepository.add (항목); } [httpput] public void put (작업 항목) {if (! _taskrepository.update (item)) {throw new httpresponsexception (httpstatuscode.notfound); }} public void delete (int id) {_taskRepository.remove (id); }}5. ASP.NET MVC 번들을 사용하여 리소스를 포장하십시오. 해당 BundleConfig 구현 코드는 다음과 같습니다.
/// <summary> /// 누락 된 CSS 및 JS 파일을 추가하십시오. 템플릿을 만들 때 일부 CSS 및 JS 파일이 추가되었습니다. scriptBundle ( "~/bundles/jquery"). 포함 ( "~/scripts/jquery- {version} .js"); bundles.add (new scriptBundle ( "~/bundles/jqueryval"). 포함 ( "~/scripts/jquery.validate*")); // ModernIZR의 개발 버전을 사용하여 개발하고 배우십시오. 그런 다음 // 제작 준비가되면 빌드 도구를 사용하여 http://modernizr.com을 사용하여 필요한 테스트 만 선택하십시오. bundles.add (new ScriptBundle ( "~/bundles/modernizr"). 포함 ( "~/scripts/modernizr-*"); bundles.add (새 scriptBundle ( "~/bundles/bootstrap"). 포함 ( "~/scripts/bootstrap.js", "~/scripts/bootstrap-datepicker.min.js"); bundles.add (new StyleBundle ( "~/content/css"). 포함 ( "~/content/bootstrap.css", "~/content/bootstrap-datepicker3.min.css", "~/content/site.css"); bundles.add (새 scriptBundle ( "~/bundles/knockout"). 포함 ( "~/scripts/knockout- {version} .js", "~/scripts/knockout.min.js", "~/scripts/knockout.mapping-latest.js"); bundles.add (new ScriptBundle ( "~/bundles/app"). 포함 ( "~/scripts/app/app.js"); }}6. 열거 유형을 페이지의 문자열로 표시해야하기 때문입니다. 열거는 기본적으로 직렬화 될 때 숫자 유형으로 변환됩니다. 따라서 WebapiconFig 클래스를 다음과 같은 변경해야합니다.
public static class webapiconfig {public static void register (httpconfiguration config) {// 웹 API 구성 및 서비스 // 웹 API 라우팅 config.maphttpattributeroutes (); config.routes.maphttproute (이름 : "defaultapi", lorteTemplate : "api/{컨트롤러}/{id}", defaults : new {id = loureparameter.optional}); // 직렬화를 낙타 케이스 스타일 직렬화 속성 config.jsonformatter.serializersettings.contractresolver = new CamelCasePropertyNamescontresolver (); // 문자열 config.formatters.jsonformatter.serializersettings.converters.add (new stringenumconverter ()); }}참고 : 낙타 소문자 직렬화가 위에서 사용되지 않으면 페이지에 데이터를 바인딩 할 때 조정해야합니다. 예를 들어, 이름 속성을 바인딩 할 때 이름 자본화를 직접 사용하십시오. 이름 메소드를 사용하는 경우이 속성에 정의 오류가 없음을 알려줍니다. JS는 낙타 소문자 스타일을 사용하여 변수 이름을 지정하기 때문입니다. 따라서 직렬화를 위해 낙타 소문자 스타일을 사용하는 것이 좋습니다. 현재 "이름"형식 만 사용하여 바인딩 할 수 있습니다. 이것은 JS 코드 사양과 더 일치합니다.
7. 해당 레이아웃 파일 및 색인 파일 컨텐츠를 수정하십시오.
레이아웃 파일의 특정 코드는 다음과 같습니다.
<! docType html> <html> <head> <meta charset = "utf-8"/> <meta name = "viewport"content = "width = device-width, initial-scale = 1.0"> <title> LearningHard Spa Application </title> @styles.render ( "~/content/css") @scripts.render ( "~/bedles/cs") <body> <div> <div> <div> <p> 간단한 작업 관리 시스템 </p> </div> <div> <ul> <li> <a href = "/"> home </a> </li> </ul> </div> </div> <div id = "main"> @renderbody () <hr /> <pirer> <p> © @dateTime.n @exerning. Application </p> </족장> </div> @scripts.render ( "~/bundles/jquery") @scripts.render ( "~/bundles/bootstrap") @scripts.render ( "~/bundles/knockout") @scripts.render ( "~/bundles/knockout" @scripts.render. </body> </html> 인덱스 페이지 코드는 다음과 같습니다. @{viewbag.title = "index"; 레이아웃 = "~/views/shared/_layout.cshtml";} <div id = "list"data-bind = "if : cancreate"> <h2> tasks </h2> <div> <table> <tr> <th> number </th> <th> <th> deplion </th> <Th> </th> <Th> <th> 완료 시간 </th> <th> statu </th> <th> </th> </tr> </t> <tbody data-bind = "foreach : tasks"> <tr> <td data-bind = "text : id"> </td> <td> <a data-bind = "text : name, click : handlecreateorupdate"> </td >> "> </td> <td data-bind ="text : onder "> </td> <td data-bind ="text : creationtime "> </td> <td data-bind ="text : finishtime "> </td> <td data-bind ="text : state "> </td> <td> <a data-bind ="click " href = "javaScript : void (0)"> 제거 </a> </a> </td> </tbody> </table> </div> <div> a href = "javaScript : void (0)"data-bind = "click (data, event) {settasklist ( 'all')}"> all </a> | <a href = "javaScript : void (0)"data-bind = "클릭 : 함수 (data, event) {settaskList ( 'active')}"> active </a> | <a href = "javaScript : void (0)"data-bind = "click : function (data, event) {settaskList ( 'wompleted')}"> 완료 </a> </div> <div> <a href = "javaScript : void (0)"data-bind = "click : handlecreateorupdate"> ADTS </div id = ""cone "> 스타일 = "가시성 : hidden"> <h2> 태스크 추가 </h2> <br/> <div> <div> <label for = "taskname"> name*</label> <div> <intep type = "text"data-bind = "value : name"id = "taskname"placeholder = "name"> </div> <div> <div> <div> <div> <div> <div> <textArea data-bind = "value : description"rows = "3"id = "taskdesc"name = "taskdesc"placeholder = "description"> </textarea> </div> </div> <div> < "taskowner"> 담당자의 사람*</label> <div> <insation id = "taskowner" "data-bind" "value" "horder": "worlder": </div> </div> <div> <label for = "taskfinish"> 추정 완료 시간*</label> <div> <입력 id = "taskfinish"data-bind = "value : finishtime"name = "taskfinish"> </div> <div> < "taskowner"> 상태*</label> <select id = "valueState" "dataState" "data-state" "indate" "> <pluxt> Active </옵션> <plite> 완료 </옵션> </select> </div> </div> <div> <div> <버튼 데이터-바인드 = "클릭 : handlesaveClick"> 저장 </button> <버튼 데이터-bind = "클릭 : handlebackclick"> back </div> </div> </div>8. 해당 프론트 엔드 스크립트 로직을 만듭니다. JS 코드를 사용하여 데이터를 요청하고 프론트 엔드 바인딩을 위해 해당 뷰 모델 객체를 만듭니다. 특정 JS 구현 코드는 다음과 같습니다.
var taskListViewModel = {tasks : ko.observablearray (), cancreate : ko.observable (true)}; var taskmodel = function () {this.id = 0; this.name = ko.observable (); this.description = ko.observable (); this.finishtime = ko.observable (); this.owner = ko.observable (); this.state = ko.observable (); this.fromjs = function (data) {this.id = data.id; this.name (data.name); this.description (data.description); this.finishtime (data.finishtime); this.owner (data.owner); this.state (data.state); };}; function getAllTasks () {sendajaxRequest ( "get", function (data) {taskListViewModel.tasks.removeall (); for (var i = 0; i <data.length; i ++) {taskListViewModel.tasks.push (data [i]), '', ',' ',' ',' ',' ',' ',' ',' 'state') });} 함수 settaskList (state) {sendajaxRequest ( "get", function (data) {taskListViewModel.tasks.removeall (); for (var i = 0; i <data.length; i ++) {taskListViewModel.tasks.push (data [i]), 'getBystate': ', wate's '). });} 함수 제거 (item) {sendajaxRequest ( "delete", function () {getAllTasks ();}, item.id);} var task = new taskmodel (); ited) {task.fromjs (항목); initDatePicker (); taskListViewModel.cancreate (false); $ ( '#create'). css ( 'Visibility', 'Visible');} function handleBackClick () {taskListViewModel.canCreate (true); $ ( '#create'). css ( 'Visibility', 'Hidden');} 함수 handlesaVeclick (item) {if (item.id == undefined) {sendajaxRequest ( "post", function (newitem) {// newItem은 RECKENDED istviewModel.task (newItem);},},},},} 설명 : item.description, finishtime : item.finishtime, 소유자 : item.owner, state : item.state}); } else {sendajaxRequest ( "put", function () {getAllTasks ();}, null, {id : item.id, name : item.name, description : item.description, finishtime : item.finishtime, 소유자 : item.owner, state : item.state}); } taskListViewModel.CancReate (true); $ ( '#create'). css ( 'Visibility', 'Hidden');} 함수 sendajaxRequest (httpMethod, 콜백, url, reqdata) {$ .ajax ( "/api/tasks" + (url? "/" + url : ""), {type : httpmethod, reqdata}); initDatePicker = function () {$ ( '#create .datePicker'). datePicker ({autoclose : true});}; $ ( '. nav'). on ( 'click', 'li', function () {$ ( '. nav li.Active'). RemoveClass ( 'active'); $ (active ') {getAlltasks ();이 시점에서 단일 페이지 프로그램이 개발되었습니다. 다음으로 그 효과를보기 위해 실행합시다.
위의 실행 결과 데모 다이어그램에서 페이지가로드되면 모든 작업이 한 페이지에서 작동하는 것처럼 보이며 브라우저 페이지가 돌고있는 것처럼 느껴집니다. 이전에 ASP.NET MVC + Razor를 사용하여 개발 된 페이지와 비교하여 스파의 부드러움을 느끼십니까? 이전에는 ASP.NET MVC + Razor를 사용하여 개발 한 페이지가 한 페이지를 요청하면 전체 페이지의 새로 고침을 느낄 수있어 사용자가 매우 나빠질 수 있습니다.
4. 면도기 개발 모델과 비교
나는 모든 사람들이 결과에서 스파의 장점을 보았다고 생각합니다. 다음으로 웹 페이지를 구현하는 전통적인 방법과 비교해야한다고 생각합니다. 면도기 개발 방법에는 두 가지 주요 차이점이 있습니다.
1. 페이지가 렌더링되면 데이터가 브라우저 측에서 처리됩니다. 서버에 있지 않습니다. 각 사용자의 브라우저쪽에 렌더링 압력을 할당하여 웹 사이트 서버의 압력을 줄입니다. 면도기 구문 인 경우 프론트 엔드 페이지 바인딩 문은 다음과 같습니다.
@Model ienumerable <Knockoutjsspa.models.task> @foreach (var item in model) {<tr> <td>@item.name.name </td> <td>@item.description </td> </tr>}이들은 서버 측의 면도기 엔진으로 렌더링됩니다. 이것은 또한 Razor를 사용하여 개발 된 페이지가 페이지를 돌리는 것을 볼 이유이기도합니다. 페이지를 전환 할 때마다 서버에 렌더링을 요청하고 서버 렌더링 후 HTML을 클라이언트에 반환하여 표시해야합니다.
2. 결합 된 데이터는 동적입니다. 이는 데이터 모델의 변경이 페이지에 즉시 반영 될 것임을 의미합니다. 이 효과는 Knockoutjs에 의해 구현 된 양방향 바인딩 메커니즘에 기인합니다.
이 방법을 사용하는 것도 프로그램 개발에 간단합니다. Web API는 데이터를 제공 할 책임이 있으며 프론트 엔드 페이지는 많은 DOM 작업을 줄입니다. DOM 작업은 복잡하고 오류가 발생하기 때문입니다. 이것은 또한 프로그램의 암시 적 버그를 줄이는 것을 의미합니다. 또한 반복적 인 개발을 피하기 위해 휴대 전화, 웹 브라우저 및 여러 플랫폼에서 백엔드 서비스를 사용할 수 있습니다.
5. 요약
이 시점 에서이 기사의 소개가 소개 될 것입니다. 이 기사는 주로 SPA 프로그램을 완료하기 위해 Knockoutjs의 사용을 소개합니다. 실제로 실제 작업에서 단일 페이지 프로그램을 만드는 모델은 angularjs를 기반으로합니다. 그런 다음 녹아웃이 많지만 녹아웃은 MVVM 프레임 워크 일 뿐이며, 라우팅 메커니즘은 ASP.NET MVC의 라우팅 메커니즘과 같은 다른 클래스 라이브러리와 함께 사용해야합니다. Knockoutjs와 비교하여 AngularJS는 MVVM+MVC 프레임 워크입니다. 따라서 다음 주제에서는 AngularJS를 사용하여 단일 페이지 프로그램 (SPA)을 만드는 방법을 소개합니다.
이 기사에서 모든 소스 코드를 다운로드하십시오 : Spawithknockoutjs
여전히 심도있게 공부하고 싶다면 여기를 클릭하여 3 가지 흥미로운 주제를 공부하고 첨부 할 수 있습니다.
부트 스트랩 학습 튜토리얼
부트 스트랩 실용 튜토리얼
부트 스트랩 플러그인 사용 튜토리얼
위의 내용은이 기사에 관한 모든 것입니다. 모든 사람의 학습에 도움이되기를 바랍니다.