
打包的ipa在APP Store审核过程中因定位被退回的解决方法
iOS应用如果需要用到定位,正常情况下
plus.geolocation.getCurrentPosition((data)=>{},(error)=>{})
即可,这时会弹出提示框给用户选择是否允许使用定位功能。
但关键的地方就是,现在审核标准需要在APP里面说明为什么要获取定位,
因此就要在manifest.json里面的代码视图添加相关代码:
"plus": {
"distribute": {
"apple": {
"plistcmds": [
"Set :NSLocationAlwaysUsageDescription 我是经常要使用定位的原因描述",
"Set :NSLocationWhenInUseUsageDescription 我是需要使用定位的原因描述"
]
}
}
}
iOS应用如果需要用到定位,正常情况下
plus.geolocation.getCurrentPosition((data)=>{},(error)=>{})
即可,这时会弹出提示框给用户选择是否允许使用定位功能。
但关键的地方就是,现在审核标准需要在APP里面说明为什么要获取定位,
因此就要在manifest.json里面的代码视图添加相关代码:
"plus": {
"distribute": {
"apple": {
"plistcmds": [
"Set :NSLocationAlwaysUsageDescription 我是经常要使用定位的原因描述",
"Set :NSLocationWhenInUseUsageDescription 我是需要使用定位的原因描述"
]
}
}
}
收起阅读 »

【分享】5+App的中View
5+App 中的 View 大概可以分为:
- DOM 也就是 HTML 的内容
- Webview 做为 HTML 的容器
- NView 原生 View
- Map、Video 等原生的控件
- NativeUI 系统原生界面
层级关系
默认的层级关系 DOM < Map = Webview < NView < NativeUI
- DOM 的层级是最低的,因此经常出现某些 HTML 的内容被其它更高层级 View 遮挡的情况。
- Map = Webview 其实不够严谨。原生控件创建后,会与当前 Webview 建立关联关系,可以简单理解为层级一致。
- Webview < NView 是默认的情况,如果 NView 被 append 到 Webview 的话,NView 的层级则会跟随父 Webview。
- NativeUI 系统原生界面的层级是最高的
下面通过一些示例,来验证一下这些层级关系。
示例
这里要先提一句,一个新的 Webview 创建并且显示,默认都会置于栈顶,也就是说会在当前所有 Webview 的最上层。
地图
- NativeUI 弹出框在 Webview 与 Map 上层
- 新的Webview 新开一个 Webview 会遮挡包含 Map 的 Webview。

