如果有同学基于上一章的代码运行过,那么一定会发现上一章提供的弹窗在实际的web应用开发中根本没法用,为什么?问题太多了:
1.无法控制弹窗后父页面是否可以响应用户的操作(我们希望父页面是否可以响应时可控的);
2.弹窗仅仅只是一个html模板(从代码角度而言),没有说明如何在弹窗内自定义行为(比如弹窗需要在几秒后自动关闭,则需要为弹窗定义一个定时器);
3.没有说明弹窗和父页面如何进行数据交互。
接下来的几篇博客会详细说明基于目前的弹窗功能应该如何处理这些问题。
首先,我们来看问题的现象:
当弹出框显示时,鼠标在父页面与弹出框不重合的任意位置点击,都会导致弹出框消失。这其实不能算是问题,我们引入的第三方插件提供的$modal服务支持我们对弹出框在什么情况下消失进行配置。实际上$modal服务还支持很多配置,想详细了解的同学可以看看这篇博客,里面有对$modal(即笔者博客里说的弹窗或弹出框,通常也被称为模态框)服务API的详细说明:
就我们上面的问题而言,里可以参考API里的这个属性:
backdrop:控制背景,允许的值:true(默认),false(无背景),“static
” - 背景是存在的,但点击模态窗口之外时,模态窗口不关闭
在笔者之前的给的代码示例中并没有对backdrop属性进行配置,所以实际在运行时使用的是默认配置,即true,这表示点击弹出框外部时,弹出框会关闭。
下面我们配置一下backdrop属性看一下效果,首先是配置为配置为false:
在frameworkCtrl.js中定义弹出框时增加backdrop配置项:
/**
* Created by 李庆 on 2016/10/6.
*/
define(["language"],function(i18n){
var frameworkControl=["$rootScope","$scope","$modal",function($rootScope,$scope,$modal){
$rootScope.menus={
"url":"framework/views/menu.html"
};
$scope.i18n = i18n;
$scope.change = function(language){
var expires = new Date(9999,12,31).toUTCString();
document.cookie = "lan="+language+"; "+expires;
location.reload();
};
$scope.modal = function(){
$modal.open({
templateUrl:"framework/views/modal.html",
backdrop:false
});
}
}];
return frameworkControl;
})
新增backdrop配置项位置如下:
重新触发弹出框效果:
可以看到,相比默认的true属性效果,弹出框显示时不再会灰化背景,但是当鼠标在非弹出框范围点击时,弹出框不会消失。
接下来是配置为static(代码和配置项变更截图略):
和默认的true属性效果相比,同样会灰化背景,但是当鼠标在非弹出框范围点击时,弹出框不会消失。这三个属性对应的效果无所谓哪个好哪个不好,而是控件本身提供的功能可以让弹出框匹配不同的业务需求:
true适用于页面的一些告警或提醒,无需用户移动鼠标去点击关闭弹出框,可以提升用户体验;
false适用于全局的页面提示,弹出框不影响用户继续进行其他操作(即可以不管弹出框,继续点击其他的按钮或链接,当然这需要页面进行图层的适配,让弹出框的z-index小 于父页面的z-index);
static适用于最常用的业务逻辑控制,用户必须完成与弹出框的交互才能继续操作父页面。
然后来看一下弹出框和父页面如何进行数据交互(这也是常用的功能,比如商城系统中我们希望用户点击商品列表中的某一件商品时能够在弹出框中显示商品的详细信息,那么 在实现时就必须在点击弹出框的时候把商品id传过去)。
这个问题(或者说需求)可以参考API里的这个属性:
resolve:定义一个成员并将他传递给$modal指定的控制器,相当于routes的一个reslove属性,如果需要传递一个object对象,需要使用angular.copy()
下面笔者用一个最简单的例子来说明resolve的用法——实现父页面向弹出框传递一个“it is a message”字符串这样一个功能:
在frameworkCtrl.js中新增需要传递给弹出框的字符串以及弹出框的controller和resolve:
/**
* Created by 李庆 on 2016/10/6.
*/
define(["language"],function(i18n){
var frameworkControl=["$rootScope","$scope","$modal",function($rootScope,$scope,$modal){
$rootScope.menus={
"url":"framework/views/menu.html"
};
$scope.i18n = i18n;
$scope.item = "it is a message";
$scope.change = function(language){
var expires = new Date(9999,12,31).toUTCString();
document.cookie = "lan="+language+"; "+expires;
location.reload();
};
var modalController = function($scope, $modalInstance, item){
$scope.item = item;
}
$scope.modal = function(){
$modal.open({
templateUrl:"framework/views/modal.html",
backdrop:"static",
controller:modalController,
resolve:{
"item":function(){
return $scope.item;
}
}
});
}
}];
return frameworkControl;
})
在弹出框的视图modal.html中显示父页面传递的值,以便我们确认值已经在弹出框获取:
<div style="width: 600px; height: 200px; border-radius: 4px">
<div>{{item}}</div>
<button ng-click="close()">关闭</button>
</div>
变更代码如下:
重新触发弹出框效果:
可以看到父页面传递的字符串在弹出框正常显示,即我们可以通过$modal提供的controller和resolve来完成父页面向弹出框传值的功能。