(三十六)AngularJS项目开发技巧之利用Service&Promise&Resolve解决图片预加载问题(后记)
最后更新于:2022-04-01 16:28:27
# AngularJS项目开发技巧之利用Service&Promise&Resolve解决图片预加载问题(后记)
### 前言
在“AngularJS项目开发技巧之图片预加载”一文中,自己曾经天真的认为提升服务端带宽就可以解决图片加载问题。但自己的想法错了,通过阅读破狼的书《AngularJS深度剖析与最佳实践》,隐隐察觉到是自己的项目架构出现了问题。存在很多待优化的地方。其书中这样写到“如果在实例化控制器之前,需要准备一些特定数据,或者有条件的阻止进入路由,那么可以在$routeProvider中配置Resolve属性来解决。”
### 注:预载入Resolve
使用预载入功能,开发者可以预先载入一系列依赖或者数据,然后注入到控制器中。在ngRoute中resolve选项可以允许开发者在路由到达前载入数据保证(promises)。在使用这个选项时比使用angular-route有更大的自由度。
预载入选项需要一个对象,这个对象的key即要注入到控制器的依赖,这个对象的value为需要被载入的factory服务。
如果传入的是字符串,angular-route会试图匹配已经注册的服务。如果传入的是函数,该函数将会被注入,并且该函数返回的值便是控制器的依赖之一。如果该函数返回一个数据保证(promise),这个数据保证将在控制器被实例化前被预先载入并且数据会被注入到控制器中。
### 思路
将图片下载耗时操作做异步处理。图片下载代码如下:
~~~
try {
var data = {};
appCallServer($http, "9101", data,
//success function
function(data) {
console.log("9101:" + JSON.stringify(data.data));
var adpic = new Array;
for (var i = 0; i
adpic[i] = data.data[i].url;
}
$scope.adpic = adpic;
return true;
},
// fail function
function(data) {
$ionicLoading.show({
template: "查询广告失败,请检查您的网络连接"
});
$timeout(function() {
$ionicLoading.hide();
}, 1200);
return false;
});
} catch (error) {
$scope.showAlert1("call:" + error.message);
return false;
}
~~~
整理后的代码如下:
路由:
~~~
.state('tab.find_med', {
url: "/find_med",
views: {
'tab-find_med': {
templateUrl: "find_medicine.html",
controller: 'find_med_contrller',
resolve:{
adpic:function(){
var data = {};
appCallServer($http, "9101", data,
//success function
function(data) {
console.log("9101_resolve:" + JSON.stringify(data.data));
var adpic = new Array;
for (var i = 0; i
adpic[i] = data.data[i].url;
}
return adpic;
},
// fail function
function(data) {
$ionicLoading.show({
template: "查询广告失败,请检查您的网络连接"
});
$timeout(function() {
$ionicLoading.hide();
}, 1200);
return false;
});
}
}
}
}
})
~~~
控制器:
~~~
$scope.getadpic = function() {
$scope.adpic = adpic;
};
$scope.getadpic();
~~~
执行程序,查看效果,提示如下错误:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad98a5cbf.png)
unpr全称是Unknown Provider,也就是说没有找到注入的东西。
找了半天忽然醒悟了,resolve中的对象只有在相应的控制器中才可以获取到,而自己之前是在别的控制器中添加的resolve对象,难怪总是报服务未注入的错误呢。正确的代码如下:
路由:
~~~
$stateProvider
.state('tab', {
url: "/tab",
templateUrl: "tabs.html",
controller: 'tabsCtrl',
resolve:{
adpic:function(){
return "www";
}
}
})
~~~
控制器:
~~~
myCtrl.controller('tabsCtrl', function($scope, $rootScope, $http, $location,... $timeout, adpic) {
...
$scope.getadpic = function() {
console.log("adpic.........." + adpic);
};
$scope.getadpic();
}
~~~
所以一定要掌握原理。不要茫然。
添加以上代码后,HBuilder报如下错误:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad98c9093.jpg)
通过参考网络文献,优化后的代码如下:
~~~
// 利用Factory单例特性创建服务
myModule.factory('myAdpicService',function($http, $q){
return {
getAdpic: function() {
var d = $q.defer();
var data = {};
appCallServer($http, "9101", data,
//success function
function(data) {
console.log("9101_resolve:" + JSON.stringify(data.data));
var adpic = new Array;
for (var i = 0; i
adpic[i] = data.data[i].url;
}
console.log("adpic___________:" + adpic);
d.resolve(adpic);
},
// fail function
function(data) {
$ionicLoading.show({
template: "查询广告失败,请检查您的网络连接"
});
$timeout(function() {
$ionicLoading.hide();
}, 1200);
d.reject(data);
});
return d.promise;
}
}
});"color: rgb(62, 75, 83); font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">
~~~
~~~
"color:#ff0000;">$stateProvider
.state('tab', {
url: "/tab",
templateUrl: "tabs.html",
controller: 'tabsCtrl',
resolve:{
adpicSunny:function(myAdpicService) {
return myAdpicService.getAdpic();
}
}
}
~~~
控制器中的代码不做任何变化。
### 代码回顾
以上代码通过定义一个独立的service的方式来使用resolve key,并且使用service来相应返回所需的数据(这种方式更容易测试)。并且对于较耗时的图片加载操作做异步处理。这与[Android](http://lib.csdn.net/base/15)中的设计思想一致。至此,图片预加载问题成功解决。
### 有图有真相
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad98dcf40.jpg)
### 参考文献
1.[http://www.bkjia.com/Javascript/1043828.html](http://www.bkjia.com/Javascript/1043828.html)
2.[http://www.bubuko.com/infodetail-828239.html](http://www.bubuko.com/infodetail-828239.html)
3.[http://my.oschina.net/tanweijie/blog/295255](http://my.oschina.net/tanweijie/blog/295255)
### 美文美图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad99076e6.jpg)
(三十四)Angular数据更新不及时问题探讨
最后更新于:2022-04-01 16:28:25
# Angular数据更新不及时问题探讨
### 前言
在修复控制角标正确变化过程中,发觉前端代码组织层次出现了严重问题。传递和共享数据时自己使用的是rootScope,为此造成了全局变量空间的污染。根据《AngularJs深度剖析与最佳实践》,如果两个控制器的协作存在大量的数据共享和交互可以利用Factory等服务的“单例”特性为它们注入一个共享对象来传递数据。而自己在使用rootScope时,出现了变量不一致的情况。如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad985674b.jpg)
按照应用逻辑,“我的”角标变化应与“找药帮查询”角标变化一致。通过运行表明,“找药帮查询”角标存在变化异常的状况。通过阅读代码与调试,发现自己的业务逻辑存在问题。业务代码如下:
~~~
/*
* 更新我的徽标
*/
$rootScope.updateMyBadge = function() {
if (localStorage.logined != '1') {
$rootScope.mybadge = '';
}else{
if ($rootScope.medNoticeBadge_Sunny && $rootScope.medNoticeBadge_Sunny != 0 ) {
$rootScope.mybadge = $rootScope.medNoticeBadge_Sunny;
} else {
$rootScope.mybadge = '';
}
}
}
setTimeout(function(){
$rootScope.updateMyBadge();
},2*1000); // 2秒后执行
~~~
其中$rootScope.mybadge为相应角标变量。其值来自于全局变量$rootScope.medNoticeBadge_Sunny,而这个变量又来自于下面的方法体:
~~~
/*
* 已响应查询找药小红点
*/
$rootScope.updateMedNoticeBadge = function(num) {
console.log(num);
$rootScope.medNoticeBadge = 0;
if (localStorage.getItem('medNoticeBadge')) {
$rootScope.medNoticeBadge = Number(localStorage.getItem('medNoticeBadge'));
$rootScope.medNoticeBadge += num;
} else {
$rootScope.medNoticeBadge += num;
}
localStorage.setItem('medNoticeBadge', $rootScope.medNoticeBadge);
$rootScope.medNoticeBadge_Sunny = localStorage.getItem('medNoticeBadge');
$rootScope.medNoticeBadge = localStorage.getItem('medNoticeBadge');
if (!$rootScope.userinfo.logined) {
localStorage.removeItem('medNoticeBadge');
$rootScope.medNoticeBadge = 0;
}
}
~~~
以上方法体又是通过如下语句调用的:
~~~
/*
*初次查询找药状况查询信息(只调用一次)
*/
$rootScope.getmedNoticeBadge = function() {
if (localStorage.logined == '1') {
var data = {
'stat': "1"
};
appCallServer($http, "9015", data, function(data) {
localStorage.setItem('medNoticeBadge', 0);
$rootScope.updateMedNoticeBadge(data.cnt);
}, function(data) {
console.log("9015_找药状况:" + data.errtext);
});
}
};
$rootScope.getmedNoticeBadge();
~~~
执行时出现了变量更新不及时的错误现象。导致角标显示异常。
通过阅读以上代码,发现变量均是通过rootScope传递的。为此自己通过延时执行角标变化的方法体。但这并不是一个良好的的项目组织层次。自己应该将控制角标变化的方法体封装成服务的形式,利用其单例特性解决数据不一致的情况。
自己尝试利用Factory单例特性创建服务,但是结果错误。代码如下:
~~~
myCtrl.factory('mybadgeService',function($http){
var mybadgeFactory = {};
mybadgeFactory.runMybadgeRequest = function(){
if (localStorage.logined == '1') {
var data = {
'stat': "1"
};
appCallServer($http, "9015", data, function(data) {
console.log("9015_找药状况-查询成功:" + JSON.stringify(data));
return data.cnt;
}, function(data) {
console.log("9015_找药状况:" + data.errtext);
return 0;
});
}
}
return mybadgeFactory;
});
~~~
### 参考文献:
1.[http://www.xker.com/page/e2015/06/199141.html](http://www.xker.com/page/e2015/06/199141.html)
### 美文美图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad987b786.jpg)
(三十三)书海拾贝之简介AngularJS中使用factory和service的方法
最后更新于:2022-04-01 16:28:22
# 简介AngularJS中使用factory和service的方法
AngularJS支持使用服务的体系结构“关注点分离”的概念。服务是JavaScript函数,并负责只做一个特定的任务。这也使得他们成为维护和测试的单独实体。控制器,过滤器可以调用它们作为需求的基础。服务使用AngularJS的依赖注入机制注入正常。
AngularJS提供例如许多内在的服务,如:$http, $route, $window, $location等。每个服务负责例如一个特定的任务,$http是用来创建AJAX调用,以获得服务器的数据。$route用来定义路由信息等。内置的服务总是前缀$符号。
有两种方法来创建服务。
工厂
服务
## 使用工厂方法
对于已经存在实例对象的服务,Factory优先,直接返回这个对象。如:在多个Controller之间共享传递数据;对$resource的请求资源的封装。
使用工厂方法,我们先定义一个工厂,然后分配方法给它。
~~~
var mainApp = angular.module("mainApp", []);
mainApp.factory('MathService', function() {
var factory = {};
factory.multiply = function(a, b) {
return a * b
}
return factory;
});
~~~
### 使用服务方法
对于需要new创建的服务而言,则Service优先,Angular会自动new并创建这个对象实例。Service更容易组织一组相同业务逻辑的API,使得业务逻辑更加的内聚。
使用服务的方法,我们定义了一个服务,然后分配方法。还注入已经可用的服务。
~~~
mainApp.service('CalcService', function(MathService){
this.square = function(a) {
return MathService.multiply(a,a);
}
});
~~~
### 例子
下面的例子将展示上述所有指令。
testAngularJS.html
~~~
html>
head>
title>Angular JS Formstitle>
head>
body>
h2>AngularJS Sample Applicationh2>
div ng-app="mainApp" ng-controller="CalcController">
p>Enter a number: input type="number" ng-model="number" />
button ng-click="square()">Xsup>2sup>button>
p>Result: {{result}}p>
div>
script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js">script>
script>
var mainApp = angular.module("mainApp", []);
mainApp.factory('MathService', function() {
var factory = {};
factory.multiply = function(a, b) {
return a * b
}
return factory;
});
mainApp.service('CalcService', function(MathService){
this.square = function(a) {
return MathService.multiply(a,a);
}
});
mainApp.controller('CalcController', function($scope, CalcService) {
$scope.square = function() {
$scope.result = CalcService.square($scope.number);
}
});
script>
body>
html>
~~~
### 结果
在Web浏览器打开textAngularJS.html。看到结果如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad981bb74.jpg)
## 美文美图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9832681.jpg)
(三十二)书海拾贝之特殊的ng-src和ng-href
最后更新于:2022-04-01 16:28:20
# 书海拾贝之特殊的ng-src和ng-href
在说明这两个指令的特殊之前,需要先了解一下ng的启动及执行过程,如下:
1) 浏览器加载静态HTML文件并解析为DOM;
2) 浏览器加载angular.js文件;
3) angular监听 DOMContentLoaded 事件,监听到时开始启动;
4) angular寻找ng-app指令,确定作用范围;
5) 找到app中定义的Module使用$injector服务进行依赖注入;
6) 根据$injector服务创建$compile服务用于编译;
7) $compile服务编译DOM中的指令、过滤器等;
8) 使用ng-init指令,将作用域中的变量进行替换;
9) 最后生成了我们的最终视图。
可以看到,ng框架是在DOMcontent加载完毕后才开始发挥作用。假如我们模板中有一张图片如下:
那么在页面开始加载到ng编译完成之前,页面上会一直显示一张错误的图片,因为路径{{imgUrl}}还未被替换,就像这样:
为了避免这种情况,我们使用ng-src指令,这样在路径被正确得到之前就不会显示找不到图片。同理,标签的href属性也需要换成ng-href,这样页面上就不会先出现一个地址错误的链接。
顺着这个思路再多想一点,我们在模板中使用{{}}显示数据时,在ng编译完成之前页面上岂不是会显示出大括号及里面的表达式?确实是这样。为了避免这个,ng中有一个与{{}}等同的指令:ng-bind,同样用于单向绑定,在页面刚加载的时候就不会显示出对用户无用的数据了。尽管这样你可能不但没舒心反而更纠结了,{{}}那么好用易理解,还不能用了不成?好消息是我们依然可以使用。因为我编写的是单页面应用,页面只会在加载index.html的时候出这个问题,只需在index.html中的模板中换成ng-bind就行。其他的模板是我们动态加载的,就可以放心使用{{}}了。
(三十一)AngularJS项目开发技巧之获取模态对话框中的组件ID
最后更新于:2022-04-01 16:28:18
# AngularJS项目开发技巧之获取模态对话框中的组件ID
### 需求
出于项目开发需求,需要实现的业务逻辑是:药店端点击查看“已发货”“已收货”订单详情时,模块弹出框中只应出现“取消”按钮。但现实的情况如下图所示。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad974f13c.jpg)
模态框核心代码如下:
~~~
<script type="text/ng-template" id="billDtlContent.html">
<div class="modal-header">
<h3 class="modal-title">立马送药订单</h3>
</div>
<div class="modal-body" id="modal-body" >
<table border="1" class="table table-bordered" >
<tr>
<td>
<div>
<label for="billid">订单编号:</label>
<input ng-model="billid" id="billid" type="text" disabled/>
</div>
</td>
</tr>
...................................................
...................................................
<td>
<div>
<label for="merch_name">配送药店:</label>
<input ng-model="merch_name" id="merch_name" type="text" disabled/>
</div>
</td>
</tr>
</table>
</div>
<div class="modal-footer" id="modal-footer" >
<button id="ok" class="btn btn-primary btn-lg" type="button" ng-click="ok()">确认配送</button>
<button id="reject" class="btn btn-danger btn-lg" type="button" ng-click="reject()">残忍拒绝</button>
<button id="cancel" class="btn btn-warning btn-lg" type="button" ng-click="cancel()">取消</button>
</div>
</script>
~~~
由于模态框的实现代码位于JS脚本中。则考虑使用获取组件ID的方式获取相应组件“确认配送”“残忍拒绝”的ID,经过在其控制器中获取测试,总是显示其值为null。获取语句如下:
~~~
console.log("LTT_Sunny:");
console.log(instance.bill_status_code);
if(instance.bill_status_code === '1' || instance.bill_status_code == '2'){
alert("SHQ:" + document.getElementById("reject"));
}
~~~
经过进一步的阅读代码,发现可以先获取模态框组件的ID,即如下语句实现:
~~~
document.getElementById("billDtlContent.html").innerHTML;
~~~
执行后的结果如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad976ae29.jpg)
那么是不是可以进一步获取其内部组件的ID呢?继续尝试如下:
~~~
document.getElementById("billDtlContent.html").innerHTML.getElementById("reject"));
~~~
结果出现了错误,如下所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9789030.jpg)
吸取前面做二维码时的教训,在其相应html页面中添加如下语句:
<i id="sunny" hidden="hidden"></i>
控制器中的语句如下:
~~~
document.getElementById("sunny").innerHTML = htmlContent;
alert("SHQ:" + document.getElementById("sunny").innerHTML);
alert("SHQ:" + document.getElementById("reject"));
~~~
结果获取到了相应组件的ID。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad979f87d.jpg)
### 总结
有时一个问题解决不了,就应该尝试着通过其它途径进行解决。就像在本文中,既然直接获取无法获取到JS脚本中组件的ID,自己就尝试着将获取到的页面内容再次放到原页面内,然后通过DOM操作再次获取。
### 后续工作
获取到模态框组件ID之后,就需要实现需求了。有关组件的隐藏方法自己已经完成。如下所示:
~~~
//控件隐藏控制函数
function displayHideUI(object)
{
var ui = object;
ui.style.display = "none";
}
// 控件显示控制函数
function displayUI(object)
{
var ui = object;
ui.style.display = "inline-block";
}
~~~
在控制器中调用控件设置方法没有看到效果。
displayHideUI(document.getElementById("reject"));
通过DOM操作可获取到其中的ID名称等等。如下所示:
alert("SHQ:" + document.getElementById("reject").attributes[0].value);
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad97b3d7f.jpg)
在view中做文章是不可能的了,还是需要改变一下思路。**有时灵感就是来的这么突然,就像幸福一样。**考虑在控制器中下手,还是阅读代码,思考是否可以通过if_else的形式实现上述效果。ng-if就暂不考虑了,因为一般的if语句就足以解决问题。既然模态框是根据其ID值加载的,那么自己就可以在控制器中通过if语句控制加载不同的模态框。那么自己就需要在模态框中添加新的模态框内容了。添加的模态框内容如下:
~~~
<script type="text/ng-template" id="billDtlContent1.html">
<div class="modal-header">
<h3 class="modal-title">立马送药订单</h3>
</div>
<div class="modal-body" id="modal-body" >
<table border="1" class="table table-bordered" >
<tr>
<td>
<div>
<label for="billid">订单编号:</label>
<input ng-model="billid" id="billid" type="text" disabled/>
</div>
</td>
</tr>
............................
...................................
<tr>
<td>
<div>
<label for="merch_name">配送药店:</label>
<input ng-model="merch_name" id="merch_name" type="text" disabled/>
</div>
</td>
</tr>
</table>
</div>
<div class="modal-footer" id="modal-footer" >
<button id="cancel_Sunny" class="btn btn-warning btn-lg" type="button" ng-click="cancel()">取消</button>
</div>
</script>
~~~
请注意以上两个模态框是不同的,主要不同点为:模态框的ID、控制按钮。在控制器中,其if控制语句如下:
~~~
console.log("LTT_Sunny:");
console.log(instance.bill_status_code);
if(instance.bill_status_code === '1' || instance.bill_status_code == '2'){
// 在药店订单查询成功后,回调执行模态框弹出
modalInstance = $modal.open({ // 开始执行控制器BillDtlPopCtrl
templateUrl: 'billDtlContent1.html', // 模态窗口的地址,指向创建的视图
controller: 'BillDtlPopCtrl', // 初始化模态范围,为$modal指定的控制器,初始化$scope,该控制器可用$modalInstance注入
resolve: { // 定义一个成员并将他传递给$modal指定的控制器,相当于routes的一个reslove属性,如果需要传递一个objec对象,需要使用angular.copy()
items: function () {
return $scope.items;
}
}
);
}else{
// 在药店订单查询成功后,回调执行模态框弹出
modalInstance = $modal.open({// 开始执行控制器BillDtlPopCtrl
templateUrl: 'billDtlContent.html', // 模态窗口的地址,指向创建的视图
controller: 'BillDtlPopCtrl', // 初始化模态范围,为$modal指定的控制器,初始化$scope,该控制器可用$modalInstance注入
resolve: { // 定义一个成员并将他传递给$modal指定的控制器,相当于routes的一个reslove属性,如果需要传递一个objec对象,需要使用angular.copy()
items: function () {
return $scope.items;
}
}
});
}
~~~
### 效果图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad97c59c0.jpg)
### 参考文献
[http://www.w3school.com.cn/jsref/dom_obj_attributes.asp](http://www.w3school.com.cn/jsref/dom_obj_attributes.asp)
### 美文美图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad97e6db8.jpg)
(三十)AngularJS项目开发技巧之图片预加载
最后更新于:2022-04-01 16:28:16
# AngularJS项目开发技巧之图片预加载
### 绪
项目(移动端采用Ionic 框架)开发完毕,测试阶段发现移动APP首页的广告图片(图片由服务器端返回相应url地址)很难加载,主要原因还是网速。如下图左所示,图片加载完毕如下图右所示。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad96e951c.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad970a1f4.jpg)
### 问题分析
尝试进行图片加载的优化工作。
经过与Ionic群内卖火柴朋友的聊天,获取到如下内容:手机端访问速度受服务端带宽的限制。一个接收一个传输,和两方都有关系。服务器对app影响是很大的。2M 一般是网站使用还可以 app会不乐观。增加服务器带宽比在客户端做工作要好很多,还有就是服务图片优化。缓存机制只是下载后的事情,再说ionic的拉数据加上缓存有bug。只能是轮番 和一些固定图片可以使用。因此考虑使用缓存机制的策略暂时告吹。
### 问题解决
提升服务端带宽。2M-->?M
在这里只是提供一个解决问题的思路,若大家有什么好的建议或想法可以给我留下你宝贵的评论,谢谢。
### 美文美图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9725762.jpg)
(二十九)AngularJS项目开发技巧之localStorage存储
最后更新于:2022-04-01 16:28:13
# AngularJS项目开发技巧之localStorage存储
### 绪
项目开发完毕,测试阶段发现后台管理端二维码生成有问题,问题在于localStorage的存储。如下图左所示,二维码生成完毕包含信息如下图左所示,实际二维码信息如下图右所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad95e8f32.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad960a990.jpg)
经过测试发现二维码实际存储的是上一次的结果。好熟悉~Bingo,自己做导航栏高亮时就遇到过这个问题,当时就是使用的localStorage。问题还是出在localStorage身上。但是存储时:localStorage.setItem(key,value),如果key存在,则更新value。问题的根源正是设置好值之后,value没有更新。这个说法也不对,刷新之后,value的值确实变了。只不过变的时机不对。
回过头来看看之前二维码的生成,猛然发现原来之前使用localStorage生成的二维码也是不对的。必须得加以改进。通过Chrome调试,自己还是看出了一些问题,很明显,二维码生成早于获取订单详情信息。如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad962922b.jpg)
二维码生成端测试语句:
~~~
var a = parent.document.getElementById("sunny");
console.log("a:");
console.log(a);
控制器:
document.getElementById("sunny").innerHTML = medInfo;
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad96450f4.jpg)
既然这样可以正确获取到数据,问题基本上就得到了解决。
var a = parent.document.getElementById("sunny");
console.log("a:");
console.log(a);
var qrcode = new QRCode(document.getElementById("qrcode"), {
width : 200, // 设置二维码宽高96
height : 200
});
qrcode.makeCode(a); // 生成二维码内容
~~~
以上语句便可生成正确的二维码信息。
### 残酷的现实
现实总是那么的残酷。生成的二维码不对,内容为空!
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad965bc31.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad967e7f4.jpg)
回过头来还得继续使用localStorage,但其保存的总是上一次的值,因为二维码页面加载早于父页面,导致localStorage的值总是滞后。
经过证实localStorage.removeItem('billInfo');确实起作用了。好纠结啊!
纠结纠结....
既然子页面加载较早,自己就想是不是可以通过延迟页面加载的方法解决。以下代码实现了子页面方法的延迟执行,结果亮了!可以了,我TTM佩服自己了!不容易啊!
~~~
<script>
// 当页面加载的时候可以调用某些函数
window.onload = function(){
setTimeout(function(){
var billInfo = localStorage.getItem('billInfo');
console.log("billInfo:");
console.log(billInfo);
var a = parent.document.getElementById("sunny");
console.log("a:");
console.log(a);
var qrcode = new QRCode(document.getElementById("qrcode"), {
width : 200, // 设置二维码宽高96
height : 200
});
qrcode.makeCode(billInfo); // 生成二维码内容
localStorage.removeItem('billInfo');
// qrcode.makeCode("http://192.168.1.105:8088/lmapp/billInformation.html");
},0.5*1000);//0.5秒后执行
};
</script>
~~~
### 有图有真相
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad969ac06.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad96b3b2a.jpg)
### 总结
其实以上问题的解决只是绕过了localStorage,而没有实质性的解决localStorage存储问题。本质原因后期进行解决。有关子页面与父页面脚本执行先后顺序,应该是子页面较早执行,若子页面需要利用父页面中的值,则子页面脚本代码需要延迟执行。
### 参考文献
[http://zhidao.baidu.com/link?url=yMKHEn0Q0lk1Mt1V8NPKThdZKAtugobZjZksHH2yPLYtGpByk4Vf1Q7L1SstZoGGMT98Jx1K47qviU-kxMhM2q](http://zhidao.baidu.com/link?url=yMKHEn0Q0lk1Mt1V8NPKThdZKAtugobZjZksHH2yPLYtGpByk4Vf1Q7L1SstZoGGMT98Jx1K47qviU-kxMhM2q)
### 美文美图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad96d1c8c.jpg)
(二十八)解决AngualrJS页面刷新导致异常显示问题
最后更新于:2022-04-01 16:28:11
# 解决AngualrJS页面刷新导致异常显示问题
### 绪
俗话说,细节决定成败,编程亦是如此。编程过程中我们可能会不自觉的忽视一些细节问题,殊不知,这些细节正是导致页面显示出现问题的地方。今略举一例,与君共勉之。
页面正常加载后,显示如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad953187d.jpg)
按F5刷新之后,页面如下所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9554038.jpg)
很明显,页面显示出现了异常。回过头再看看Chrome的错误提示,
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9572846.jpg)
具体代码如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad958cf03.jpg)
正是以上代码导致了错误的发生。
### 追根溯源
让我们回顾一下,错误到底是如何发生的。正常加载情况下,页面正常显示很容易理解,程序是按照既定的数据流走的。但是按F5刷新之后,$stateParams.uid已经不存在了,此时再次调用就会出现undefined的错误,导致页面加载出现异常。
### 如何解决这类问题呢?
首先应在语句执行之前添加变量判断语句,若变量存在且不为空,则可继续执行其它流程。代码如下:
~~~
$scope.pageNumber = 1; // 起始查询页码
$scope.totalItems = 0; // 查询数据总数
$scope.pageCnt = 1; // 初始化总页数
if($stateParams.uid != "" && $stateParams.uid != null && typeof(instance.shopStatementDtl) != "undefined")
{
.................
.................
}
~~~
执行后效果:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad95a6895.jpg)
### 美文美图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad95c3759.jpg)
(二十七)实现二维码信息的集成思路
最后更新于:2022-04-01 16:28:09
# AngularJS实现二维码信息的集成思路
赠人玫瑰,手留余香。若您感觉此篇博文对您有用,请花费2秒时间点个赞,您的鼓励是我不断前进的动力,与君共勉!
[**注:点击此处进行知识充电。**](http://blog.csdn.net/sunhuaqiang1/article/details/50475429)
### 需求
实现生成的二维码包含订单详情信息。
### 思路
获取的内容数据如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9419090.jpg)
现在可以获取到第一级数据,第二级数据data获取不到。利用第一级数据的获取方法获取不到第二级数据。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9431e1b.jpg)
~~~
for(i in data){
alert(i); //获得属性
if(typeof(data[i]) == "object"){
var tmp = data[i];
for(j in tmp){
alert(tmp[j]);
}
}else{
alert(data[i]); //获得属性值
}
}
~~~
经过层层解析,获取到的数据结构如下所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9451af5.jpg)
经过进一步的优化改进,获取到的数据详情如下所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad946bbd1.jpg)
接下来面临的问题就是:如何实现两个html页面间传值?通过搜索,不同页面之间的传值方法有:1.地址传值(get) 2.cookie 3.localstorage 4.sessionStorage 5.flash 6.依赖后端服务器。根据不同场景和需求选择不同方案。
经过自己的多次尝试,终于在localstorage这条路上走通了。
但是在二维码显示的环节上遇到了问题,太大(见下图左)的话影响布局,太小(见下图右)的话二维码无法解析。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9486d41.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad94a2a19.jpg)
自己必须找到一个折中的办法,看来得重新布局一下了,原始布局如下所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad94bb73a.jpg)
改善的页面布局如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad94d6d60.jpg)
### 核心代码
### js
~~~
var tmp;
var medInfo = "{";
for(i in data){
//alert(i); // 获得属性
var trans;
// 对获取信息进行筛选
if(typeof(i) != "undefined" && i != "stat" && i != "merch_uid" && i != "result" && i != "errtext") {
switch (i) {
case "tx_time":
trans = "交易时间";
break;
case "buy_uid":
trans = "购药者帐号";
break;
case "buy_addr":
trans = "收货地址";
break;
case "receiver":
trans = "收货人";
break;
case "receiver_tel":
trans = "收货人电话";
break;
case "old_amt":
trans = "药品总价";
break;
case "amt":
trans = "支付金额";
break;
case "merch_name":
trans = "配送药店";
break;
case "msg":
trans = "客户留言";
break;
case "cnt":
trans = "药品种类";
break;
case "data":
trans = "药品列表";
break;
default:
}
medInfo += "\"" + trans + "\":";
if(typeof(data[i]) == "object"){
tmp = data[i];
//alert("这是一个object对象");
}else{
//alert(data[i]); // 获得属性值
medInfo += "\"" + data[i] + "\",\n";
}
}
}
//alert(tmp.length);
tag = 1;
// 获取二级数据(购物车内容)
for(k = 0; k < tmp.length; k++){
zqy = tmp[k];
for(j in zqy){
//alert(j);
var trans;
// 对获取信息进行筛选
switch (j) {
case "medcnt":
trans = "药品数量";
break;
case "medamt":
trans = "金额总计";
break;
case "medname":
trans = "药品名称";
break;
case "medprice":
trans = "药品价格";
break;
case "medid":
trans = "药品ID";
break;
default:
}
if(tag == 1){
medInfo += "\n[\"" + trans + "\":";
tag = 2;
}else{
medInfo += "\"" + trans + "\":";
}
//alert(zqy[j]);
medInfo += "\"" + zqy[j] + "\",\n";
}
if(k == tmp.length-1){
medInfo += "]";
}else{
medInfo += "],[";
}
}
medInfo += "}";
//alert(medInfo);// 最终的订单详情
document.getElementById("sunny").innerHTML = medInfo;
//alert(document.getElementById("sunny").innerHTML);
localStorage.setItem('billInfo', medInfo);
~~~
### Html js
~~~
<script>
// 当页面加载的时候可以调用某些函数
window.onload = function(){
// alert(localStorage.getItem('billInfo'));
console.log(localStorage.getItem('billInfo'));
var a = parent.document.getElementById("sunny");
var qrcode = new QRCode(document.getElementById("qrcode"), {
width : 96, // 设置二维码宽高96
height : 96
});
qrcode.makeCode(localStorage.getItem('billInfo')); // 默认二维码内容
// qrcode.makeCode("http://192.168.1.105:8088/lmapp/billInformation.html");
};
</script>
~~~
### 有图有真相
扫码后效果图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad94f2482.jpg)
### 参考文献
1. [http://blog.csdn.net/zccst/article/details/6185856](http://blog.csdn.net/zccst/article/details/6185856)
2. [http://zhidao.baidu.com/link?url=Jktv0wA9m7BO-K52gozTBHKGetj-dywKAZokiO1FQQ8cvOyVd5iK8Zas9O6YZ_OEg4byCgUI75_53pJ4aPfayRMKebfeyfGXjQPC1ShQTs_](http://zhidao.baidu.com/link?url=Jktv0wA9m7BO-K52gozTBHKGetj-dywKAZokiO1FQQ8cvOyVd5iK8Zas9O6YZ_OEg4byCgUI75_53pJ4aPfayRMKebfeyfGXjQPC1ShQTs_)
3. [http://www.cnblogs.com/wangxiang/p/3332797.html](http://www.cnblogs.com/wangxiang/p/3332797.html)
4. [http://blog.csdn.net/happyflyingave/article/details/25415413](http://blog.csdn.net/happyflyingave/article/details/25415413)
5. [http://www.jb51.net/article/47692.htm](http://www.jb51.net/article/47692.htm)
6. [http://my.oschina.net/adamboy/blog/74162](http://my.oschina.net/adamboy/blog/74162)
7. [http://www.w3school.com.cn/tiy/t.asp?f=html_table_span](http://www.w3school.com.cn/tiy/t.asp?f=html_table_span)
8. [http://cli.im/text?text37aa640da147831f1126ba0e06e10797](http://cli.im/text?text37aa640da147831f1126ba0e06e10797)
### 美文美图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad951805d.jpg)
(二十五)JS实现导入文件功能
最后更新于:2022-04-01 16:28:07
# JS实现导入文件功能
赠人玫瑰,手留余香。若您感觉此篇博文对您有用,请花费2秒时间点个赞,您的鼓励是我不断前进的动力,共勉!(PS:此篇博文是自己在午饭时间所写,为此没吃午饭,这就是程序猿的生活。![哭](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad912661e.gif)
)
项目开发过程中,需要实现文件上传功能。借此机会学习之。
使用HTML中现有的input type “file”可以支持这一功能。如下所示:
<input ng-model="url" id="url" type="file"/>
浏览时只显示指定文件类型
<input type="file" accept="application/msword" ><br><br>accept属性列表<br>
1.accept="application/msexcel"
2.accept="application/msword"
3.accept="application/pdf"
4.accept="application/poscript"
5.accept="application/rtf"
6.accept="application/x-zip-compressed"
7.accept="audio/basic"
8.accept="audio/x-aiff"
9.accept="audio/x-mpeg"
10.accept="audio/x-pn/realaudio"
11.accept="audio/x-waw"
12.accept="image/gif"
13.accept="image/jpeg"
14.accept="image/tiff"
15.accept="image/x-ms-bmp"
16.accept="image/x-photo-cd"
17.accept="image/x-png"
18.accept="image/x-portablebitmap"
19.accept="image/x-portable-greymap"
20.accept="image/x-portable-pixmap"
21.accept="image/x-rgb"
22.accept="text/html"
23.accept="text/plain"
24.accept="video/quicktime"
25.accept="video/x-mpeg2"
26.accept="video/x-msvideo"
下面的问题是:如何获得文件的上传路径,然后才能进行文件的读写后续操作。
下面是一个图片上传、预览的Demo:
~~~
<!doctype html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
<title>Image preview example</title>
<script type="text/javascript">
var loadImageFile = (function () {
if (window.FileReader) {
var oPreviewImg = null, oFReader = new window.FileReader(),
rFilter = /^(?:image\/bmp|image\/cis\-cod|image\/gif|image\/ief|image\/jpeg|image\/jpeg|image\/jpeg|image\/pipeg|image\/png|image\/svg\+xml|image\/tiff|image\/x\-cmu\-raster|image\/x\-cmx|image\/x\-icon|image\/x\-portable\-anymap|image\/x\-portable\-bitmap|image\/x\-portable\-graymap|image\/x\-portable\-pixmap|image\/x\-rgb|image\/x\-xbitmap|image\/x\-xpixmap|image\/x\-xwindowdump)$/i;
oFReader.onload = function (oFREvent) {
if (!oPreviewImg) {
var newPreview = document.getElementById("imagePreview");
oPreviewImg = new Image();
oPreviewImg.style.width = (newPreview.offsetWidth).toString() + "px";
oPreviewImg.style.height = (newPreview.offsetHeight).toString() + "px";
newPreview.appendChild(oPreviewImg);
}
oPreviewImg.src = oFREvent.target.result;
arr = oPreviewImg.src.toString().split(",");
alert(arr[0]);
alert(arr[1]);
};
return function () {
var aFiles = document.getElementById("imageInput").files;
if (aFiles.length === 0) { return; }
if (!rFilter.test(aFiles[0].type)) { alert("You must select a valid image file!"); return; }
oFReader.readAsDataURL(aFiles[0]);
}
}
if (navigator.appName === "Microsoft Internet Explorer") {
return function () {
alert(document.getElementById("imageInput").value);
document.getElementById("imagePreview").filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = document.getElementById("imageInput").value;
}
}
})();
</script>
<style type="text/css">
#imagePreview {
width: 160px;
height: 120px;
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale);
}
</style>
</head>
<body>
<div id="imagePreview">
</div>
<form name="uploadForm">
<p>
<input id="imageInput" type="file" name="myPhoto" onchange="loadImageFile();" /><br />
<input type="submit" value="Send" /></p>
</form>
</body>
</html>
~~~
### 测试
通过测试,可得到文件的格式、编码方式及编码内容,如下所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad933b5ad.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad93528b4.jpg)
### 领悟
通过阅读代码,可以获取到图片的格式与编码方式了。接下来就是文件的传输了。
经历了两天的屈辱、不甘、痛苦挣扎,自己最终还是顽强的站了起来。
晚上回到宿舍继续挣扎,慢慢思路得以理清:在获取到图片的Base64编码格式之后,自己就联想到了之前写过的文件传输代码了,当然之前写的都是一些基本的文件操作。由此,自己联想,在这使用最原始的文件传输方法应该也可以实现。
早晨到实验室,自己先尝试将图片的Base64编码传输至服务端,在服务端接收到客户端传输来的Base64编码后,采用Base64Img工具包([点击下载工具包](http://download.csdn.net/detail/sunhuaqiang1/9394204))将Base64图片编码转换为图片格式,并保存至指定位置。初次尝试,将图片文件保存至本地是没有问题的。经过更改一些细微的细节问题,将程序部署在阿里云服务器上,经过测试,SUCCESS!
### 核心代码
### html
~~~
<div style="padding-top: 15px">
<label for="pic">更新广告图片 :</label>
<!-- <a class="btn btn-warning btn-sm" id="choice" ng-click="doChoice()" style="font-size:14px; color:red; font-family:微软雅黑; border-radius: 9px;">选择文件</a> -->
<input id="imageInput" type="file" accept="image/jpeg" onchange="loadImageFile();" />
<i id="img" hidden="hidden"></i>
<i id="imgName" hidden="hidden"></i>
</div>
~~~
### javaScript
~~~
arr = oPreviewImg.src.toString().split(",");
document.getElementById("img").innerHTML = arr[1];
document.getElementById("imgName").innerHTML = document.getElementById("imageInput").files[0].name;
//alert(document.getElementById("img").innerHTML);
//alert(document.getElementById("imageInput").files[0].name);// 获取 图片名称(PS:瞬间感觉自己好聪明啊~~)
//alert(arr[0]);// 获取图片格式与编码方式
//alert(arr[1]);// 获取图片Base 64编码字节
~~~
### 程序截图
客户端顶部显示广告信息:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9387b94.jpg)
服务端广告管理界面:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad93a6180.jpg)
服务端修改广告信息界面:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad93c1f0c.jpg)
### 结语
至此,自己的文件上传操作终于完成了,一路坎坷,一路心酸。
自己也曾尝试过使用ng插件ng-file-upload(见参考文献1),但最终还是以失败而告终,真心没有搞明白代码,仿照源代码写就是没有效果,而且布局也不对,自己也是汗颜了。
自己接下来要突破的问题就是分页了,对于刚接触到的知识,往往不明觉厉。
### 参考文献
1.[https://github.com/danialfarid/ng-file-upload](https://github.com/danialfarid/ng-file-upload)
2.[http://www.cnblogs.com/wolf-sun/p/4781673.html](http://www.cnblogs.com/wolf-sun/p/4781673.html)
3.[http://jsfiddle.net/danialfarid/maqbzv15/544/#update](http://jsfiddle.net/danialfarid/maqbzv15/544/#update)
4.[http://www.tuicool.com/articles/jQrQnmf](http://www.tuicool.com/articles/jQrQnmf)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad93e76b5.jpg)
(二十四)AngularJS与单选框及多选框的双向动态绑定
最后更新于:2022-04-01 16:28:04
# AngularJS与单选框及多选框的双向动态绑定
赠人玫瑰,手留余香。若您感觉此篇博文对您有用,请花费2秒时间点个赞,您的鼓励是我不断前进的动力,共勉!
AngularJS 在 <input type="text" /> 中实现双向动态绑定十分简单,如下所示:
<input type="text" ng-model="topic.title" />
只需要用ng-model 与 $scope 中的属性对应,即实现了type=”text” 的双向动态绑定。当 <input type="radio" /> 及 <input type="checkbox" /> 时情况略有不同:
### 1. <inputtype="radio" />
~~~
<input type="radio" name="person-action" value="go_home" ng-model="person.action" />回家
<input type="radio" name="person-action" value="go_to_school" ng-model="person.action" />回学校
~~~
通过 value 属性指定选中状态下对应的值,并通过 ng-model 将单选框与 $scope 中的属性对应,便实现了 type=”radio” 时的双向动态绑定。
### 2. <input type="checkbox" />
~~~
<input type="checkbox" ng-true-value="true" ng-false-value="false" ng-model="phone.play_sound" />铃声
<input type="checkbox" ng-true-value="true" ng-false-value="false" ng-model="phone.play_vibrate" />震动
<input type="checkbox" ng-true-value="true" ng-false-value="false" ng-model="phone.play_lights" />呼吸灯
~~~
通过AngularJS 的内置指令 ng-true-value 和 ng-false-value ,指定多选框在选中和未选中状态下对应的值,再通过ng-model 将其与 $scope 中的属性对应,便实现了type=”checkbox” 的双向动态绑定。
但是理想跟现实总是相差太多,在实际操作过程中还是出现了问题。应该是ng-repeat中scope作用域的问题。
经过一番搜索、调试,自己终于将此问题解决了,效果图如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad931982e.jpg)
### 核心源码
### js
~~~
var str = ""; // 原来存放选中的项
$scope.Selected = false; //默认未选中
var choseArr=[]; // 定义数组用于存放前端显示
$scope.check = function(z,x){
console.log("HUY:");
console.log(z);
console.log("HUYU:");
console.log(x);
if (x == false) { // 选中
str = str + z + ',';
} else {
str = str.replace(z + ',', ''); // 取消选中
}
choseArr = (str.substr(0,str.length-1)).split(',');
console.log("HY:");
console.log(choseArr);
$scope.number_request = choseArr.length; // 前端显示所选数量
$scope.content_request = choseArr; // 前端显示所选请求ID
};
~~~
### Html
~~~
<tr ng-repeat="item in querydata">
<td ng-bind="$index+1">1</td>
<td><a ui-sref="#">{{item.postid}}</a></td>
<td>{{item.medname}}</td>
<td>{{item.medfact}}</td>
<td>{{item.medcnt}}</td>
<td>{{item.remark}}</td>
<td>{{item.tel}}</td>
<td>{{item.post_time}}</td>
<td><input id={{item.postid}} type="checkbox" ng-model="Selected" ng-click="check(item.postid,Selected)" /></td>
</tr>
~~~
参考文献:
[http://www.oschina.net/translate/handling-checkboxes-and-radio-buttons-in-angular-forms](http://www.oschina.net/translate/handling-checkboxes-and-radio-buttons-in-angular-forms)
[http://www.cnblogs.com/CheeseZH/p/4517701.html](http://www.cnblogs.com/CheeseZH/p/4517701.html)
[http://www.bubuko.com/infodetail-954078.html](http://www.bubuko.com/infodetail-954078.html)
(二十三)ANGULAR三宗罪之版本陷阱
最后更新于:2022-04-01 16:28:02
# ANGULAR三宗罪之版本陷阱
坑!碰到个大坑,前面由于绑定日期时将angular版本换为angular-1.3.0-beta.1时,后来午睡后,登录系统,发现无论如何都登陆不进去了,经过调试,发现数据视图已经无法实现双向绑定了。自己还以为又碰到了“僵尸程序”了呢,对比药店端的程序发现并没有什么不同之处。后来自己经过一番思索才隐约感觉到是不是angular的版本造成的,将版本换为之前的1.3.0.14,发现居然神奇般的可以了。自己这才恍然大悟:这就是一个坑啊!按照常理解释的话,angular中MVVM本来就是其一大特色,在这反而成为一个程序猿的陷阱!
(二十一)Angularjs中scope与rootscope区别及联系
最后更新于:2022-04-01 16:28:00
# Angularjs中scope与rootscope区别及联系
scope是html和单个controller之间的桥梁,数据绑定就靠他了。rootscope是各个controller中scope的桥梁。用rootscope定义的值,可以在各个controller中使用。下面用实例详细的说明一下。
1.js代码
~~~
phonecatApp.controller('TestCtrl',['$scope','$rootScope',
function($scope,$rootScope) {
$rootScope.name = 'this is test';
}
]);
phonecatApp.controller('Test111Ctrl',['$scope','$rootScope',
function($scope,$rootScope) {
$scope.name = $rootScope.name;
}
]);
~~~
2.html代码
~~~
<div ng-controller="TestCtrl">
I set the global variable.<strong>{{$root.name}}</strong>
</div>
<div ng-controller="Test111Ctrl">
1,get global variable .<strong>{{name}}</strong><br>
2,get global variable .<strong>{{$root.name}}</strong>
</div>
~~~
3.显示结果
I set the global variable.this is test
1,get global variable .this is test
2,get global variable .this is test
由结果可以看出来,$rootScope.name设置的变量,在所有controller里面都是可以直接用{{$root.name}}来显示的,很强大。那当然也可以赋值给scope.
(十九)在AngularJS应用中集成百度地图实现定位功能
最后更新于:2022-04-01 16:27:58
# 在AngularJS应用中集成百度地图实现定位功能
**[注:请点击此处进行充电!](http://blog.csdn.net/sunhuaqiang1/article/details/50193301#t2)**
### 前言
根据项目需求,需要实现手机定位功能,考虑到百度业务的强大能力,遂决定使用百度地图第三方服务。
添加第三方模块的步骤与前面介绍的“[在AngularJS应用中集成科大讯飞语音输入功能](http://blog.csdn.net/sunhuaqiang1/article/details/50193301#t2)”步骤相同,在此不再赘述。
### 问题
1.有些手机无法实现定位功能(以我的手机为例:MX2,刚开始时可以实现定位,后来就出现无法定位的情况,手机定位功能也已经打开)。
一部分原因是有些手机真的没有打开定位功能。(经过检查手机设置,还真是发现自己将手机定位功能给关闭了,打开手机定位功能后,定位正常)截图如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad92c6c51.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad92d880d.jpg)
经过测试发现了与微信授权类似的问题:在真机测试是没有问题的,打包成APK,然后再在手机上运行则出现无法定位的情况。难道又是因为“真机调试的时候使用的是HBuilder基座的参数”?
但是在别的手机安装APK之后运行结果正常,截图如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad92eadd7.jpg)
2.手机虽然可以实现定位,但是定位速度比较慢。
跟网络有一定的关系。
### 优化
### 源码分析
源代码如下所示:
~~~
<!--百度地图-->
<script src="http://api.map.baidu.com/components?ak=bOwh2i9zIWG7Ucl8xPitV2TM&v=1.0">
</script>
/*
* 获取地理位置信息
*/
$rootScope.getAddr = function() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
//获取位置信息成功
function(position) {
$rootScope.latitude = position.coords.latitude;
$rootScope.longitude = position.coords.longitude;
var myGeo = new BMap.Geocoder();
//根据坐标得到地址描述
$rootScope.getGeo();
},
//获取位置信息失败
function(error) {
switch (error.code) {
case error.PERMISSION_DENIED:
$rootScope.showAlert("请打开设备定位功能!");
break;
case error.POSITION_UNAVAILABLE:
$rootScope.showAlert("定位信息不可用!");
break;
case error.TIMEOUT:
$rootScope.showAlert("定位请求超时!");
break;
case error.UNKNOWN_ERROR:
$rootScope.showAlert("未知错误!");
break;
}
},
{
// 指示浏览器获取高精度的位置,默认为false
enableHighAccuracy: true,
// 指定获取地理位置的超时时间,默认不限时,单位为毫秒
timeout: 5000,
// 最长有效期,在重复获取地理位置时,此参数指定多久再次获取位置。
maximumAge: 3000
});
} else {
$rootScope.showAlert("您的设备不支持GPS定位!");
}
};
$rootScope.getAddr();
$rootScope.getGeo = function() {
var myGeo = new BMap.Geocoder();
// 根据坐标得到地址描述
myGeo.getLocation(new BMap.Point($rootScope.longitude, $rootScope.latitude), function(result) {
if (result) {
console.log(JSON.stringify(result));
$rootScope.geoaddress = {
'fulladdress': result.addressComponents.city + result.addressComponents.district + result.addressComponents.street,
'city': result.addressComponents.city,
'area': result.addressComponents.district,
'street': result.addressComponents.street,
};
console.log(JSON.stringify($rootScope.geoaddress));
}else {
$rootScope.showAlert("定位失败,地址解析失败");
}
});
};
~~~
### 感悟
通过阅读参考资料3,得知上面使用的定位方式是采用的 HTML5 的地理位置功能。
### 注:
总的来说,在PC的浏览器中 HTML5 的地理位置功能获取的位置精度不够高,如果借助这个 HTML5 特性做一个城市天气预报是绰绰有余,但如果是做一个地图应用,那误差还是太大了。不过,如果是移动设备上的 HTML5 应用,可以通过设置 enableHighAcuracy 参数为 true,调用设备的 GPS 定位来获取高精度的地理位置信息。
### 附:
### 手机定位方式汇总
GPS,基站,Wi-Fi等多种定位方式
### 什么是GPS定位、基站定位和Wi-Fi定位?
1、GPS定位:根据设备GPS芯片和GPS卫星实现定位,GPS定位在室内是不可以使用的。GPS定位精度和芯片本身以及实际使用环境有关,一般情况下,GPS定位精度在10m左右。
2、基站定位:根据设备获取的基站信息实现定位,基站定位精度一般不受使用环境影响,主要和基站的覆盖半径有关。百度的基站定位服务精度目前在200m左右。
3、Wi-Fi定位:根据设备获取的Wi-Fi的信息进行定位,Wi-Fi定位精度一般不受使用环境影响,主要和Wi-Fi半径,密度有关。百度的Wi-Fi定位精度目前在20m左右。
### 疑问
如何判断手机的定位方式?
### 附加奖励
额外发现一个问题:当手机出现定位失败的情况,如何处理?移动端在软件逻辑设计上还存在缺陷。
### 参考资料:
1. [http://www.html5plus.org/doc/zh_cn/maps.html](http://www.html5plus.org/doc/zh_cn/maps.html)
2. [http://blog.csdn.net/smok56888/article/details/20628161](http://blog.csdn.net/smok56888/article/details/20628161)
3. [http://www.cnblogs.com/lhb25/archive/2012/07/10/html5-geolocation-api-demo.html](http://www.cnblogs.com/lhb25/archive/2012/07/10/html5-geolocation-api-demo.html)
4. [http://www.cnblogs.com/lhb25/archive/2012/07/06/html5-geolocation-api-demo.html](http://www.cnblogs.com/lhb25/archive/2012/07/06/html5-geolocation-api-demo.html)
5. [http://www.zgxue.com/170/1700801.html](http://www.zgxue.com/170/1700801.html)
6. [http://blog.csdn.net/cyzero/article/details/42584193](http://blog.csdn.net/cyzero/article/details/42584193)
7. [http://blog.csdn.net/zuowensheng/article/details/7800308](http://blog.csdn.net/zuowensheng/article/details/7800308)
8. [http://www.html5plus.org/doc/zh_cn/maps.html#plus.maps.Map.getUserLocation](http://www.html5plus.org/doc/zh_cn/maps.html#plus.maps.Map.getUserLocation)
(十八)在AngularJS应用中集成科大讯飞语音输入功能
最后更新于:2022-04-01 16:27:55
# 在AngularJS应用中集成科大讯飞语音输入功能
**[注:请点击此处进行充电!](http://blog.csdn.net/sunhuaqiang1/article/details/50188605)**
### 前言
根据项目需求,需要在首页搜索框中添加语音输入功能,考虑到科大讯飞语音业务的强大能力,遂决定使用科大讯飞语音输入第三方服务。软件首页截图如下所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad91c67dc.jpg)
涉及的源代码如下所示:
~~~
<button ng-click="startRecognize()">
<i class="icon ion-mic-a " ></i>
</button>
//语音识别
$rootScope.startRecognize = function() {
var speech;
var options = {}; //语音识别参数,用于控制语音引擎的各种技术参数
options.engine = 'iFly';
options.userInterface = 'false';
text = "";
plus.speech.startRecognize(options, function(s) {
text += s;
console.log(text);
text = text.replace(',', '').replace('。', '').replace('?', '');
$scope.$apply(function() {
$rootScope.medname= text;
$scope.searchMed(2, $rootScope.medname)
});
}, function(e) {
$ionicLoading.show({
template: "语音输入失败,请重新尝试"
});
setTimeout(function() {
$ionicLoading.hide();
}, 2000);
});
setTimeout(function() {
plus.speech.stopRecognize();
}, 10000); //超时语音结束
}
~~~
其中涉及到使用ionic框架中的按钮组件。
其云端打包授权功能需要到第三方开发平台申请应用后获取相关配置参数。集成过程与微信授权认证差不多。
### 添加第三方登录模块
### 可视化界面配置
首先是需要添加第三方登录模块,双击应用的manifest.json文件:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad91dee18.jpg)
切换到“模块权限配置”项,在“未选模块”中选择“Speech(语音输入)”添加到“已选模块”:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad920958e.jpg)
### 代码视图配置
切换到“代码视图”项,在permissions节点下添加如下Speech节点数据:
"Speech": {"description": "语音输入"}
效果如下所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9234336.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9267b96.jpg)
(说明:点击“语音输入按钮”后,弹出录音识别界面,在说出“感冒”一词后将识别出的文字填充在输入栏中,同时搜索相关药品,搜索结果如上图右所示。)
### 优化
优化点主要存在两个地方:
1.icon图标过于丑陋
2.将语音输入icon集成进input输入栏,如下图所示(UC Browser):
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9282b7a.jpg)
3.存在版本兼容问题。有些手机不支持此插件。
首先第一个问题属于美工干的活。但自己似乎应该给其预留出应有的填补空间才对。优化后的效果如下图所示(感觉还是很丑):
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad92a6dc1.jpg)
第二个问题,解决起来似乎有一定的难度。自己只能够慢慢摸索。
第三个问题暂时得不到解决。
### 附:button设置图片
~~~
<button style="width:40px; height:38px; white-space: normal; padding:12px; padding-left:20px; background:none; background: url(img/btnbg.png) no-repeat -2px -2px;" ng-click="startRecognize()">
<!--<i class="icon ion-mic-a " ></i>-->
</button>
~~~
### 参考文献:
[http://www.runoob.com/ionic/ionic-icon.html](http://www.runoob.com/ionic/ionic-icon.html)
[http://www.html5plus.org/doc/zh_cn/audio.html](http://www.html5plus.org/doc/zh_cn/audio.html)
[http://www.html5plus.org/doc/zh_cn/speech.html#plus.speech.SpeechRecognizeOption](http://www.html5plus.org/doc/zh_cn/speech.html#plus.speech.SpeechRecognizeOption)
(十七)在AngularJS应用中实现微信认证授权遇到的坑
最后更新于:2022-04-01 16:27:53
# 在AngularJS应用中集成微信认证授权遇到的坑
**[注:请点击此处进行充电!](http://blog.csdn.net/sunhuaqiang1/article/details/50158499)**
### 前言
项目开发过程中,移动端新近增加了一个功能“微信授权登录”,由于自己不是负责移动端开发的,但最后他人负责的部分未达到预期效果。不能准确实现微信授权登录。最后还得靠自己做进一步的优化工作,谁让自己是负责人呢?原来负责人就是负责最后把所有的BUG解决掉。
首先,熟悉一下微信授权部分的源代码,如下所示:
~~~
/*-------------- 微信授权登陆 --------------*/
// 扩展 API 加载完毕后触发“plusready"事件
document.addEventListener("plusready", function() {
// 扩展API加载完毕,现在可以正常调用扩展API
plus.oauth.getServices(function(services) {
// services.length可获取当前运行环境支持授权登录认证服务数目
if (services.length > 0) {
auths = services;
} else {
alert("当前运行环境不支持授权登录认证服务!");
}
}, function(e) {
alert("获取分享服务列表失败:" + e.message + " - " + e.code);
});
}, false);
// 微信授权登录操作
$scope.authLogin = function(){
for(var i = 0; i < auths.length; i++){
console.log(auths[i].description);
if(auths[i].description == "微信"){
var s = auths[i];
break;
}
}
if (!s.authResult) {
console.log("微信尚未授权");
s.login(
//登录认证成功
function(e){
console.log("微信登录认证成功!");
var objuser = s.userInfo;
var uname = objuser.nickname;
console.log(objuser.nickname);
localStorage.uid = uname;
localStorage.logined = "2";
$rootScope.userinfo = {
'logined': "2",
'username': uname
};
console.log(localStorage.logined);
$scope.set_defaultaddr();
//登录后查询订单
$scope.getBillBadge();
if (sessionStorage) {
console.log(sessionStorage.getItem("hisURL"));
if(sessionStorage.getItem("hisURL")=='/tab/med_search')
$rootScope.familyBox();
$location.path(sessionStorage.getItem("hisURL"));
}
},
//登录认证失败
function(e){
alert( "登录认证失败!" );
});
}else{
console.log("已经登录认证!");
}
~~~
授权认证步骤:获取授权登录认证服务——>授权登录认证服务
手机之间在运行同一款软件时由于系统差异也是存在表现差异。如下图所示,上图为红米Android4.4.4版本上的测试结果,下图为魅族5.0.1版本上的测试结果。很明显下图手机不能实现定位功能。
更明显的差异存在于授权部分,调用授权服务时返回的数组内容不同,从下图可明显看出微信与QQ在返回数组中的位置不同。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad91451a4.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad915c437.jpg)
参考文献:[http://www.html5plus.org/doc/zh_cn/oauth.html](http://www.html5plus.org/doc/zh_cn/oauth.html)
[http://ask.dcloud.net.cn/article/192](http://ask.dcloud.net.cn/article/192)
平台支持:
Android - 2.2+ (不支持)
iOS - 5.0+ (不支持)
注:Js中判断两字符串是否相等,使用“==”判断。不能使用equals。
又出现了问题,在手机上调试一切正常,等到打包成APK就出现不能授权(提示登录认证失败)的问题。
alert( "登录认证失败!" + e.message+" - "+e.code);如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9174f9f.jpg)
还是直接在手机测试,出现下面的现象:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9199e81.jpg)
感觉处于一种死循环的状态,但自己也一时找不到可以修改的地方。
### 注:
微信登录配置的参数必须要提交在线打包才能生效(真机调试的时候使用的是HBuilder基座的参数)
折腾了一天,微信授权登录还是未能完成。,头痛....
好吧,我输了。
### 第二天晚上
继续昨天未完的问题。尝试根据返回的错误信息进行修正。
通过查阅资料终于发现问题所在了。授权中配置的参数必须来自微信开放平台申请所得,而非公众平台。那么二者之间又存在什么样的区别呢?接下来继续讲解。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad91b0850.jpg)
### 微信开放平台和公众平台的区别?
简单来讲,微信公众平台是我们常见的公众号,包括订阅号、服务号和企业号,主要用于不具备太强技术开放能力,拥有一定运营能力的品牌、商户、媒体以及个人,作为一个自媒体平台或者服务窗口来用,是面向更广大的人群使用的。
微信开放平台是一个开发者平台,针对的是有较强技术开发能力、能够研发同微信对接的应用开发者来使用的,面向的是技术公司和开发者,不是面向所有人都可以使用的。
因此对于分不清二者区别的人来讲,用公众平台就对了,能用得上开放平台的人肯定都是对开放平台功能有一定了解的人群。
那么,微信开放平台与公众平台注册所得信息通用吗?
答案是NO!因为注册时就不允许使用同一邮箱注册。
(十四)AngularJS灵异代码事件
最后更新于:2022-04-01 16:27:51
# AngularJS灵异代码事件
**[注:请点击此处进行充电!](http://blog.csdn.net/sunhuaqiang1/article/details/50134509)**
### 事情原委
router_sys.js源代码如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad90c3701.jpg)
自己在html路由跳转的代码如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad90dbacd.jpg)
但是在实际路由过程中,却路由到了下面的状态,相应的页面中去。
诡异的是在UC上第一次路由正常,第二次还是路由到下面的状态!路由命名是没有问题的,却执行到别路由中去了。费解!
### 驱除内鬼
内鬼一时还真找不出来。
尝试通过编写点击事件在函数内路由至所需页面,结果还是不可达。
~~~
<a class="btn btn-success btn-sm" id="butAdd" ng-click="doAdd()">新增药店</a>
//路由至新增药店
$scope.doAdd = function(){
alert("SHQ");
$state.go('SHQ');
};
~~~
提示错误如下:
Could not resolve 'SHQ' from state 'shopManag'
把路由中的shop_set_dtl.html页面注释掉,居然还能路由!地址居然还显示!如何是好?
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad90ec8f4.jpg)
这个问题已经超出了自己的能力范围,实在是没有办法!
### 真相大白
呵呵....不要管我,让我哭会!为自己的过错哭会![大哭](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-09_56911dcf36bd4.gif)
原来自己写有3个路由分别为router.js、router_sys.js、router.shop.js,我就纳了闷了,我说怎么该路由死活都不对呢,原来问题就出在第一个路由上。第一个路由中的路由这是自己给自己埋的一颗雷啊!雷区如下:
~~~
//TODO(待考虑)
/*-----------------------药店详情维护------------------------*/
.state('shopDtlManag', {
url: '/shopDtlManag/',
views: { //注意这里的写法,当一个页面上带有多个ui-view的时候如何进行命名和视图模板的加载动作
'': {
templateUrl: 'sys_tpls/rightInfoList.html'
},
'sys_banner@shopDtlManag': {
templateUrl: 'sys_tpls/sys_banner.html'
},
'rightContent@shopDtlManag': {
templateUrl: 'sys_tpls/shop_set_dtl.html'
}
}
})
~~~
这样就不难解释为何会出现以上灵异事件了。
将之替换为如下代码,问题迎刃而解!
~~~
/*---------------------------新增药店-----------------------------*/
.state('shopAdd', {
url: '/shopAdd/',
views: { //注意这里的写法,当一个页面上带有多个ui-view的时候如何进行命名和视图模板的加载动作
'': {
templateUrl: 'sys_tpls/rightInfoList.html'
},
'sys_banner@shopAdd': {
templateUrl: 'sys_tpls/sys_banner.html'
},
'rightContent@shopAdd': {
templateUrl: 'sys_tpls/shop_add.html' // 路由至新增药店页面
}
}
})
~~~
### 亡羊补牢
既然错误已犯,自己就要悔过了。必须得把这可盲雷拆掉!
不过看过代码,感觉这可暗雷不好拆除。当初自己是本着药店端和后台管理端可以分开登录来设计的。
当初的项目需求是实现两个管理端分别进入自己的登录界面,分别为index_sys.html和index_shop.hml。而自己起初是将两者置于一起的,后来为了分离后,应对交易调用错误如何处置的情况,故保留了index.html。
拆雷时,须将index.html与router同时拆除。
其实,经过对比发现router_sys.js与router.shop.js的唯一不同之处在于以下划红线部分代码:
~~~
$stateProvider
.state('index', {
url: '/index',
views: {
'': {
templateUrl: 'sys_tpls/home.html'
},
'sys_login@index': {
templateUrl: 'sys_tpls/sys_login.html'
}
}
})
~~~
经过不断测试,自己必须将这颗暗雷拆除。![生气](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad910ce86.gif)
经过调试,查出暗雷之后,程序运行正常!╰( ̄▽ ̄)╮![哭](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad912661e.gif)
(十)AngularJS改变元素显示状态
最后更新于:2022-04-01 16:27:49
# AngularJS改变元素显示状态
### 前言
本文描述使用AngularJS提供的ng-show和ng-hide指令实现自动监听某布尔型变量来改变元素显示状态。
控制html元素显示和隐藏有n种方法:html的hidden、css的display、jquery的hide()和show()、bootstrap的.hide。今天的重点不是显示和隐藏,而是监听某个布尔变量值,自动改变元素显示和隐藏状态。监听函数、if判断、选择dom、设置dom,5行代码搞不定吧,而且毫无技术含量。
### 实例1
~~~
<body>
<div ng-controller="VisibleController">
<p ng-show="visible">字符串1</p>
<p ng-hide="visible">字符串2</p>
<button ng-click="toggle()">切换</button>
</div>
<script src="../lib/angularjs/1.2.26/angular.min.js"></script>
<script>
function VisibleController($scope) {
$scope.visible = false;
$scope.toggle = function () {
$scope.visible = !$scope.visible;
}
}
</script>
</body>
~~~
两个指令很简单,只是ng-show在true时显示,false时隐藏,而ng-hide效果相反。
对于菜单、上下文敏感的工具以及很多其他情况来说,显示和隐藏元素是一项核心的功能。与Angualr中其他功能一样,Angular是通过修改数据模型的方式来驱动UI刷新,然后通过指令把变更反应到UI上。
ng-show和ng-hide这两条指令的功能是等价的,但是运行效果正好相反,我们都可以根据所传递的表达式来显示或隐藏元素。也就是说,ng-show在表达式为true时将会显示元素,为false时将会隐藏元素;而ng-hide则恰好相反。
### 工作原理
这两条指令的工作原理是:根据实际情况把元素的样式设置为display:block来显示元素;设置为display:none来隐藏元素。
### 实例2
~~~
<body ng-controller='ShowController'>
<button ng-click="toggleMenu()">Toggle Menu</button>
<ul ng-show='menuState.show'>
<li>Stun</li>
<li>Disintegrate</li>
<li>Erase from history</li>
</ul>
<script src="lib/angular/angular.js"></script>
<script>
var myApp=angular.module('myApp',[]) myApp.controller('ShowController',function($scope) {$scope.menuState={show: false},$scope.toggleMenu=function() {$scope.menuState.show=!$scope.menuState.show;}});
</script>
</body>
~~~
(七)实现根据不同条件显示不同控件
最后更新于:2022-04-01 16:27:46
# AngularJS实现根据不同条件显示不同控件
由于项目需求,需要实现根据不同条件显示不同控件的功能。具体要求如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad9089e7d.jpg)
即当选择“每单固定减”时,下方只显示“减免金额”一栏;
当选择“每单固定折扣”时,下方只显示“折扣比例”一栏;
当选择“每单满额减”时,下方只显示“满..减..”两栏。
根据自己对angular的了解,应该可以很轻松的实现此功能。
js设置控件的隐藏与显示,设置控件style的display和visibility属性就可以了。
用JavaScript隐藏控件的方法有两种,分别是通过设置控件的style的“display”和“visibility”属性。
当style.display="block"或style.visibility="visible"时控件可见,当style.display="none"或style.visibility="hidden"时控件不可见。不同的是“display”不但隐藏控件,而且被隐藏的控件不再占用显示时占用的位置,而“visibility”隐藏的控件仅仅是将控件设置成不可见了,控件仍然占俱原来的位置。
执行结果截图如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad90a3c58.jpg)
### 附
部分源码如下:
~~~
function displayHideUI()
{
var ui =document.getElementById("bbs");
ui.style.display="none";
}
function displayShowUI()
{
var ui =document.getElementById("bbs");
ui.style.display="";//display为空的话会好使,为block会使后边的空间换行
}
function visibilityHideUI()
{
var ui =document.getElementById("bbs");
ui.style.visibility="hidden";
}
function visibilityShowUI()
{
var ui =document.getElementById("bbs");
ui.style.visibility="visible";
}
</script>
~~~
值 描述
none 此元素不会被显示。
block 此元素将显示为块级元素,此元素前后会带有换行符。
inline 默认。此元素会被显示为内联元素,元素前后没有换行符。
inline-block 行内块元素。(CSS2.1新增的值)
list-item 此元素会作为列表显示。
run-in 此元素会根据上下文作为块级元素或内联元素显示。
compact CSS 中有值compact,不过由于缺乏广泛支持,已经从CSS2.1 中删除。
marker CSS 中有值marker,不过由于缺乏广泛支持,已经从CSS2.1 中删除。
table 此元素会作为块级表格来显示(类似<table>),表格前后带有换行符。
inline-table 此元素会作为内联表格来显示(类似<table>),表格前后没有换行符。
table-row-group 此元素会作为一个或多个行的分组来显示(类似<tbody>)。
table-header-group 此元素会作为一个或多个行的分组来显示(类似<thead>)。
table-footer-group 此元素会作为一个或多个行的分组来显示(类似<tfoot>)。
table-row 此元素会作为一个表格行显示(类似<tr>)。
table-column-group 此元素会作为一个或多个列的分组来显示(类似<colgroup>)。
table-column 此元素会作为一个单元格列显示(类似<col>)
table-cell 此元素会作为一个表格单元格显示(类似<td>和<th>)
table-caption 此元素会作为一个表格标题显示(类似<caption>)
inherit 规定应该从父元素继承display属性的值。
(六)AngularJS+BootStrap实现弹出对话框
最后更新于:2022-04-01 16:27:44
# AngularJS+BootStrap实现弹出对话框
参考资料:
[http://angular-ui.github.io/bootstrap/#/modal](http://angular-ui.github.io/bootstrap/#/modal)
[https://www.zybuluo.com/bornkiller/note/6023](https://www.zybuluo.com/bornkiller/note/6023)
[http://www.html5jq.com/fe/angular_node/20141127/13.html](http://www.html5jq.com/fe/angular_node/20141127/13.html)
若想要实现对话框弹出效果,可以使用angular的$modal服务。Github上的解释如下:
$modal is a service to quickly create AngularJS-powered modal windows. Creating custom modals is straightforward: create a partial view, its controller and reference them when using the service.
The $modal service has only one method: open(options) where available options are like follows:
templateUrl - a path to a template representing modal's content
template - inline template representing the modal's content
scope - a scope instance to be used for the modal's content (actually the $modal service is going to create a child scope of a provided scope). Defaults to $rootScope
controller - a controller for a modal instance - it can initialize scope used by modal. Accepts the "controller-as" syntax in the form 'SomeCtrl as myctrl'; can be injected with $modalInstance
controllerAs - an alternative to the controller-as syntax, matching the API of directive definitions. Requires the controller option to be provided as well
bindToController - when used with controllerAs & set to true, it will bind the $scope properties onto the controller directly
resolve - members that will be resolved and passed to the controller as locals; it is equivalent of the resolve property for AngularJS routes
animation - set to false to disable animations on new modal/backdrop. Does not toggle animations for modals/backdrops that are already displayed.
backdrop - controls presence of a backdrop. Allowed values: true (default), false (no backdrop), 'static' - backdrop is
present but modal window is not closed when clicking outside of the modal window.
keyboard - indicates whether the dialog should be closable by hitting the ESC key, defaults to true
backdropClass - additional CSS class(es) to be added to a modal backdrop template
windowClass - additional CSS class(es) to be added to a modal window template
windowTemplateUrl - a path to a template overriding modal's window template
size - optional suffix of modal window class. The value used is appended to the modal- class, i.e. a value of sm gives modal-sm
openedClass - class added to the body element when the modal is opened. Defaults to modal-open
Global defaults may be set for $modal via $modalProvider.options.
The open method returns a modal instance, an object with the following properties:
close(result) - a method that can be used to close a modal, passing a result
dismiss(reason) - a method that can be used to dismiss a modal, passing a reason
result - a promise that is resolved when a modal is closed and rejected when a modal is dismissed
opened - a promise that is resolved when a modal gets opened after downloading content's template and resolving all variables
rendered - a promise that is resolved when a modal is rendered.
In addition the scope associated with modal's content is augmented with 2 methods:
$close(result)
$dismiss(reason)
Those methods make it easy to close a modal window without a need to create a dedicated controller.
If the $scope is destroyed via unexpected mechanism, such as it being passed in the modal options and a $route/$state transition occurs,
the modal will be dismissed with the value $uibUnscheduledDestruction.
Finally, a modal.closing event is broadcast to the modal scope before the modal closes. If the listener calls preventDefault on the event,
then the modal will remain open. The $close and $dismiss methods return true if the event was allowed.
The event itself includes a parameter for the result/reason and a boolean parameter that indicates whether the modal is being closed (true) or dismissed.
译文如下:
$modal是一个可以迅速创建模态窗口的服务,创建部分页,控制器,并关联他们。
$modal仅有一个方法open(options),可以使用的选项如下:
templateUrl:模态窗口的地址
template:用于显示html标签
scope:一个作用域为模态的内容使用(事实上,$modal会创建一个当前作用域的子作用域)默认为$rootScope
controller:为$modal指定的控制器,初始化$scope,该控制器可用$modalInstance注入
resolve:定义一个成员并将他传递给$modal指定的控制器,相当于routes的一个reslove属性,如果需要传递一个objec对象,需要使用angular.copy()
backdrop:控制背景,允许的值:true(默认),false(无背景),“static” - 背景是存在的,但点击模态窗口之外时,模态窗口不关闭
keyboard:当按下Esc时,模态对话框是否关闭,默认为ture
windowClass:指定一个class并被添加到模态窗口中
open方法返回一个模态实例,该实例有如下属性
close(result):关闭模态窗口并传递一个结果
dismiss(reason):撤销模态方法并传递一个原因
result:一个契约,当模态窗口被关闭或撤销时传递
opened:一个契约,当模态窗口打开并且加载完内容时传递的变量
另外,$modalInstance扩展了两个方法$close(result)、$dismiss(reason),这些方法很容易关闭窗口并且不需要额外的控制器
实战:
在app.js中需要加入依赖ui.bootstrap,需要在index.html中引入ui-bootstrap-tpls-0.7.0.js。
以下为html代码:
~~~
<div ng-controller="ModalDemoCtrl">
~~~
~~~
<span style="white-space:pre"> </span><script type="text/ng-template" id="myModalContent.html">
~~~
~~~
<span style="white-space:pre"> </span><div class="modal-header">
~~~
~~~
<span style="white-space:pre"> </span><h3 class="modal-title">I'm a modal!</h3>
~~~
~~~
<span style="white-space:pre"> </span></div>
~~~
~~~
<span style="white-space:pre"> </span><div class="modal-body">
~~~
~~~
<span style="white-space:pre"> </span><ul>
~~~
~~~
<span style="white-space:pre"> </span> <li ng-repeat="item in items">
~~~
~~~
<span style="white-space:pre"> </span> <a href="#" ng-click="$event.preventDefault(); selected.item = item">{{ item }}</a>
~~~
~~~
</li>
~~~
~~~
</ul>
~~~
~~~
Selected: <b>{{ selected.item }}</b>
~~~
~~~
</div>
~~~
~~~
<div class="modal-footer">
~~~
~~~
<button class="btn btn-primary" type="button" ng-click="ok()">OK</button>
~~~
~~~
<button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>
~~~
~~~
</div>
~~~
~~~
</script>
~~~
~~~
<button type="button" class="btn btn-default" ng-click="open()">Open me!</button>
~~~
~~~
<button type="button" class="btn btn-default" ng-click="open('lg')">Large modal</button>
~~~
~~~
<button type="button" class="btn btn-default" ng-click="open('sm')">Small modal</button>
~~~
~~~
<button type="button" class="btn btn-default" ng-click="toggleAnimation()">Toggle Animation ({{ animationsEnabled }})</button>
~~~
~~~
<div ng-show="selected">Selection from a modal: {{ selected }}</div></div>
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope, $modal, $log) {
~~~
~~~
$scope.items = ['item1', 'item2', 'item3'];
~~~
~~~
$scope.animationsEnabled = true;
~~~
~~~
$scope.open = function (size) {
~~~
~~~
var modalInstance = $modal.open({
~~~
~~~
animation: $scope.animationsEnabled,
~~~
~~~
templateUrl: 'myModalContent.html',
~~~
~~~
controller: 'ModalInstanceCtrl',
~~~
~~~
size: size,
~~~
~~~
resolve: {
~~~
~~~
items: function () {
~~~
~~~
return $scope.items;
~~~
~~~
}
~~~
~~~
}
~~~
~~~
});
~~~
以下为JS代码:
~~~
modalInstance.result.then(function (selectedItem) {
~~~
~~~
$scope.selected = selectedItem; },
~~~
~~~
function () {
~~~
~~~
$log.info('Modal dismissed at: ' + new Date()); }); };
~~~
~~~
$scope.toggleAnimation = function () {
~~~
~~~
$scope.animationsEnabled = !$scope.animationsEnabled; }; });
~~~
~~~
// Please note that $modalInstance represents a modal window (instance) dependency.
~~~
~~~
// It is not the same as the $modal service used above.
~~~
~~~
angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($scope, $modalInstance, items) {
~~~
~~~
$scope.items = items;
~~~
~~~
$scope.selected = {
~~~
~~~
item: $scope.items[0] };
~~~
~~~
$scope.ok = function () {
~~~
~~~
$modalInstance.close($scope.selected.item); };
~~~
~~~
$scope.cancel = function () { $modalInstance.dismiss('cancel');
~~~
~~~
};});
~~~
出现如下错误:
Modal dismissed at: Mon Sep 14 2015 18:53:33 GMT+0800 (中国标准时间)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad90467dc.jpg)
也就是说bootstrap.min.css、ui-bootstrap-tpls-0.13.4.js、angular.js要保持一定的版本关系。
在将ui-bootstrap-tpls的版本改为0.13.4之后,又出现如下错误提示:
Error: [$injector:unpr] Unknown provider: $templateRequestProvider <- $templateRequest <- $modal
如果是因为版本冲突的原因,自己就尝试着更换ui-bootstrap-tpls的版本,结果当试到ui-bootstrap-tpls-0.9.0.js时,发现问题解决了。截图如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-02_56d6ad90650ac.jpg)
在热心网友破狼的大力支持下,问题终于解决了,在此表示深深的谢意。