NView
- NView 默认情况下,层级是高于所有 Webview 的。
- 不append 此时点击“新开窗口”或“返回”,会一直看到 NView 的存在。
- append 此时 NView 作为 Webview 的一部分存在,层级与父 Webview 一致,点击“新开窗口”或“返回”不会再看到 NView 的存在。
- NativeUI 弹出框始终会在 NView 上层
源码
示例的具体代码,见附件。
5+App 中的 View 大概可以分为:
- DOM 也就是 HTML 的内容
- Webview 做为 HTML 的容器
- NView 原生 View
- Map、Video 等原生的控件
- NativeUI 系统原生界面
层级关系
默认的层级关系 DOM < Map = Webview < NView < NativeUI
- DOM 的层级是最低的,因此经常出现某些 HTML 的内容被其它更高层级 View 遮挡的情况。
- Map = Webview 其实不够严谨。原生控件创建后,会与当前 Webview 建立关联关系,可以简单理解为层级一致。
- Webview < NView 是默认的情况,如果 NView 被 append 到 Webview 的话,NView 的层级则会跟随父 Webview。
- NativeUI 系统原生界面的层级是最高的
下面通过一些示例,来验证一下这些层级关系。
示例
这里要先提一句,一个新的 Webview 创建并且显示,默认都会置于栈顶,也就是说会在当前所有 Webview 的最上层。
地图
- NativeUI 弹出框在 Webview 与 Map 上层
- 新的Webview 新开一个 Webview 会遮挡包含 Map 的 Webview。
NView
- NView 默认情况下,层级是高于所有 Webview 的。
- 不append 此时点击“新开窗口”或“返回”,会一直看到 NView 的存在。
- append 此时 NView 作为 Webview 的一部分存在,层级与父 Webview 一致,点击“新开窗口”或“返回”不会再看到 NView 的存在。
- NativeUI 弹出框始终会在 NView 上层
源码
示例的具体代码,见附件。
收起阅读 »
【5+】Webview页面之间的数据交流
一个App,其中大部分是要对页面之间的数据进行交互。
碧如:A打开B页面,B页面执行一些代码,再通知回A页面。
这可能是h5+er们遇到最常见的一个场景了。
ok,我们将问题实例化:
A页面有个选择地区的按钮,需要打开B页面选择一个地区,然后获取到选取结果返回给A页面并展示。
我们看看用mui.fire怎么来实现这个功能
A页面
<header class="mui-bar mui-bar-nav">
<h1 class="mui-title">A</h1>
</header>
<div class="mui-content">
<input type="text" readonly placeholder="未选择">
<button type="button" class="mui-btn mui-btn-blue">选取地区</button>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript">
mui.init();
// 自定义监听select事件
document.addEventListener('select', function(e){
var text = e.detail.text;
document.querySelector("input").value = text;
});
// 按钮点击事件
document.querySelector(".mui-btn-blue").addEventListener('tap', function(){
// 打开B页面,选取一个结果
mui.openWindow('B.html');
});
</script>
B页面
<header class="mui-bar mui-bar-nav">
<a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
<h1 class="mui-title">B</h1>
</header>
<div class="mui-content">
<ul class="mui-table-view">
<li class="mui-table-view-cell">
<a class="mui-navigate-right">
上海
</a>
</li>
<li class="mui-table-view-cell">
<a class="mui-navigate-right">
深圳
</a>
</li>
<li class="mui-table-view-cell">
<a class="mui-navigate-right">
北京
</a>
</li>
</ul>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript">
mui.init();
mui('ul').on('tap', 'li', function() {
// 获取当前选择的内容
var text = this.innerText;
// 通知上个页面
var w = plus.webview.currentWebview();
var opener = w.opener();
mui.fire(opener, "select",{
text: text
});
// 关闭本页面
w.close();
});
真机调试一下,o98k。
但是!我个人还是建议脱离mui.js来实现这个功能
可以借用咱们之前文章里面的讲过的,利用webview对象的evalJS方法
【5+】跨webview多页面 触发事件(一)
【5+】跨webview多页面 触发事件(一)
感觉用Broadcast.js有点小题大做
那咱们就写一个类似Android中的onActivityResult和setResult方法
新建一个app.js,作为一个自己的插件,里面实现两个方法 onActivityResult 和 setResult
(function(app){
/**
* 打开一个页面
* @param {String} url 页面路径
* @param {String} id 页面id
* @param {Object} ex 参数
* @param {Function} callback
*/
app.onActivityResult = function(url, id, ex, callback){
};
/**
* 返回创建者页面数据
* @param {Object} data 需要返回的数据
* @return {Webview} w 当前webview
*/
app.setResult = function(data){
};
}(window.app || (window.app = {})));
我们一步步来,先看看setResult如何触发上个页面的函数
/**
* 返回创建者页面数据
* @param {Object} data 需要返回的数据
* @return {Webview} w 当前webview
*/
app.setResult = function(data){
// 获取当前webview
var indexW = plus.webview.currentWebview();
// 获取创建者的webview
var opener = indexW.opener();
// 执行js字符串
opener.evalJS();// ??????
};
卧槽,那么,问题来了,evalJS该执行什么呢?
如果我在A页面的window对象下定一个函数
window.test = function(data){
alert(JSON.stringify(data));
}
那么,我们在evalJS里面就该这么写
// 执行js字符串
var jsstr = "window.test && window.test(" + JSON.stringify(data) + ")";
opener.evalJS(jsstr);
好吧,考虑到一个页面可能通过这个方式打开多个页面,那么我们这个test函数就得改一个不重复唯一的名称,并且定义放到onActivityResult方法里面
var _id = 0,
_tempName = '',
ow,cw;
/**
* 打开一个页面
* @param {String} url 页面路径
* @param {String} id 页面id
* @param {Object} ex 参数
* @param {Function} callback
*/
app.onActivityResult = function(url, id, ex, callback) {
// 生成唯一回调函数名称
_tempName = 'APP_RESULT_FUN_' + _id++;
// 定义函数
window[_tempName] = function(data){
// 执行自定义回调
callback(data);
};
// 传递函数名称到目标页面
ex.callbackName = _tempName;
// 显示菊花
cw = plus.nativeUI.showWaiting();
// 创建目标页面
ow = plus.webview.create(url, id, {
render: "always"
}, ex);
// title更新时显示 页面
ow.addEventListener('titleUpdate', function(){
// 关闭菊花
cw && (cw.close(),cw = null);
// 显示页面
ow.show('pop-in');
});
// 页面关闭时,注销window下此次事件
ow.addEventListener('close', function(){
setTimeout(function(){
window[_tempName] = null;
});
});
};
生成特殊一个函数,并把函数名通过extras的方式传参到目标页面,
相应的,setResult方法也需要少许更改
/**
* 返回创建者页面数据
* @param {Object} data 需要返回的数据
* @return {Webview} w 当前webview
*/
app.setResult = function(data) {
// 获取当前webview
var indexW = plus.webview.currentWebview();
// js字符串
var jsstr = "";
// 如果存在自定义回调函数名
if(indexW.callbackName){
// 拼接js字符串
jsstr = "window." + indexW.callbackName;
jsstr = jsstr + "&&" + jsstr + "(" + JSON.stringify(data) + ")";
// 执行
indexW.opener().evalJS(jsstr);
}
// 返回当前页面
return indexW;
};
试试引用后在AB页面测试一下
// A页面 按钮点击事件
document.querySelector(".mui-btn-blue").addEventListener('tap', function(){
// 打开B页面,选取一个结果
app.onActivityResult('B.html', 'B', {}, function(data){
// 修改内容
document.querySelector("input").value = data.text;
});
});
// B页面 选项点击事件
mui('ul').on('tap', 'li', function() {
// 获取当前选择的内容
var text = this.innerText;
// 通知上个页面 并关闭本页面
app.setResult({
text: text
}).close();
});
卧槽666。
class Man{
constructor(){
this.name = 'newsning'
}
say(){
console.log('天行健, 君子以自强不息. ')
}
}
一个App,其中大部分是要对页面之间的数据进行交互。
碧如:A打开B页面,B页面执行一些代码,再通知回A页面。
这可能是h5+er们遇到最常见的一个场景了。
ok,我们将问题实例化:
A页面有个选择地区的按钮,需要打开B页面选择一个地区,然后获取到选取结果返回给A页面并展示。
我们看看用mui.fire怎么来实现这个功能
A页面
<header class="mui-bar mui-bar-nav">
<h1 class="mui-title">A</h1>
</header>
<div class="mui-content">
<input type="text" readonly placeholder="未选择">
<button type="button" class="mui-btn mui-btn-blue">选取地区</button>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript">
mui.init();
// 自定义监听select事件
document.addEventListener('select', function(e){
var text = e.detail.text;
document.querySelector("input").value = text;
});
// 按钮点击事件
document.querySelector(".mui-btn-blue").addEventListener('tap', function(){
// 打开B页面,选取一个结果
mui.openWindow('B.html');
});
</script>
B页面
<header class="mui-bar mui-bar-nav">
<a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
<h1 class="mui-title">B</h1>
</header>
<div class="mui-content">
<ul class="mui-table-view">
<li class="mui-table-view-cell">
<a class="mui-navigate-right">
上海
</a>
</li>
<li class="mui-table-view-cell">
<a class="mui-navigate-right">
深圳
</a>
</li>
<li class="mui-table-view-cell">
<a class="mui-navigate-right">
北京
</a>
</li>
</ul>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript">
mui.init();
mui('ul').on('tap', 'li', function() {
// 获取当前选择的内容
var text = this.innerText;
// 通知上个页面
var w = plus.webview.currentWebview();
var opener = w.opener();
mui.fire(opener, "select",{
text: text
});
// 关闭本页面
w.close();
});
真机调试一下,o98k。
但是!我个人还是建议脱离mui.js来实现这个功能
可以借用咱们之前文章里面的讲过的,利用webview对象的evalJS方法
【5+】跨webview多页面 触发事件(一)
【5+】跨webview多页面 触发事件(一)
感觉用Broadcast.js有点小题大做
那咱们就写一个类似Android中的onActivityResult和setResult方法
新建一个app.js,作为一个自己的插件,里面实现两个方法 onActivityResult 和 setResult
(function(app){
/**
* 打开一个页面
* @param {String} url 页面路径
* @param {String} id 页面id
* @param {Object} ex 参数
* @param {Function} callback
*/
app.onActivityResult = function(url, id, ex, callback){
};
/**
* 返回创建者页面数据
* @param {Object} data 需要返回的数据
* @return {Webview} w 当前webview
*/
app.setResult = function(data){
};
}(window.app || (window.app = {})));
我们一步步来,先看看setResult如何触发上个页面的函数
/**
* 返回创建者页面数据
* @param {Object} data 需要返回的数据
* @return {Webview} w 当前webview
*/
app.setResult = function(data){
// 获取当前webview
var indexW = plus.webview.currentWebview();
// 获取创建者的webview
var opener = indexW.opener();
// 执行js字符串
opener.evalJS();// ??????
};
卧槽,那么,问题来了,evalJS该执行什么呢?
如果我在A页面的window对象下定一个函数
window.test = function(data){
alert(JSON.stringify(data));
}
那么,我们在evalJS里面就该这么写
// 执行js字符串
var jsstr = "window.test && window.test(" + JSON.stringify(data) + ")";
opener.evalJS(jsstr);
好吧,考虑到一个页面可能通过这个方式打开多个页面,那么我们这个test函数就得改一个不重复唯一的名称,并且定义放到onActivityResult方法里面
var _id = 0,
_tempName = '',
ow,cw;
/**
* 打开一个页面
* @param {String} url 页面路径
* @param {String} id 页面id
* @param {Object} ex 参数
* @param {Function} callback
*/
app.onActivityResult = function(url, id, ex, callback) {
// 生成唯一回调函数名称
_tempName = 'APP_RESULT_FUN_' + _id++;
// 定义函数
window[_tempName] = function(data){
// 执行自定义回调
callback(data);
};
// 传递函数名称到目标页面
ex.callbackName = _tempName;
// 显示菊花
cw = plus.nativeUI.showWaiting();
// 创建目标页面
ow = plus.webview.create(url, id, {
render: "always"
}, ex);
// title更新时显示 页面
ow.addEventListener('titleUpdate', function(){
// 关闭菊花
cw && (cw.close(),cw = null);
// 显示页面
ow.show('pop-in');
});
// 页面关闭时,注销window下此次事件
ow.addEventListener('close', function(){
setTimeout(function(){
window[_tempName] = null;
});
});
};
生成特殊一个函数,并把函数名通过extras的方式传参到目标页面,
相应的,setResult方法也需要少许更改
/**
* 返回创建者页面数据
* @param {Object} data 需要返回的数据
* @return {Webview} w 当前webview
*/
app.setResult = function(data) {
// 获取当前webview
var indexW = plus.webview.currentWebview();
// js字符串
var jsstr = "";
// 如果存在自定义回调函数名
if(indexW.callbackName){
// 拼接js字符串
jsstr = "window." + indexW.callbackName;
jsstr = jsstr + "&&" + jsstr + "(" + JSON.stringify(data) + ")";
// 执行
indexW.opener().evalJS(jsstr);
}
// 返回当前页面
return indexW;
};
试试引用后在AB页面测试一下
// A页面 按钮点击事件
document.querySelector(".mui-btn-blue").addEventListener('tap', function(){
// 打开B页面,选取一个结果
app.onActivityResult('B.html', 'B', {}, function(data){
// 修改内容
document.querySelector("input").value = data.text;
});
});
// B页面 选项点击事件
mui('ul').on('tap', 'li', function() {
// 获取当前选择的内容
var text = this.innerText;
// 通知上个页面 并关闭本页面
app.setResult({
text: text
}).close();
});
卧槽666。
class Man{
constructor(){
this.name = 'newsning'
}
say(){
console.log('天行健, 君子以自强不息. ')
}
}
收起阅读 »

