【全栈开发】精通 MEAN: 使用 MEAN 和 UGLI CRUD 实现响应式 Web 设计
您現在已經了解了 MEAN 應用程序的機制,接下來我們將對第一期文章中創建的 MEAN.JS應用程序進行定制。我們在第二期文章中對該應用程序有了一個大致的了解。在第三期文章中,我將演示該應用程序的基本 CRUD功能。您還會了解一些有關響應式 Web 設計和 Bootstrap 的內容。
本系列其余部分將要構建的應用程序被命名為 UGLI:User Group List and Information 應用程序。我從 2010年開始運營 HTML5 Denver User Group(前身是 Boulder Java User Group,更早以前是 Denver Java UserGroup),因此我是本地用戶組的狂熱粉絲,但是讓我不解的是一直沒有專門的軟件來運行用戶組?,F在我們就要解決這個問題了。
許多用戶組都在 Meetup.com 建立了一個在線主頁。我使用 MEAN 和UGLI 應用程序的目標并不是要取代 Meetup.com;相反,我想與它建立更深入的集成。Meetup.com集中了運行成功的用戶組所需的大部分核心功能;注冊新用戶,發布會議細節、處理 RSVP等等。但是對于用戶組領導者來說仍然缺失一些關鍵功能,包括管理一組會議主持人(presenter)并鏈接到幻燈片(slide deck)。UGLI可以填補這方面的空缺。(參見 下載 獲得完整的樣例代碼)。
調整標記
創建應用程序 UGLI 的第一個任務就是調整應用程序的標記(branding)。需要在應用程序的服務器端對 config 和 app 目錄做一些修改;另外要對客戶端的 public 目錄做一些修改。
首先從 config/env/all.js 中的元數據開始。將標題修改為 HTML5 Denver(或您選擇的用戶組),并將描述修改為 HTML5 Denver User Group,如清單 1 所示。
清單 1. config/env/all.js
'use strict';module.exports = {app: {title: 'HTML5 Denver',description: 'HTML5 Denver User Group',keywords: 'MongoDB, Express, AngularJS, Node.js'},config/env/development.js 中的標題也需要修改,如清單 2 所示。上篇文章中我們已經了解到 development.js 和 all.js 會在運行時合并。
清單 2. config/env/development.js
'use strict';module.exports = {db: 'mongodb://localhost/test-dev',app: {title: 'HTML5 Denver'},接下來,修改導航欄左上角顯示的品牌。為此,需要編輯
public/modules/core/views/header.client.view.html。在大概第 9 列的地方找到 anchor 標記和 navbar-brand 類,將 body 修改為 HTML5 Denver,如清單 3 所示。
清單 3. public/modules/core/views/header.client.view.html
<div class="container" data-ng-controller="HeaderController"><div class="navbar-header"><button class="navbar-toggle" type="button" data-ng-click="toggleCollapsibleMenu()"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a href="/#!/" class="navbar-brand">HTML5 Denver</a></div><!-- ...snip... --> </div>要驗證所做的修改,請在命令行輸入 mongod 啟動 MongoDB,然后輸入 grunt 啟動應用程序。在瀏覽器中查看 Web 應用程序,看看標記是否顯示在菜單和標題欄中。
要完成標記修改,需要替換 public/modules/core/views/home.client.view.html中的標準文本(boilerplate),該文本顯示在主頁的正文中。創建一個名為 home.client.view.html.original的副本,這樣就可以在稍后往回引用(如果需要的話)。
該文件利用 Bootstrap框架的功能,確保您的網站從一開始就面向移動應用。在繼續之前,需要了解 Bootstrap 提供的 12 列的網格布局。
了解 Bootstrap 和響應式 Web 設計
查看任意硬拷貝新聞或雜志,您都會看到其中使用了列。有時,一副圖片或標題因為某種設計風格而需跨越多個列,但是一個基本的柱狀布局構成了幾乎所有打印頁面的基礎。
Web 頁面也是如此。例如,訪問 TIME網站。您看到它的布局也是基于列的。但是,當您將瀏覽器窗口的寬度從全屏縮小到非常窄的時候,注意會發生什么??梢娏械臄盗繉㈦S著窗口變小而減少,并隨著窗口增大而增多。
這種效應被稱為 響應式Web 設計,因為 Web 頁面會 響應 并調整設計來適應設備所要求的屏幕尺寸。現代 Web開發人員構建的網站可以無縫地支持從最小的手持設備到擁有最大屏幕的臺式機或壁掛屏幕等各種設備。分別使用 http://m.* 和http://www.* URL 為智能手機、平板電腦、筆記本等創建專門的、離散的網站,這種做法早已過時。
響應式 Web 設計 并不是 一個全能的解決方案;相反,它是“一個外觀要求可以適應所有設備的網站”。您不需要選擇用戶訪問網站所使用的設備類型,因此您的設計具備內置的靈活性,可以相應地進行自我調整。
許多流行網站(包括 Facebook 和 Instagram)更多地是通過移動設備而不是傳統計算機來進行訪問的。Twitter的用戶群絕大多數是移動用戶。Twitter 規范了其響應式 Web 設計策略并實現了與 Bootstrap 相同的開源化。Bootstrap 有12 列的布局,可以根據您用來定義列的 CSS 類進行縮小或放大。
請注意,MEAN.JS 應用程序中對 MongoDB、Express、AngularJS 和 Node.js 使用了四個列的布局,如圖 1 所示。
圖 1. Bootstrap 的列布局示例
現在查看 public/modules/core/views/home.client.view.html 中的源代碼,如清單 4 所示,看看Bootstrap 的 12 列布局是什么樣子的。
清單 4. public/modules/core/views/home.client.view.html
<div class="row"><div class="col-md-3"><h2><strong>M</strong>ongoDB</h2></div><div class="col-md-3"><h2><strong>E</strong>xpress</h2></div><div class="col-md-3"><h2><strong>A</strong>ngularJS</h2></div><div class="col-md-3"><h2><strong>N</strong>ode.js</h2></div> </div>如果您向一個父 div 添加 class="row",那么您可以向子div 添加 class="col-_xx_-_N_"屬性來將它們分成幾個列。_N_ 值必須介于 1 和 12之間,_xx_ 值取決于您希望優化布局的設備的尺寸:
- xs 適用于極小設備(低于 768 像素寬)
- sm 用于小型設備(768 和 991 像素之間)
- md 適合中型設備(992 和 1,199 像素之間)
- lg 適合大型設備(1,200 像素或更高)
查看 Bootstrap CSS 文檔的 網格系統小節,了解有關的更多信息。
由于清單 4 中的每個列針對中型(md)設備進行了優化,因此如果在屏幕寬度低于 992 像素的設備上訪問該頁面,列將垂直堆疊而不是水平堆疊。將您的瀏覽器窗口變得足夠窄來觸發這一更改,如圖 2 所示。
圖 2. 移動設備上的響應式 Web 設計示例
現在,可以使用我們已經需到的知識,使用特定于 UGLI 的文本替換 home.client.view.html 中的標準文本。
首先,從 W3C HTML5 徽標頁面 下載256 像素的 HTML5 徽標,并將其復制到public/modules/core/img/brand/HTML5_Logo_256.png。然后使用清單 5 中的源代碼替換public/modules/core/views/home.client.view.html 中現有的 HTML。
清單 5. public/modules/core/views/home.client.view.html
<section data-ng-controller="HomeController"><div class="jumbotron text-center"><div class="row"><div class="col-md-4"><img alt="HTML5" class="img-responsive center-block" src="modules/core/img/brand/HTML5_Logo_256.png" /></div><div class="col-md-8"><h1>The HTML story is still being written.</h1> <h2><em>Come hear the latest chapter at the HTML5 Denver User Group.</em></h2></div></div></div> </section>在較寬的瀏覽器窗口中查看網站時,HTML5 徽標會出現在文本旁邊,如圖 3 所示。
圖 3. 新的 UGLI 主頁
當您將瀏覽器窗口變得足夠窄時,徽標會出現在文本的上方,如圖 4 所示。
圖 4. 新的 UGLI 主頁,它會出現在移動設備上
使用 Bootstrap 可以輕松地讓您的網站對移動應用程序變得更友好,我在為客戶構建每個新網站時都使用 Bootstrap 作為基礎技術。
現在我們將要在 MEAN 堆棧中處理 CRUD。
基礎 CRUD
Meetup.com 可以幫助我很好地管理用戶組活動。但是,在某個活動結束后,就時間方面而言,該活動的重要性不如當天晚上的談話。
換句話說,這個網站的一個用戶用例就是:“下次會議要討論什么?”Meetup.com 可以很好地滿足這種用戶用例。
第二個用戶用例(“向我顯示與 MEAN 堆棧有關的所有談話,不管是什么時候發生的” )正是我準備通過 UGLI應用程序解決的用例。要實現這個用例,必須圍繞一個新的名為 Talk 的模型對象創建一個 CRUD
基礎架構。幸運的是,可以使用一個 Yeoman 生成器來實現這個基礎架構。
在應用程序的根目錄,輸入 yo meanjs:crud-module talks。響應提示:
清單 6 顯示了交互式命令行序列。
清單 6. 使用 Yeoman 生成器生成一個新的 CRUD
模塊
$ yo meanjs:crud-module talks [?] Which supplemental folders would you like to include in your angular module? css, img, directives, filters [?] Would you like to add the CRUD module links to a menu? Yes [?] What is your menu identifier? topbarcreate app/controllers/talks.server.controller.jscreate app/models/talk.server.model.jscreate app/routes/talks.server.routes.jscreate app/tests/talk.server.model.test.jscreate public/modules/talks/config/talks.client.routes.jscreate public/modules/talks/controllers/talks.client.controller.jscreate public/modules/talks/services/talks.client.service.jscreate public/modules/talks/tests/talks.client.controller.test.jscreate public/modules/talks/config/talks.client.config.jscreate public/modules/talks/views/create-talk.client.view.htmlcreate public/modules/talks/views/edit-talk.client.view.htmlcreate public/modules/talks/views/list-talks.client.view.htmlcreate public/modules/talks/views/view-talk.client.view.htmlcreate public/modules/talks/talks.client.module.js在清單 6 中,請注意,生成器創建了服務器端基礎架構(保存在 app 目錄中):路由、一個控制器、一個模型和一個單元測試。它還在public/modules/talks 目錄下構建了所有客戶端工件。
您稍后將向 Talk 對象添加一些自定義字段。在此之前,在瀏覽器中訪問網站,查看默認情況下會得到哪些內容。
單擊右上角的 Signin 鏈接,輸入本系列早些時候創建的用戶名和密碼,或者單擊Signup 并創建一組新的憑證。
完成登錄后,可以在左上角看到一個 Talks 菜單。從菜單中選擇 New Talk打開一個 HTML 表單,其中提供了一個獨立的 Name 字段,如圖 5 所示。
圖 5. 自定義之前的 New Talk 表單
這是一個良好的開端,但是要捕捉 Talk 的所有屬性,您需要的不僅僅是一個簡單文本。
添加新字段實現持久性
要向 Talk 添加新字段,必須編輯 6 個文件 — 四個用于顯示,兩個用于持久性:
- app/models/talk.server.model.js
- public/modules/controllers/talks.client.controller.js
- public/modules/talks/views/create-talk.client.view.html
- public/modules/talks/views/edit-talk.client.view.html
- public/modules/talks/views/view-talk.client.view.html
- public/modules/talks/views/list-talks.client.view.html
首先要處理持久性。解決方案一半用在服務器端,另一半用在客戶端。
服務器端模型(在 app/models/talk.server.model.js中定義)是應用程序的原型。您將在其中命名字段,提供數據類型,驗證規則等等。
客戶端控制器(在 public/modules/controllers/talks.client.controller.js中定義)收集來自用戶的數據輸入,并通過 HTTP 請求將數據推到服務器??刂破鬟€通過連接獲得 JSON 數據,并提供給視圖以用于演示。
此架構的一個有趣之處是對象模型永遠不會離開服務器。對象是來自客戶機的數據的具體化實現,并在 HTTP 響應中序列化到 JSON。
該應用程序有兩個控制器(一個位于服務器端,另一個位于客戶端),但是我們只關心客戶端控制器。服務器端控制器只是將進入的 JSON推入到模型對象。因此在向模型添加額外字段時不需要對服務器端控制器做任何調整??蛻舳丝刂破饕M行一些調整來容納新的字段。
打開 app/models/talk.server.model.js,向服務器端模型添加新的字段,如清單 7 所示。您可以看到展開的
name 字段(如 圖 5
所示),同時還定義了兩個元數據字段:created 和 user。
清單 7. app/models/talk.server.model.js
/*** Talk Schema*/ var TalkSchema = new Schema({name: {type: String,default: '',required: 'Please fill Talk name',trim: true},created: {type: Date,default: Date.now},user: {type: Schema.ObjectId,ref: 'User'} });這個基于 JSON 的模式無需多加解釋。在定義新字段時,您可以指定數據類型、默認值和錯誤消息,以顯示給必要的字段。您還可以做出許多其他優化。查看 Mongoosedocumentation,獲得有關的更多信息。
對 description、presenter 和 slidesUrl添加新字段,如清單 8 所示。在本例中,description 和 presenter都是必要字段。slidesUrl 字段是可選字段。
清單 8. app/models/talk.server.model.js
/*** Talk Schema*/ var TalkSchema = new Schema({name: {type: String,default: '',required: 'Please fill Talk name',trim: true},description: {type: String,default: '',required: 'Please fill Talk description',trim: true}, presenter: {type: String,default: '',required: 'Please fill Talk presenter',trim: true},slidesUrl: {type: String,default: '',trim: true},created: {type: Date,default: Date.now},user: {type: Schema.ObjectId,ref: 'User'} });此時,您的服務器端后端已經準備好接收新字段。現在您需要處理客戶端控制器。打開public/modules/controllers/talks.client.controller.js,添加新的字段,如清單 9 所示。
清單 9. public/modules/controllers/talks.client.controller.js
// Create new Talk $scope.create = function() {// Create new Talk objectvar talk = new Talks ({name: this.name,description: this.description,presenter: this.presenter,slidesUrl: this.slidesUrl});// Redirect after savetalk.$save(function(response) {$location.path('talks/' + response._id);}, function(errorResponse) {$scope.error = errorResponse.data.message;});// Clear form fieldsthis.name = '';this.description = '';this.presenter = '';this.slidesUrl = ''; };在 $scope.create 函數中,表格字段將被聚集到一個 JSON對象,并被發送給服務器,以便實現持久存儲。從模型向控制器添加相應的字段后,您就實現了持久存儲。
現在我們要將注意力轉移到演示層,這樣用戶就可以查看新字段并進行交互。
添加新字段以進行顯示
查看 public/modules/talks/views/。有四個字段與 CRUD 生命周期有關:
- create-talk.client.view.html
- edit-talk.client.view.html
- view-talk.client.view.html
- list-talks.client.view.html
打開 create-talk.client.view.html,如清單 10 所示。
清單 10. 生成的
<section data-ng-controller="TalksController"><div class="page-header"><h1>New Talk</h1></div><div class="col-md-12"><form class="form-horizontal" data-ng-submit="create()" novalidate><fieldset><div class="form-group"><label class="control-label" for="name">Name</label><div class="controls"><input type="text" data-ng-model="name" id="name" class="form-control" placeholder="Name" required></div></div><div class="form-group"><input type="submit" class="btn btn-default"></div><div data-ng-show="error" class="text-danger"><strong data-ng-bind="error"></strong></div></fieldset></form></div> </section>將與 Name 有關的代碼塊復制三次,以便支持Description、Presenter 和slidesUrl,如清單 11 所示。我將 Description 字段設置為textarea,而不是一個簡單的文本字段。同樣,我從 slidesUrl 字段移除了required 屬性,并將 input type 從 text修改為 url。
清單 11. 更新
create-talk.client.view.html
<section data-ng-controller="TalksController"><div class="page-header"><h1>New Talk</h1></div><div class="col-md-12"><form class="form-horizontal" data-ng-submit="create()" novalidate><fieldset><div class="form-group"><label class="control-label" for="name">Name</label><div class="controls"><input type="text" data-ng-model="name" id="name" class="form-control" placeholder="Name" required></div></div><div class="form-group"><label class="control-label" for="description">Description</label><div class="controls"><textarea data-ng-model="description" id="description" class="form-control" placeholder="Description" required></textarea></div></div><div class="form-group"><label class="control-label" for="presenter">Presenter</label><div class="controls"><input type="text" data-ng-model="presenter" id="presenter" class="form-control" placeholder="Presenter" required></div></div><div class="form-group"><label class="control-label" for="slidesUrl">Slides</label><div class="controls"><input type="url" data-ng-model="slidesUrl" id="slidesUrl" class="form-control" placeholder="Slides Url"></div></div> <div class="form-group"><input type="submit" class="btn btn-default"></div><div data-ng-show="error" class="text-danger"><strong data-ng-bind="error"></strong></div></fieldset></form></div> </section>在 Web 瀏覽器中,您新修改的 New Talk 頁面應當類似圖 6 所示。
圖 6. 自定義后的 New Talk 表單
如果對所做的更改感到滿意,請打開 edit-talk.client.view.html 并執行相應的更改,如清單 12 所示。
清單 12. edit-talk.client.view.html
<div class="col-md-12"><form class="form-horizontal" data-ng-submit="update()" novalidate><fieldset><div class="form-group"><label class="control-label" for="name">Name</label><div class="controls"><input type="text" data-ng-model="talk.name" id="name" class="form-control" placeholder="Name" required></div></div><div class="form-group"><label class="control-label" for="description">Description</label><div class="controls"><textarea data-ng-model="talk.description" id="description" class="form-control" placeholder="Description" required></textarea></div></div><div class="form-group"><label class="control-label" for="presenter">Presenter</label><div class="controls"><input type="text" data-ng-model="talk.presenter" id="name" class="form-control" placeholder="Presenter" required></div></div><div class="form-group"><label class="control-label" for="slidesUrl">Slides</label><div class="controls"><input type="url" data-ng-model="talk.slidesUrl" id="name" class="form-control" placeholder="Slides Url"></div></div><div class="form-group"><input type="submit" value="Update" class="btn btn-default"></div><div data-ng-show="error" class="text-danger"><strong data-ng-bind="error"></strong></div></fieldset></form> </div>請注意,用于編輯的 HTML 與之前修改的創建表單稍微有些不同。在編輯時,您已經有了一個 Talk 對象,因此data-ng-model 屬性將以完全限定的方式引用字段,比如用 talk.name 而不是
name。在 Web 瀏覽器中查看修改,如圖 7 所示。
圖 7. 自定義后的 Edit Talk 表單
view-talk.client.view.html 頁面是對象的只讀視圖。用戶在保存新的 Talk,更新現有的Talk 或從列表頁面中選擇 Talk 后將來到該視圖。如清單 13 所示做出修改。
清單 13. edit-talk.client.view.html
<div class="page-header"><h1 data-ng-bind="talk.name"></h1><h2><em>by {{talk.presenter}} <span ng-if="talk.slidesUrl !== '' ">[<a href="{{talk.slidesUrl}}">slides</a>]</span></em></h2><p>{{talk.description}}</p> </div>前面提到 slidesUrl 是可選字段。在視圖頁面中,您將使用 ng-if指令有條件地顯示字段(如果已填充)。在瀏覽器中查看頁面,檢查這一行為,如圖 8 所示。
圖 8. 自定義后的 View Talk 表單
List 視圖是最后一個需要做出調整的視圖。打開 list-talks.client.view.html 并如清單 14 所示進行修改。
清單 14. list-talks.client.view.html
<div class="list-group"><a data-ng-repeat="talk in talks" data-ng-href="#!/talks/{{talk._id}}" class="list-group-item"><h4 class="list-group-item-heading" data-ng-bind="talk.name"></h4><p><em>by {{talk.presenter}}</em></p></a> </div>請注意,這里使用 data-ng-repeat 指令顯示了服務器返回的 talk 列表中的每個talk。在瀏覽器中查看結果,如圖 9 所示。
圖 9. 自定義后的 List Talks 表單
結束語
此時,您已經了解了 MEAN 堆棧交互的各個方面。您使用 Bootstrap 的響應式 Web 設計功能確保您的網站能夠適應所有設備,而不僅限于傳統的有 101 個鍵和鼠標的傳統臺式機。您已經領略了使用 Yeoman 生成器向應用程序添加新 CRUD模塊的強大之處及其便利性。該生成器將原始工件放到正確的目錄中,您只需要對它們進行自定義即可。
下載
范例代碼:wa-mean3src.zip
原文出處:精通 MEAN: 使用 MEAN 和 UGLI CRUD 實現響應式 Web 設計
總結
以上是生活随笔為你收集整理的【全栈开发】精通 MEAN: 使用 MEAN 和 UGLI CRUD 实现响应式 Web 设计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 匿名者黑页html源码,匿名者 黑页源码
- 下一篇: 新版jdk安装,配置,测试详解