Bootstrap+AngularJS實現對話框、表單和表格
本文主要介紹Bootstrap+AngularJS實現簡單的對話框,並實現表單提交功能,表單提交之後表格的數據同步更新,並且表格實現了選擇動態樣式和刪除行功能。本文適合作爲Bootstrap和AngularJS入門的例子來進行學習。
界面展示
環境準備
由於只是寫一個靜態頁面,所以環境準備只需要在頁面中引入所需要的第三方腳本文件和樣式文件即可。
<link href="./plugin/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<link href="./plugin/font-awesome/css/font-awesome.min.css" rel="stylesheet" />
第一個link引入的是Bootstrap的樣式文件,第二個link是一些常用的三方圖標樣式文件。
<script type="text/javascript" src="./plugin/angular/angular.js"></script>
<script type="text/javascript" src="./plugin/bootstrap/js/bootstrap.min.js"></script>
兩個腳本引入的分別是AngularJS和Bootstrap的腳本文件
(以上引入的文件均爲本地文件,也可以引入CDN靜態服務的URL獲取線上的資源,推薦一個可以查找URL的網址:http://www.bootcdn.cn/)
<script type="text/javascript" src="./script/app.js"></script>
<script type="text/javascript" src="./script/modalController.js"></script>
另外還需要引入自己編寫的腳本文件,這裏第一個是AngularJS邏輯控制部分的腳本,第二個是對話框交互操作函數的腳本。
html編碼
<html ng-app="testviewApp">
在html標籤中加入ng-app指令聲明html爲一個angularJS應用。
<body ng-controller="MainCtrl as mainCtrl">
在body標籤中加入指令ng-controller指令,聲明控制器作用於爲整個body。
<div id="createButton" style="margin:20px;">
<button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#limitSpeedTemplateDialog">
<span id="tv-iui-createTemplate" name_i18n="tv_iui_i18n"></span>
</button>
</div>
以上代碼爲點擊彈出對話框的按鈕,data-toggle=”modal”表示點擊按鈕彈出模態框,data-target=”#limitSpeedTemplateDialog”表示打開的對話框目標爲id爲limitSpeedTemplateDialog的模態框。span標籤爲內聯的文本。
一級對話框代碼:
<div class="modal fade" id="limitSpeedTemplateDialog"
data-backdrop="static" data-keyboard="false" aria-hidden="true">
<div class="modal-dialog" style="width: 80%;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span>×</span>
</button>
<h4 class="modal-title" id="tv-iui-LimitSpeedTemplateTitle">創建限速模板</h4>
</div>
<div class="modal-body">
<form class="form-horizontal" id="templateForm" novalidate>
<div class="form-group">
<label class="control-label col-xs-3 col-sm-3"
for="limit-template-name-input"> <span
id="tv-iui-limitTemplateName">模板名稱</span> <span class="required">*</span>
</label>
<div class="col-xs-7 col-sm-7">
<input type="text" class="form-control"
id="limit-template-name-input" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-3 col-sm-3"
for="limit-template-flow-list"> <span
id="tv-iui-limitTemplateFlow">流量方向</span>
</label>
<div class="col-xs-7 col-sm-7">
<select class="form-control" id="limit-template-flow-list"
ng-model="mainCtrl.selectedFlow"
ng-options="flow for flow in mainCtrl.flows">
</select>
</div>
</div>
</form>
<hr>
<button class="btn btn-success btn-sm" style="margin: 10px;"
data-toggle="modal" data-target="#matchRuleDialog">
<span class="glyphicon glyphicon-plus pull-left"></span> <span
id="tv-iui-openCreateModal">創建</span>
</button>
<div id="matchRuleTable" class="table-responsive">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th id="tv-iui-matchRuleTable-matchItem">匹配項</th>
<th id="tv-iui-matchRuleTable-matchItemValue">匹配項值</th>
<th id="tv-iui-matchRuleTable-promiseSpeed">承諾速率(kbps)</th>
<th id="tv-iui-matchRuleTable-promiseSize">承諾突發尺寸(kbps)</th>
<th id="tv-iui-matchRuleTable-peakSpeed">峯值速率(kbps)</th>
<th id="tv-iui-matchRuleTable-peakSize">峯值突發尺寸(kB)</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="template in mainCtrl.templates"
ng-class="{danger:$index == mainCtrl.selectedRow}"
ng-click="mainCtrl.selectRow($index)">
<td ng-bind="template.matchItem"></td>
<td ng-bind="template.matchItemValue"></td>
<td ng-bind="template.promiseSpeed"></td>
<td ng-bind="template.promiseSize"></td>
<td ng-bind="template.peakSpeed"></td>
<td ng-bind="template.peakSize"></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger pull-left"
id="tv-iui-template-delete"
ng-show="mainCtrl.selectedRow!=undefined"
ng-click="mainCtrl.deleteRow()">刪除</button>
<button type="submit" class="btn btn-primary"
id="tv-iui-template-save">確定</button>
<button class="btn btn-default" data-dismiss="modal"
id="tv-iui-template-cancle">取消</button>
</div>
</div>
</div>
</div>
以上代碼爲創建了一個一級對話框,如下圖所示:
代碼解析:
- class=”modal fade”表示 Bootstrap 內置模態框,fade表示窗口淡入淡出。
- data-backdrop=”static” data-keyboard=”false” 實現點擊窗口之外空白處和按鍵盤Esc鍵時不關閉窗口(默認爲關閉)。
- aria-hidden=”true”實現窗口在未觸發時保持隱藏。
<button type="button" class="close" data-dismiss="modal">
<span>×</span>
</button>
實現窗口關閉按鈕,"×"
爲關閉符號x的實體符號。- class=”form-horizontal” 實現水平樣式的表單。
- class=”control-label 實現label左對齊。
- class=”form-control” 實現表單項的響應式設計,適應不同的屏幕大小。
- class=”col-xs-7 col-sm-7” 同樣爲了實現響應式設計,爲Bootstrap的佈局方式,col-xs-7表示在小屏幕上佔7列,col-sm-7表示在中型屏幕上佔7列。
- ng-model=”mainCtrl.selectedFlow” 爲angularJS指令,實現數據的雙向綁定
ng-options=”flow for flow in mainCtrl.flows” 爲angularJS指令,實現數據遍歷並填充到select標籤中。 - class=”glyphicon glyphicon-plus” 引入font-awesome中的加號圖標。
<table class="table table-bordered table-hover">
實現帶邊框和懸停效果的表格。<tr ng-repeat="template in mainCtrl.templates"
ng-class="{danger:$index == mainCtrl.selectedRow}"
ng-click="mainCtrl.selectRow($index)">
<td ng-bind="template.matchItem"></td>
其中ng-repeat用來遍歷數據,danger:$index == mainCtrl.selectedRow表示點擊選擇的表格行爲當前行時顯示danger紅色樣式(即點擊表格哪行,哪行就變紅色),ng-click添加點擊事件函數,ng-bind單向綁定遍歷的數據。
二級對話框代碼:
<div class="modal fade" id="matchRuleDialog" data-backdrop="static"
data-keyboard="false" aria-hidden="true">
<div class="modal-dialog" style="width: 50%;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span>×</span>
</button>
<h4 class="modal-title" id="tv-iui-createMatchRuleTitle">創建匹配規則</h4>
</div>
<div class="modal-body">
<form class="form-horizontal" id="createMatchRuleForm"
name="mainCtrl.matchRuleForm" novalidate>
<div class="form-group">
<label class="control-label col-lg-3 col-sm-3 col-xs-3"
for="matchItemList"><span id="tv-iui-matchItemLabel">匹配項</span></label>
<div class="col-lg-7 col-sm-7 col-xs-7">
<select class="form-control" id="matchItemList"
ng-model="mainCtrl.newTemplate.matchItem"
ng-options="item for item in mainCtrl.matchItems">
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-lg-3 col-sm-3 col-xs-3"
for="matchItemValue-input"> <span
id="tv-iui-matchItemValueLabel">匹配項值</span> <span
class="required">*</span>
</label>
<div class="col-lg-7 col-sm-7 col-xs-7">
<input type="text" class="form-control" id="matchItemValue-input"
name="matchItemValue"
ng-model="mainCtrl.newTemplate.matchItemValue" required>
<span style="color: red"
ng-show="mainCtrl.matchRuleForm.matchItemValue.$dirty && mainCtrl.matchRuleForm.matchItemValue.$invalid">
<span
ng-show="mainCtrl.matchRuleForm.matchItemValue.$error.required"
id="tv-iui-requiredWarning">必填項</span>
</span>
</div>
</div>
<div class="form-group">
<label class="control-label col-lg-3 col-sm-3 col-xs-3"
for="promiseSpeed-input"> <span
id="tv-iui-promiseSpeedLabel">承諾速率(kbps)</span> <span
class="required">*</span>
</label>
<div class="col-lg-7 col-sm-7 col-xs-7">
<input type="text" class="form-control" id="promiseSpeed-input"
name="promiseSpeed" ng-model="mainCtrl.newTemplate.promiseSpeed"
placeholder="0-9999" ng-pattern="/^0|[1-9][0-9]{0,3}$/" required>
<span style="color: red"
ng-show="mainCtrl.matchRuleForm.promiseSpeed.$dirty && mainCtrl.matchRuleForm.promiseSpeed.$invalid">
<span
ng-show="mainCtrl.matchRuleForm.promiseSpeed.$error.required"
id="tv-iui-requiredWarning">必填項</span> <span
ng-show="mainCtrl.matchRuleForm.promiseSpeed.$error.pattern"
id="tv-iui-patternWarning">不符合規則</span>
</span>
</div>
</div>
<div class="form-group">
<label class="control-label col-lg-3 col-sm-3 col-xs-3"
for="promiseBandwidth-input"> <span
id="tv-iui-promiseSizeLabel">承諾突發尺寸(kB)</span>
</label>
<div class="col-lg-7 col-sm-7 col-xs-7">
<input type="text" class="form-control"
id="promiseBandwidth-input" name="promiseSize"
ng-model="mainCtrl.newTemplate.promiseSize" placeholder="0-9999"
ng-pattern="/^0|[1-9][0-9]{0,3}$/"> <span
style="color: red"
ng-show="mainCtrl.matchRuleForm.promiseSize.$dirty && mainCtrl.matchRuleForm.promiseSize.$invalid">
<span
ng-show="mainCtrl.matchRuleForm.promiseSize.$error.pattern"
id="tv-iui-patternWarning">不符合規則</span>
</span>
</div>
</div>
<div class="form-group">
<label class="control-label col-lg-3 col-sm-3 col-xs-3" for="promiseSpeed-input"> <span
id="tv-iui-peakSpeedLabel">峯值速率(kbps)</span> <span
class="required">*</span>
</label>
<div class="col-lg-7 col-sm-7 col-xs-7">
<input type="text" class="form-control" id="peakSpeed-input"
name="peakSpeed" ng-model="mainCtrl.newTemplate.peakSpeed"
placeholder="0-9999" ng-pattern="/^0|[1-9][0-9]{0,3}$/" required>
<span style="color: red"
ng-show="mainCtrl.matchRuleForm.peakSpeed.$dirty && mainCtrl.matchRuleForm.peakSpeed.$invalid">
<span ng-show="mainCtrl.matchRuleForm.peakSpeed.$error.required"
id="tv-iui-requiredWarning">必填項</span> <span
ng-show="mainCtrl.matchRuleForm.peakSpeed.$error.pattern"
id="tv-iui-patternWarning">不符合規則</span>
</span>
</div>
</div>
<div class="form-group">
<label class="control-label col-lg-3 col-sm-3 col-xs-3"
for="promiseBandwidth-input"> <span
id="tv-iui-peakSizeLabel">峯值突發尺寸(kB)</span>
</label>
<div class="col-lg-7 col-sm-7 col-xs-7">
<input type="text" class="form-control"
id="promiseBandwidth-input" name="peakSize"
ng-model="mainCtrl.newTemplate.peakSize" placeholder="0-9999"
ng-pattern="/^0|[1-9][0-9]{0,3}$/"> <span
style="color: red"
ng-show="mainCtrl.matchRuleForm.peakSize.$dirty && mainCtrl.matchRuleForm.peakSize.$invalid">
<span ng-show="mainCtrl.matchRuleForm.peakSize.$error.pattern"
id="tv-iui-patternWarning">不符合規則</span>
</span>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary"
id="tv-iui-matchRule-save"
ng-click="[mainCtrl.addTemplate(),mainCtrl.resetTemplate()]"
ng-disabled="mainCtrl.matchRuleForm.$invalid">確定</button>
<button class="btn btn-default" data-dismiss="modal"
id="tv-iui-matchRule-cancle">取消</button>
</div>
</div>
</div>
</div>
以上爲點擊一級對話框中的創建按鈕後彈出的二級對話框代碼,對應界面如下圖:
代碼解析:
- ng-model=”mainCtrl.newTemplate.matchItemValue” required 在表單input標籤中,與數據綁定,且required對輸入框進行必填項驗證。
placeholder=”0-9999”
ng-pattern=”/^0|[1-9][0-9]{0,3}$/”
分別給輸入框加入輸入提示,正則表達式驗證。<span style="color: red"
ng-show="mainCtrl.matchRuleForm.promiseSize.$dirty
&& mainCtrl.matchRuleForm.promiseSize.$invalid">
<span ng-show="mainCtrl.matchRuleForm.promiseSize.$error.pattern"
id="tv-iui-patternWarning">不符合規則</span>
</span>
這段代碼實現表單的驗證動態樣式,輸入框輸入值且未通過驗證則輸入框顯示紅色且在輸入框旁邊顯示”不符合規則“文本,若通過驗證則提示樣式取消。ng-disabled=”mainCtrl.matchRuleForm.$invalid” 實現確定按鈕在表單未通過驗證情況下不能點擊。
js腳本編碼
AngularJS的腳本爲app.js,代碼如下:
angular.module('testviewApp',[])
.controller('MainCtrl',[function(){
this.templates=[
{matchItem:'A', matchItemValue:1, promiseSpeed:10, promiseSize:10, peakSpeed:10,peakSize:10},
{matchItem:'B', matchItemValue:2, promiseSpeed:10, promiseSize:10, peakSpeed:10,peakSize:10},
{matchItem:'C', matchItemValue:3, promiseSpeed:10, promiseSize:10, peakSpeed:10,peakSize:10}
];
this.flows=['W','N','E','S'];
this.selectedFlow='W';
this.matchItems=['A','B','C','D'];
this.newTemplate={matchItem:'A'};
this.addTemplate = function(){
this.templates.push(this.newTemplate);
};
this.resetTemplate = function(){
this.newTemplate={matchItem:'A'};
this.matchRuleForm.$setPristine();
};
this.selectRow = function(rowIndex){
this.selectedRow=rowIndex;
};
this.deleteRow = function(){
this.templates.splice(this.selectedRow,1);
};
}]);
代碼解析:
- angular.module(‘testviewApp’,[]) 定義angular應用,並返回應用。第一個參數與html中聲明的應用名對應,第二個參數爲依賴的服務或控制器數組(目前未用到,所以爲空數組)。
- controller(‘MainCtrl’,[function(){ 定義控制器,第一個參數爲控制器名稱,第二個參數爲控制器函數,對數據的操作都在控制器函數中。
- 控制器函數中的代碼都是對控制器作用域內的數據和事件函數進行初始化和定義,其中 this.matchRuleForm.$setPristine(); 使用angular內置函數讓表單重置爲初始狀態,在取消對話框或提交表單後觸發。
- this.templates.splice(this.selectedRow,1); 實現刪除選中的表格行。
需要注意的是,在angular控制器函數中對綁定數據進行的操作,都會自動同步到界面,不需要對界面進行操作, 實現數據和界面完全分離。
二級對話框提交表單之後同步在一級對話框表格的界面如下圖:
總結
利用Bootstrap直接進行樣式定製可以快速創建出可用的響應式界面,可以比較容易地適應各種大小屏幕;使用AngularJS框架可以用少量的代碼就實現前端頁面的複雜邏輯,將MVC模式完美地應用於前端開發。