点击li跳转时总跳转至第一个li的页面。而alert显示的是正确的innertext
var obj_lis = document.getElementById("my_list_movie").getElementsByTagName("li");
for(i = 0; i < obj_lis.length; i++) {
obj_lis[i].onclick = function() {
if(this.innerHTML.indexOf("电影票订单")) {
window.location.href = "ticket_order.html";
alert(this.innerHTML);
} else if(this.innerHTML.indexOf("代金优惠卷")) {
window.location.href = "coupons.html";
alert(this.innerHTML);
} else if(this.innerHTML.indexOf("收藏的电影")) {
window.location.href = "favorite_movie.html";
alert(this.innerHTML);
}
}
}
var obj_lis = document.getElementById("my_list_movie").getElementsByTagName("li");
for(i = 0; i < obj_lis.length; i++) {
obj_lis[i].onclick = function() {
if(this.innerHTML.indexOf("电影票订单")) {
window.location.href = "ticket_order.html";
alert(this.innerHTML);
} else if(this.innerHTML.indexOf("代金优惠卷")) {
window.location.href = "coupons.html";
alert(this.innerHTML);
} else if(this.innerHTML.indexOf("收藏的电影")) {
window.location.href = "favorite_movie.html";
alert(this.innerHTML);
}
}
}
收起阅读 »

vue2.x引入mui的开源项目源码+案例公开,没有过多的业务逻辑,刚写的项目,希望有好的commit提交过来整理好项目
项目地址:https://github.com/wuhou123/mui-vue2
下载app可以查看我的-我的足迹用到h5+和原生定位功能
也有关于mui常见问题文档
如果有问题提issues吧
项目地址:https://github.com/wuhou123/mui-vue2
下载app可以查看我的-我的足迹用到h5+和原生定位功能
也有关于mui常见问题文档
如果有问题提issues吧

css常用知识点
解决img标签与p标签之间有空隙的问题
1.将img设置为block: img{display:block}
- 设置img的竖直对其方式:vertical-align: bottom;
- 定义容器里的字体大小为0。
div{
width:110px;
border:1px solid #000000;
font-size:0px;
}
css实现图片元素水平垂直居中
样式//style .outer{ width: 500px; height: 200px; line-height: 200px; text-align: center; border: green solid 5px; } .inner{ display: inline-block; vertical-algin: middle; }
html
<div class='outer'> <img src="https://www.baidu.com/img/baidu_jgylogo3.gif"> </div>
.one {
position:absolute;
width200px;
height:200px;
top:50%;
left:50%;
margin-top:-100px;
margin-left:-100px;
background:red;
}
.two{
position:fixed;
width:180px;
height:180px;
top:50%;
left:50%;
margin-top:-90px;
margin-left:-90px;
background:orange;
}
.three{
position:fixed; width:160px; height:160px; top:0; right:0; bottom:0; left:0; margin:auto; background:pink;
}
.four{ position:absolute; width:140px; height:140px; top:0; right:0; bottom:0; left:0; margin:auto; background:black;}
css实现单行、多行文本溢出显示省略号
单行文本的移除显示省略号用text-overflow:ellipsis属性,还需要加宽度width属性来兼容部分浏览器。
实现方法:
overflow:hidden;
white-spacen:nowrap;
text-overflow:ellipsis;
1.使用overflow:hidden把超出的内容进行隐藏;
- 然后使用white-space:nowrap设置内容不换行;
- 最后使用text-overflow:ellipsis设置超出内容为省略号
但是这个属性只支持单行文本的溢出显示省略号。
实现多行文本溢出显示省略号,如下。
display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:2;
overflow:hidden;
因为使用了webkit的css扩展属性,该方法适用于webkit浏览器及移动端;
注:
1.-webkit-line-clamp用来限制在一个块元素显示的文本的行数。为了实现该效果,它需要组合其他的webkit属性。常见结合属性:
- display:-webkit-box;必须结合的属性,将对象作为弹性伸缩盒子模型显示。
- -webkit-box-orient必须结合的属性,设置或检索伸缩盒对象的子元素的排列方式。
实现方法:p{position:relative;line-height:20px;max-height:40px;overflow:hidden;} p::after{content:"...";position:absolute;bottom:0;right:0;padding-left:40px; background: line-gradient(to right,transparent,#fff 55%); background: -webkit-linear-gradient(left, transparent, #fff 55%); background: -o-linear-gradient(right, transparent, #fff 55%); background: -moz-linear-gradient(right, transparent, #fff 55%); }
该方法使用范围广,但文字未超出行的情况下也会出现省略号,可结合js优化该方法。
注:
1.将height设置为line-height的整倍数,防止超出的文字露出。 - 给p::after添加背景可避免文字只显示一半。
3.由于ie6-7不显示content内容,所以要添加标签兼容ie6-7(如:<span>…<span/>);兼容ie8需要将::after替换成:after
css3中的transform对行内元素(inline)无效,查资料后发现,transform适用于:所有块级元素及某些内联元素。
相关链接:http://www.css88.com/book/css/properties/transform/transform.htm
解决img标签与p标签之间有空隙的问题
1.将img设置为block: img{display:block}
- 设置img的竖直对其方式:vertical-align: bottom;
- 定义容器里的字体大小为0。
div{
width:110px;
border:1px solid #000000;
font-size:0px;
}
css实现图片元素水平垂直居中
样式//style .outer{ width: 500px; height: 200px; line-height: 200px; text-align: center; border: green solid 5px; } .inner{ display: inline-block; vertical-algin: middle; }
html
<div class='outer'> <img src="https://www.baidu.com/img/baidu_jgylogo3.gif"> </div>
.one {
position:absolute;
width200px;
height:200px;
top:50%;
left:50%;
margin-top:-100px;
margin-left:-100px;
background:red;
}
.two{
position:fixed;
width:180px;
height:180px;
top:50%;
left:50%;
margin-top:-90px;
margin-left:-90px;
background:orange;
}
.three{
position:fixed; width:160px; height:160px; top:0; right:0; bottom:0; left:0; margin:auto; background:pink;
}
.four{ position:absolute; width:140px; height:140px; top:0; right:0; bottom:0; left:0; margin:auto; background:black;}
css实现单行、多行文本溢出显示省略号
单行文本的移除显示省略号用text-overflow:ellipsis属性,还需要加宽度width属性来兼容部分浏览器。
实现方法:
overflow:hidden;
white-spacen:nowrap;
text-overflow:ellipsis;
1.使用overflow:hidden把超出的内容进行隐藏;
- 然后使用white-space:nowrap设置内容不换行;
- 最后使用text-overflow:ellipsis设置超出内容为省略号
但是这个属性只支持单行文本的溢出显示省略号。
实现多行文本溢出显示省略号,如下。
display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:2;
overflow:hidden;
因为使用了webkit的css扩展属性,该方法适用于webkit浏览器及移动端;
注:
1.-webkit-line-clamp用来限制在一个块元素显示的文本的行数。为了实现该效果,它需要组合其他的webkit属性。常见结合属性:
- display:-webkit-box;必须结合的属性,将对象作为弹性伸缩盒子模型显示。
- -webkit-box-orient必须结合的属性,设置或检索伸缩盒对象的子元素的排列方式。
实现方法:p{position:relative;line-height:20px;max-height:40px;overflow:hidden;} p::after{content:"...";position:absolute;bottom:0;right:0;padding-left:40px; background: line-gradient(to right,transparent,#fff 55%); background: -webkit-linear-gradient(left, transparent, #fff 55%); background: -o-linear-gradient(right, transparent, #fff 55%); background: -moz-linear-gradient(right, transparent, #fff 55%); }
该方法使用范围广,但文字未超出行的情况下也会出现省略号,可结合js优化该方法。
注:
1.将height设置为line-height的整倍数,防止超出的文字露出。 - 给p::after添加背景可避免文字只显示一半。
3.由于ie6-7不显示content内容,所以要添加标签兼容ie6-7(如:<span>…<span/>);兼容ie8需要将::after替换成:after
css3中的transform对行内元素(inline)无效,查资料后发现,transform适用于:所有块级元素及某些内联元素。
相关链接:http://www.css88.com/book/css/properties/transform/transform.htm

cookie和session有什么区别?
1.由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识别具体的用户,这个机制就是session。典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的session,用于标识这个用户,并且跟踪用户,这样才知道购物车里有几本书这个session是保存在服务端的,有一个唯一标识。在服务端保存session的方法很多,内存、数据库、文件都有。集群的时候也要考虑session的转移,在大型的网站,一般会有专门的session服务器集群,用来保存用户会话,这个时候session信息都是放在内存的,使用一些缓存服务比如Mecached之类的来放session。
- 服务端是如何识别特定的客户的?这个时候cookie就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用Cookie来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在Cookie里面记录一个Seeion ID,以后每次请求都会把这个会话ID发送到服务器,我就知道你是谁了。有人问,如果客户端的浏览器禁用了Cookie怎么办?一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被加上一个诸如sid=XXX这样的参数,服务端据此来识别用户。
- cookie信息可以写到cookie里面,访问网站的时候,网站页面的脚本客户已读取这个信息,就自动帮你把用户名填了,方便用户
session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存咋集群、数据库、文件中;
cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是是实现session的一种方式。
不要混淆session和session实现。
本来session是一个抽象的概念,开发者为了实现中断和继续等操作,将user agent和server之间一对一的交互,抽象为“会话”,进而衍生出“会话状态”,也就是session的概念。
而cookie是一个实际存在的东西,http协议中定义在header中的字段。可以认为是session的一种后端无状态实现。
而我们今天常说的“session”,是为了绕开cookie的各种限制,通常借助cookie本身和后端存储实现的,一种更高级的会话状态实现。
所以cookie和session,你可以认为是同一层次的概念,也可以认为是不同层次的概念。具体到实现,session因为session id的存在,通常要借助cookie实现,但这并非必要,只能说是通用性较好的一种实现方案。
1.session在服务端,cookie在客户端(浏览器)
- session默认被存在服务器的一个文件里(不是内存)
- session的运行依赖session id,而session id是存在cookie中的,也就是说如果浏览器禁用了cookie,同时session也会失效(可以通过其它方式实现,如在url中传递session_id)
- session可以放在文件、数据库、或内存中的都可以。
- 用户验证这种场合一般都会用session
因此,维持一个会话的核心就是客户端的唯一标识,即session_id
1.由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识别具体的用户,这个机制就是session。典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的session,用于标识这个用户,并且跟踪用户,这样才知道购物车里有几本书这个session是保存在服务端的,有一个唯一标识。在服务端保存session的方法很多,内存、数据库、文件都有。集群的时候也要考虑session的转移,在大型的网站,一般会有专门的session服务器集群,用来保存用户会话,这个时候session信息都是放在内存的,使用一些缓存服务比如Mecached之类的来放session。
- 服务端是如何识别特定的客户的?这个时候cookie就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用Cookie来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在Cookie里面记录一个Seeion ID,以后每次请求都会把这个会话ID发送到服务器,我就知道你是谁了。有人问,如果客户端的浏览器禁用了Cookie怎么办?一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被加上一个诸如sid=XXX这样的参数,服务端据此来识别用户。
- cookie信息可以写到cookie里面,访问网站的时候,网站页面的脚本客户已读取这个信息,就自动帮你把用户名填了,方便用户
session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存咋集群、数据库、文件中;
cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是是实现session的一种方式。
不要混淆session和session实现。
本来session是一个抽象的概念,开发者为了实现中断和继续等操作,将user agent和server之间一对一的交互,抽象为“会话”,进而衍生出“会话状态”,也就是session的概念。
而cookie是一个实际存在的东西,http协议中定义在header中的字段。可以认为是session的一种后端无状态实现。
而我们今天常说的“session”,是为了绕开cookie的各种限制,通常借助cookie本身和后端存储实现的,一种更高级的会话状态实现。
所以cookie和session,你可以认为是同一层次的概念,也可以认为是不同层次的概念。具体到实现,session因为session id的存在,通常要借助cookie实现,但这并非必要,只能说是通用性较好的一种实现方案。
1.session在服务端,cookie在客户端(浏览器)
- session默认被存在服务器的一个文件里(不是内存)
- session的运行依赖session id,而session id是存在cookie中的,也就是说如果浏览器禁用了cookie,同时session也会失效(可以通过其它方式实现,如在url中传递session_id)
- session可以放在文件、数据库、或内存中的都可以。
- 用户验证这种场合一般都会用session
因此,维持一个会话的核心就是客户端的唯一标识,即session_id

关于打包正式版APP
一定要用最新版。否则图标弄死都是Hbuilder那个图标。
坑了我一个月,也是醉了。都不强制更新下app。找资料也找不到。
一定要用最新版。否则图标弄死都是Hbuilder那个图标。
坑了我一个月,也是醉了。都不强制更新下app。找资料也找不到。

上传图片和压缩
分享自己写的一个上传图片并压缩的方法
element是点击的元素
defaultPic默认图片的名称
defaultPath默认图片的路径
category是我写的一个分类
overwrite是否覆盖压缩 默认覆盖压缩
quality压缩的大小 默认百分之二十
overWriteName 图片压缩后的名称
<div class="uploadPhotoItem">
<img class="pictureUpload pictures" src="../../../images/pic_morentu.jpg">
<span>照片</span>
</div>
//获取上传图片元素
var pictureUploads = document.getElementsByClassName('pictureUpload');
for (var i = 0; i < pictureUploads.length; i++) {
utilsJs.uploadPictures({
element: pictureUploads[i],
defaultPic: 'pic_morentu',
defaultPath: '../../images/pic_morentu.jpg',
category: 'order',
onSuccess: function () {
},
onFailed: function () {
ApiConfig.staticShowToast('图片上传失败');
}
})
}
Utils.prototype.uploadPictures = function (options) {
var _this = this;
options = options || {};
var element = options.element;
var quality = options.quality;
var category = options.category;
var overwrite = options.overwrite;
var defaultPic = options.defaultPic;
var defaultPath = options.defaultPath;
var overWriteName = options.overWriteName;
if (element) {
element.addEventListener('tap', function () {
_this.selectUploadWay({
element: element,
quality: quality,
category: category,
overwrite: overwrite,
defaultPic: defaultPic,
defaultPath: defaultPath,
overWriteName: overWriteName,
onSuccess: function (responseJson) {
options.onSuccess && options.onSuccess(responseJson);
},
onFailed: function (errorJson) {
options.onFailed && options.onFailed(errorJson);
},
onCompleted: function () {
options.onCompleted && options.onCompleted();
}
});
})
}
}
Utils.prototype.selectUploadWay = function (options) {
options = options || {};
var _this = this;
var element = options.element;
var defaultPic = options.defaultPic;
var defaultPath = options.defaultPath;
var overWriteName = options.overWriteName;
var bts = [{
title: '相册'
}, {
title: '拍照'
}, {
title: '删除'
}];
plus.nativeUI.actionSheet({
cancel: "取消",
buttons: bts
},
function (e) {
var i = e.index;
switch (i) {
case 1:
// 拍照添加文件
plus.gallery.pick(function (path) {
_this.uploadPictureHandle({
src: path,
dst: options.dst,
quality: options.quality,
element: options.element,
category: options.category,
overwrite: options.overwrite,
overWriteName: overWriteName,
onSuccess: function (responseJson) {
options.onSuccess && options.onSuccess(responseJson);
},
onFailed: function (errorJson) {
options.onFailed && options.onFailed(errorJson);
},
onCompleted: function () {
options.onCompleted && options.onCompleted();
}
})
});
break;
case 2:
// 从相册添加文件
plus.camera.getCamera().captureImage(function (path) {
_this.uploadPictureHandle({
src: path,
dst: options.dst,
quality: options.quality,
element: options.element,
category: options.category,
overwrite: options.overwrite,
overWriteName: overWriteName,
onSuccess: function (responseJson) {
options.onSuccess && options.onSuccess(responseJson);
},
onFailed: function (errorJson) {
options.onFailed && options.onFailed(errorJson);
},
onCompleted: function () {
options.onCompleted && options.onCompleted();
}
})
});
break;
case 3:
if (element.src.indexOf(defaultPic) >= 0) {
ApiConfig.staticShowToast('当前未上传图片,无法删除');
} else {
element.src = defaultPath;
}
break;
default:
break;
}
}
);
}
Utils.prototype.uploadPictureHandle = function (options) {
options = options || {};
var element = options.element;
var overWriteName = options.overWriteName;
if (!options.overwrite) {
overWriteName = '_doc/default.jpg';
}
plus.zip.compressImage({
src: options.src,
dst: overWriteName,
quality: options.quality || 20,
overwrite: options.overwrite || true
},
function (event) {
dpHttp.upLoadPictureHttp({
files: event.target,
category: options.category,
onSuccess: function (responseJson) {
element.src = responseJson.url;
options.onSuccess && options.onSuccess(responseJson);
},
onFailed: function (errorJson) {
options.onFailed && options.onFailed(errorJson);
},
onCompleted: function () {
options.onCompleted && options.onCompleted();
}
});
},
function (error) {
options.onFailed && options.onFailed(error);
console.log(JSON.stringify(error));
}
);
}
HttpUtils.prototype.upLoadFile = function (options) {
var wt = plus.nativeUI.showWaiting();
options = options || {};
var responseJson = null;
var postParams = options.postParams;
var postFilesMap = options.postFilesMap;
ApiConfig.staticIsDebug('upLoadFile', options.url);
var task = plus.uploader.createUpload(options.url, {
method: "POST",
priority: 100
}, function (t, status) {
if (status == 200) {
try {
wt.close();
responseJson = JSON.parse(t.responseText);
if (responseJson.rt) {
ApiConfig.staticIsDebug('responseJson', responseJson, 1);
options.onSuccess && options.onSuccess(responseJson);
} else {
ApiConfig.staticIsDebug('errorJson', responseJson, 1);
options.onFailed && options.onFailed(responseJson);
}
} catch (e) {
wt.close();
ApiConfig.staticIsDebug('error', e);
ApiConfig.staticIsDebug('errorJson', xhr.responseText);
options.onFailed && options.onFailed(responseJson);
}
} else {
wt.close();
ApiConfig.staticIsDebug('errorJson', responseJson, 1);
options.onFailed && options.onFailed(responseJson);
}
});
//task.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var keys = postFilesMap.keys();
task.addFile(postFilesMap.get(keys[0]), {
key: keys[0]
});
if (postParams) {
var paramsKeys = postParams.keys();
if (paramsKeys.length > 1) {
paramsKeys.forEach(function (key) {
task.addData(key, postParams.get(key));
})
} else {
task.addData(paramsKeys[0], postParams.get(paramsKeys[0]));
}
}
task.start();
}
分享自己写的一个上传图片并压缩的方法
element是点击的元素
defaultPic默认图片的名称
defaultPath默认图片的路径
category是我写的一个分类
overwrite是否覆盖压缩 默认覆盖压缩
quality压缩的大小 默认百分之二十
overWriteName 图片压缩后的名称
<div class="uploadPhotoItem">
<img class="pictureUpload pictures" src="../../../images/pic_morentu.jpg">
<span>照片</span>
</div>
//获取上传图片元素
var pictureUploads = document.getElementsByClassName('pictureUpload');
for (var i = 0; i < pictureUploads.length; i++) {
utilsJs.uploadPictures({
element: pictureUploads[i],
defaultPic: 'pic_morentu',
defaultPath: '../../images/pic_morentu.jpg',
category: 'order',
onSuccess: function () {
},
onFailed: function () {
ApiConfig.staticShowToast('图片上传失败');
}
})
}
Utils.prototype.uploadPictures = function (options) {
var _this = this;
options = options || {};
var element = options.element;
var quality = options.quality;
var category = options.category;
var overwrite = options.overwrite;
var defaultPic = options.defaultPic;
var defaultPath = options.defaultPath;
var overWriteName = options.overWriteName;
if (element) {
element.addEventListener('tap', function () {
_this.selectUploadWay({
element: element,
quality: quality,
category: category,
overwrite: overwrite,
defaultPic: defaultPic,
defaultPath: defaultPath,
overWriteName: overWriteName,
onSuccess: function (responseJson) {
options.onSuccess && options.onSuccess(responseJson);
},
onFailed: function (errorJson) {
options.onFailed && options.onFailed(errorJson);
},
onCompleted: function () {
options.onCompleted && options.onCompleted();
}
});
})
}
}
Utils.prototype.selectUploadWay = function (options) {
options = options || {};
var _this = this;
var element = options.element;
var defaultPic = options.defaultPic;
var defaultPath = options.defaultPath;
var overWriteName = options.overWriteName;
var bts = [{
title: '相册'
}, {
title: '拍照'
}, {
title: '删除'
}];
plus.nativeUI.actionSheet({
cancel: "取消",
buttons: bts
},
function (e) {
var i = e.index;
switch (i) {
case 1:
// 拍照添加文件
plus.gallery.pick(function (path) {
_this.uploadPictureHandle({
src: path,
dst: options.dst,
quality: options.quality,
element: options.element,
category: options.category,
overwrite: options.overwrite,
overWriteName: overWriteName,
onSuccess: function (responseJson) {
options.onSuccess && options.onSuccess(responseJson);
},
onFailed: function (errorJson) {
options.onFailed && options.onFailed(errorJson);
},
onCompleted: function () {
options.onCompleted && options.onCompleted();
}
})
});
break;
case 2:
// 从相册添加文件
plus.camera.getCamera().captureImage(function (path) {
_this.uploadPictureHandle({
src: path,
dst: options.dst,
quality: options.quality,
element: options.element,
category: options.category,
overwrite: options.overwrite,
overWriteName: overWriteName,
onSuccess: function (responseJson) {
options.onSuccess && options.onSuccess(responseJson);
},
onFailed: function (errorJson) {
options.onFailed && options.onFailed(errorJson);
},
onCompleted: function () {
options.onCompleted && options.onCompleted();
}
})
});
break;
case 3:
if (element.src.indexOf(defaultPic) >= 0) {
ApiConfig.staticShowToast('当前未上传图片,无法删除');
} else {
element.src = defaultPath;
}
break;
default:
break;
}
}
);
}
Utils.prototype.uploadPictureHandle = function (options) {
options = options || {};
var element = options.element;
var overWriteName = options.overWriteName;
if (!options.overwrite) {
overWriteName = '_doc/default.jpg';
}
plus.zip.compressImage({
src: options.src,
dst: overWriteName,
quality: options.quality || 20,
overwrite: options.overwrite || true
},
function (event) {
dpHttp.upLoadPictureHttp({
files: event.target,
category: options.category,
onSuccess: function (responseJson) {
element.src = responseJson.url;
options.onSuccess && options.onSuccess(responseJson);
},
onFailed: function (errorJson) {
options.onFailed && options.onFailed(errorJson);
},
onCompleted: function () {
options.onCompleted && options.onCompleted();
}
});
},
function (error) {
options.onFailed && options.onFailed(error);
console.log(JSON.stringify(error));
}
);
}
HttpUtils.prototype.upLoadFile = function (options) {
var wt = plus.nativeUI.showWaiting();
options = options || {};
var responseJson = null;
var postParams = options.postParams;
var postFilesMap = options.postFilesMap;
ApiConfig.staticIsDebug('upLoadFile', options.url);
var task = plus.uploader.createUpload(options.url, {
method: "POST",
priority: 100
}, function (t, status) {
if (status == 200) {
try {
wt.close();
responseJson = JSON.parse(t.responseText);
if (responseJson.rt) {
ApiConfig.staticIsDebug('responseJson', responseJson, 1);
options.onSuccess && options.onSuccess(responseJson);
} else {
ApiConfig.staticIsDebug('errorJson', responseJson, 1);
options.onFailed && options.onFailed(responseJson);
}
} catch (e) {
wt.close();
ApiConfig.staticIsDebug('error', e);
ApiConfig.staticIsDebug('errorJson', xhr.responseText);
options.onFailed && options.onFailed(responseJson);
}
} else {
wt.close();
ApiConfig.staticIsDebug('errorJson', responseJson, 1);
options.onFailed && options.onFailed(responseJson);
}
});
//task.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var keys = postFilesMap.keys();
task.addFile(postFilesMap.get(keys[0]), {
key: keys[0]
});
if (postParams) {
var paramsKeys = postParams.keys();
if (paramsKeys.length > 1) {
paramsKeys.forEach(function (key) {
task.addData(key, postParams.get(key));
})
} else {
task.addData(paramsKeys[0], postParams.get(paramsKeys[0]));
}
}
task.start();
}
收起阅读 »

总结下dcloud中遇到的问题
1、微信分享返回 code:-100,innerCode:-6解决方案
解决办法: 确认申请时填写的应用签名是否小写,是否去除冒号,签名正确,以上验证过了,确保打包验证,不要debug方式验证
2、code: -2,message: 用户取消,
解决办法:确认申请时填写的包名和打包时是否一致
1、微信分享返回 code:-100,innerCode:-6解决方案
解决办法: 确认申请时填写的应用签名是否小写,是否去除冒号,签名正确,以上验证过了,确保打包验证,不要debug方式验证
2、code: -2,message: 用户取消,
解决办法:确认申请时填写的包名和打包时是否一致