关于aes加密(一)
https://developer.mozilla.org/en-US/docs/Web/API/Crypto
https://chromium.googlesource.com/chromium/blink/+/72fef91ac1ef679207f51def81
http://www.oschina.net/code/snippet_552425_46178
<!doctype html>
<html>
<head>
<meta charset='UTF-8'>
</head>
<body>
<div class='test'></div>
<script type="text/javascript">
function encrypt(data, keyJSON){
var data = new TextEncoder("UTF-8").encode(data);
var randomsKeys = geneRandomHexStr(64); // 128 bit keys
var encryptedKey = hexStringToUint8Array(randomsKeys);
var aesAlgo = {name: 'aes-cbc', iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
return crypto.subtle.importKey("jwk", keyJSON, {name: "rsa-oaep", hash: {name: "sha-256"}},true, ['encrypt'])
.then(function(publicKey){
return crypto.subtle.encrypt({name: "rsa-oaep"}, publicKey, encryptedKey);
}).then(function(res){
encryptedKey = bytesToHexString(res)
// use aes to encrypt data
// import aes key
return crypto.subtle.importKey('raw',
hexStringToUint8Array(randomsKeys) , aesAlgo, false, ['encrypt', 'decrypt']);
}).then(function(result){
// use aes to encode
return crypto.subtle.encrypt(aesAlgo,
result, data);
}).then(function(encryptedData){
return Promise.resolve({
'encrypted': bytesToHexString(encryptedData),
'encryptedKey': encryptedKey,
});
});
//console.log(new TextDecoder("UTF-8").decode(data));
// use server public key to encrypt
}
function decrypt(data, keyJSON){
// use local private key to decrypt
var encryptedKey = new hexStringToUint8Array(data.encryptedKey);
var encryptedData = new hexStringToUint8Array(data.encrypted);
var aesAlgo = {name: 'aes-cbc', iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
// decrypt key
return crypto.subtle.importKey('jwk', keyJSON, {name: "rsa-oaep", hash: {name: "sha-256"}}, true,
['decrypt']).then(function(privateKey){
return crypto.subtle.decrypt({name: 'rsa-oaep'}, privateKey, encryptedKey);
}).then(function(decryptedKey){
// import aes key
return crypto.subtle.importKey('raw',
decryptedKey, aesAlgo, false, ['encrypt', 'decrypt']);
}).catch(function(){
console.error("decrypt error");
}).then(function(result){
// decode encrypted data
return crypto.subtle.decrypt(aesAlgo, result, encryptedData);
}).then(function(data){
return Promise.resolve(new TextDecoder("UTF-8").decode(new Uint8Array(data)));
})
}
function createNewUserKey(){
var algorithmKeyGen = {
name: "RSA-OAEP",
hash: {name: "sha-256"},
// RsaKeyGenParams
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // Equivalent to 65537
};
var nonExtractable = false;
var publicKey = "";
var privateKey = "";
var keyPairs = "";
return crypto.subtle.generateKey(algorithmKeyGen, true, ['encrypt', 'decrypt']).then(function(result) {
// gene key pair
keyPairs = result;
return Promise.all([crypto.subtle.exportKey("jwk", keyPairs.publicKey),
crypto.subtle.exportKey("jwk", keyPairs.privateKey)]);
})
}
function _arrayBufferToBase64( buffer ) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa( binary );
}
function hexStringToUint8Array(hexString) {
if (hexString.length % 2 != 0)
throw "Invalid hexString";
var arrayBuffer = new Uint8Array(hexString.length / 2);
for (var i = 0; i < hexString.length; i += 2) {
var byteValue = parseInt(hexString.substr(i, 2), 16);
if (byteValue == NaN)
throw "Invalid hexString";
arrayBuffer[i/2] = byteValue;
}
return arrayBuffer;
}
function bytesToHexString(bytes) {
if (!bytes)
return null;
bytes = new Uint8Array(bytes);
var hexBytes = [];
for (var i = 0; i < bytes.length; ++i) {
var byteString = bytes[i].toString(16);
if (byteString.length < 2)
byteString = "0" + byteString;
hexBytes.push(byteString);
}
return hexBytes.join("");
}
function geneRandomHexStr(length){
var text = "";
var possible = "0123456789abcdef";
for( var i=0; i < length; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
createNewUserKey().then(function(keyPairs){
encrypt("this is origin text", keyPairs[0]).then(function(res){
console.log('public', JSON.stringify(keyPairs[0]));
console.log('private', JSON.stringify(keyPairs[1]));
decrypt(res, keyPairs[1]).then(function(decrypted){
console.log('decrypted', decrypted);
});
});
})
</script>
</body>
</html>
https://developer.mozilla.org/en-US/docs/Web/API/Crypto
https://chromium.googlesource.com/chromium/blink/+/72fef91ac1ef679207f51def81
http://www.oschina.net/code/snippet_552425_46178
<!doctype html>
<html>
<head>
<meta charset='UTF-8'>
</head>
<body>
<div class='test'></div>
<script type="text/javascript">
function encrypt(data, keyJSON){
var data = new TextEncoder("UTF-8").encode(data);
var randomsKeys = geneRandomHexStr(64); // 128 bit keys
var encryptedKey = hexStringToUint8Array(randomsKeys);
var aesAlgo = {name: 'aes-cbc', iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
return crypto.subtle.importKey("jwk", keyJSON, {name: "rsa-oaep", hash: {name: "sha-256"}},true, ['encrypt'])
.then(function(publicKey){
return crypto.subtle.encrypt({name: "rsa-oaep"}, publicKey, encryptedKey);
}).then(function(res){
encryptedKey = bytesToHexString(res)
// use aes to encrypt data
// import aes key
return crypto.subtle.importKey('raw',
hexStringToUint8Array(randomsKeys) , aesAlgo, false, ['encrypt', 'decrypt']);
}).then(function(result){
// use aes to encode
return crypto.subtle.encrypt(aesAlgo,
result, data);
}).then(function(encryptedData){
return Promise.resolve({
'encrypted': bytesToHexString(encryptedData),
'encryptedKey': encryptedKey,
});
});
//console.log(new TextDecoder("UTF-8").decode(data));
// use server public key to encrypt
}
function decrypt(data, keyJSON){
// use local private key to decrypt
var encryptedKey = new hexStringToUint8Array(data.encryptedKey);
var encryptedData = new hexStringToUint8Array(data.encrypted);
var aesAlgo = {name: 'aes-cbc', iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
// decrypt key
return crypto.subtle.importKey('jwk', keyJSON, {name: "rsa-oaep", hash: {name: "sha-256"}}, true,
['decrypt']).then(function(privateKey){
return crypto.subtle.decrypt({name: 'rsa-oaep'}, privateKey, encryptedKey);
}).then(function(decryptedKey){
// import aes key
return crypto.subtle.importKey('raw',
decryptedKey, aesAlgo, false, ['encrypt', 'decrypt']);
}).catch(function(){
console.error("decrypt error");
}).then(function(result){
// decode encrypted data
return crypto.subtle.decrypt(aesAlgo, result, encryptedData);
}).then(function(data){
return Promise.resolve(new TextDecoder("UTF-8").decode(new Uint8Array(data)));
})
}
function createNewUserKey(){
var algorithmKeyGen = {
name: "RSA-OAEP",
hash: {name: "sha-256"},
// RsaKeyGenParams
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // Equivalent to 65537
};
var nonExtractable = false;
var publicKey = "";
var privateKey = "";
var keyPairs = "";
return crypto.subtle.generateKey(algorithmKeyGen, true, ['encrypt', 'decrypt']).then(function(result) {
// gene key pair
keyPairs = result;
return Promise.all([crypto.subtle.exportKey("jwk", keyPairs.publicKey),
crypto.subtle.exportKey("jwk", keyPairs.privateKey)]);
})
}
function _arrayBufferToBase64( buffer ) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa( binary );
}
function hexStringToUint8Array(hexString) {
if (hexString.length % 2 != 0)
throw "Invalid hexString";
var arrayBuffer = new Uint8Array(hexString.length / 2);
for (var i = 0; i < hexString.length; i += 2) {
var byteValue = parseInt(hexString.substr(i, 2), 16);
if (byteValue == NaN)
throw "Invalid hexString";
arrayBuffer[i/2] = byteValue;
}
return arrayBuffer;
}
function bytesToHexString(bytes) {
if (!bytes)
return null;
bytes = new Uint8Array(bytes);
var hexBytes = [];
for (var i = 0; i < bytes.length; ++i) {
var byteString = bytes[i].toString(16);
if (byteString.length < 2)
byteString = "0" + byteString;
hexBytes.push(byteString);
}
return hexBytes.join("");
}
function geneRandomHexStr(length){
var text = "";
var possible = "0123456789abcdef";
for( var i=0; i < length; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
createNewUserKey().then(function(keyPairs){
encrypt("this is origin text", keyPairs[0]).then(function(res){
console.log('public', JSON.stringify(keyPairs[0]));
console.log('private', JSON.stringify(keyPairs[1]));
decrypt(res, keyPairs[1]).then(function(decrypted){
console.log('decrypted', decrypted);
});
});
})
</script>
</body>
</html>
收起阅读 »前端动画制作,量大项目hold不过来,诚心找靠谱长期合作的前端技术人员合作(经常使用HBuilder的优先)
因为文件比较大上传源文件到百度云了,如有意愿加我QQ:2206367168,看完要做的项目的话,然后报价和工期,根据自己的能力来,我们这边的话根据你的能力和速度给到相应的单。具体的咱可以加QQ再聊,有不清楚的地方电话里面沟通也可以,是长期合作的项目,非诚勿扰。
因为文件比较大上传源文件到百度云了,如有意愿加我QQ:2206367168,看完要做的项目的话,然后报价和工期,根据自己的能力来,我们这边的话根据你的能力和速度给到相应的单。具体的咱可以加QQ再聊,有不清楚的地方电话里面沟通也可以,是长期合作的项目,非诚勿扰。
webview模式-缩放式侧滑(类手机QQ)
MUI提供了非常多的控件,我想其中的侧滑导航大多数MUI使用者都在使用,并且遇到不少难题,而我就是其中一个。大家可以发现MUI模板里面有一个非常亮眼的侧滑导航当属缩放式导航(类手机QQ),这是一个DIV模式的缩放式侧滑,它的优点是可以跟着手势滑动,缺点是不可以复用,其实它还有其它缺点,比如在主页面拥有子webview的情况下,这种缩放式侧滑就无法使用了,由于是div模式的,子webview并不会跟着一起缩放。这就不得不让人舍弃主页面的子webview了,但是一般主页面都有下拉刷新控件的,而下拉刷新最佳的拖动性能是必须使用一个单独的webview去装载下拉刷新,如下图,中间下拉刷新是一个webview,导航和底部菜单是一个webview,因此遇到这种情况我们就需要采用webview模式的缩放式侧滑。
这里我讲解一下我使用webview模式开发的缩放式侧滑,做的不好的地方请指教。首先有一个侧滑页面的webview和主页面的webview,主页面下有一个子webview。我们先预加载左边的侧滑页面member/left.html,代码如下:
// 预加载侧滑页面,先让页面藏在显示区域之外-100%
var memberLeftView = mui.preload({
url:'views/member/left.html',
id:'views/member/left.html',
styles: {
left: "-100%",
zindex: -9997,
render:'always'
}
});
然后在触发侧滑的时候设置页面webview的移动位置,侧滑页面首先右移到显示区域,主页面的webview移动到left: '70%',top: '10%',bottom: '10%',的位置,同时打开遮罩,动画300毫秒的移动时间,注意:切勿使用mui.createMash(callback);去创建遮罩,因为主页面是有子webview,会造成不同步且会出现闪动情况。接着在关闭遮罩的时候,再移回原来的位置,这样就实现了简单的webview模式的缩放式侧滑。注意:恢复正常界面的时候隐藏侧滑页面,避免资源消耗。代码如下:
// 我的头像的点击事件
document.getElementById('reho-left-me').addEventListener('tap', function() {
// 侧滑页面出现右移到显示区域
GO_Index.memberLeftView.show('none', 0, function() {
GO_Index.memberLeftView.setStyle({
left: '0',
});
});
// 主界面右移
GO_Index.indexView.show('none', 0, function() {
GO_Index.indexView.setStyle({
left: '70%',
top: '10%',
bottom: '10%',
mask: 'rgba(0,0,0,0.5)',
transition: {
duration: 300
}
});
});
// 每次移除遮罩点击事件,避免重复添加监听
GO_Index.indexView.removeEventListener('maskClick');
// 点击关闭遮罩时
GO_Index.indexView.addEventListener('maskClick', function(){
// 主界面移动到最大显示区域
GO_Index.indexView.setStyle({
left: '0',
top: '0',
bottom: '0',
mask: 'none',
transition: {
duration: 300
}
});
// 侧滑界面移出显示区域之外
GO_Index.memberLeftView.setStyle({
left: "-100%",
transition: {
duration: 300
}
});
// 隐藏侧滑页面,setTimeout避免竞争资源
setTimeout(function() {
GO_Index.memberLeftView.hide();
}, 300);
},false);
});
实现效果如下图:
(更多精彩内容请访问DCloud官网(http://www.dcloud.io/))
MUI提供了非常多的控件,我想其中的侧滑导航大多数MUI使用者都在使用,并且遇到不少难题,而我就是其中一个。大家可以发现MUI模板里面有一个非常亮眼的侧滑导航当属缩放式导航(类手机QQ),这是一个DIV模式的缩放式侧滑,它的优点是可以跟着手势滑动,缺点是不可以复用,其实它还有其它缺点,比如在主页面拥有子webview的情况下,这种缩放式侧滑就无法使用了,由于是div模式的,子webview并不会跟着一起缩放。这就不得不让人舍弃主页面的子webview了,但是一般主页面都有下拉刷新控件的,而下拉刷新最佳的拖动性能是必须使用一个单独的webview去装载下拉刷新,如下图,中间下拉刷新是一个webview,导航和底部菜单是一个webview,因此遇到这种情况我们就需要采用webview模式的缩放式侧滑。
这里我讲解一下我使用webview模式开发的缩放式侧滑,做的不好的地方请指教。首先有一个侧滑页面的webview和主页面的webview,主页面下有一个子webview。我们先预加载左边的侧滑页面member/left.html,代码如下:
// 预加载侧滑页面,先让页面藏在显示区域之外-100%
var memberLeftView = mui.preload({
url:'views/member/left.html',
id:'views/member/left.html',
styles: {
left: "-100%",
zindex: -9997,
render:'always'
}
});
然后在触发侧滑的时候设置页面webview的移动位置,侧滑页面首先右移到显示区域,主页面的webview移动到left: '70%',top: '10%',bottom: '10%',的位置,同时打开遮罩,动画300毫秒的移动时间,注意:切勿使用mui.createMash(callback);去创建遮罩,因为主页面是有子webview,会造成不同步且会出现闪动情况。接着在关闭遮罩的时候,再移回原来的位置,这样就实现了简单的webview模式的缩放式侧滑。注意:恢复正常界面的时候隐藏侧滑页面,避免资源消耗。代码如下:
// 我的头像的点击事件
document.getElementById('reho-left-me').addEventListener('tap', function() {
// 侧滑页面出现右移到显示区域
GO_Index.memberLeftView.show('none', 0, function() {
GO_Index.memberLeftView.setStyle({
left: '0',
});
});
// 主界面右移
GO_Index.indexView.show('none', 0, function() {
GO_Index.indexView.setStyle({
left: '70%',
top: '10%',
bottom: '10%',
mask: 'rgba(0,0,0,0.5)',
transition: {
duration: 300
}
});
});
// 每次移除遮罩点击事件,避免重复添加监听
GO_Index.indexView.removeEventListener('maskClick');
// 点击关闭遮罩时
GO_Index.indexView.addEventListener('maskClick', function(){
// 主界面移动到最大显示区域
GO_Index.indexView.setStyle({
left: '0',
top: '0',
bottom: '0',
mask: 'none',
transition: {
duration: 300
}
});
// 侧滑界面移出显示区域之外
GO_Index.memberLeftView.setStyle({
left: "-100%",
transition: {
duration: 300
}
});
// 隐藏侧滑页面,setTimeout避免竞争资源
setTimeout(function() {
GO_Index.memberLeftView.hide();
}, 300);
},false);
});
实现效果如下图:
(更多精彩内容请访问DCloud官网(http://www.dcloud.io/))
收起阅读 »webview层级的一个问题(设置zindex后ios上与安卓不一致)
效果:(菜单中间的那个图标比较大,需要凸显出来)
设置菜单层级和样式
mui.init({
subpages:[{
url:'nav.html',
id:'nav.html',
styles:{
zindex:"90",
width:"100%",
height:"70px",
bottom:"0px",//默认为0px,可不定义;
background:"transparent"
}
}]
});
var subpages = ['bf.html', 'straight.html', 'find.html', 'expert.html', 'person.html'];
var subpage_style = {
zindex:"20",
top: '0px',
bottom: '50px'
};
点击菜单切换的代码
for(var i=0;i<subpages.length;i++){
if(subpages[i]==targetTab){
plus.webview.show(subpages[i]);
plus.webview.show('nav.html');
}else{
plus.webview.hide(subpages[i]);
}
}
注意:这个plus.webview.show('nav.html');一定要加上去(原因:在ios上面,plus.webview.show()这个方法会默认把这个层显示在最上面)
效果:(菜单中间的那个图标比较大,需要凸显出来)
设置菜单层级和样式
mui.init({
subpages:[{
url:'nav.html',
id:'nav.html',
styles:{
zindex:"90",
width:"100%",
height:"70px",
bottom:"0px",//默认为0px,可不定义;
background:"transparent"
}
}]
});
var subpages = ['bf.html', 'straight.html', 'find.html', 'expert.html', 'person.html'];
var subpage_style = {
zindex:"20",
top: '0px',
bottom: '50px'
};
点击菜单切换的代码
for(var i=0;i<subpages.length;i++){
if(subpages[i]==targetTab){
plus.webview.show(subpages[i]);
plus.webview.show('nav.html');
}else{
plus.webview.hide(subpages[i]);
}
}
注意:这个plus.webview.show('nav.html');一定要加上去(原因:在ios上面,plus.webview.show()这个方法会默认把这个层显示在最上面)
收起阅读 »Android监听电话呼入呼出
基本上是对着Native.js和百度的Android原生代码撸出来的。暂未测试多台机型。
(function($) {
var receiver, main, context, TelephonyManager;
$.plusReady(function() {
context = plus.android.importClass('android.content.Context'); //上下文
TelephonyManager = plus.android.importClass('android.telephony.TelephonyManager'); //通话管理
main = plus.android.runtimeMainActivity(); //获取activity
receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {
onReceive: doReceive //实现onReceiver回调函数
});
var IntentFilter = plus.android.importClass('android.content.IntentFilter');
var Intent = plus.android.importClass('android.content.Intent');
var filter = new IntentFilter();
//filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); //监听飞行模式
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); //监听电话状态
main.registerReceiver(receiver, filter); //注册监听
});
function doReceive(context, intent) {
plus.android.importClass(intent);
var phoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER),
telephony = context.getSystemService(context.TELEPHONY_SERVICE),
state = telephony.getCallState();
switch(state) {
case TelephonyManager.CALL_STATE_RINGING:
console.log("[Broadcast]等待接电话=" + phoneNumber);
break;
case TelephonyManager.CALL_STATE_IDLE:
console.log("[Broadcast]电话挂断=" + phoneNumber);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
console.log("[Broadcast]通话中=" + phoneNumber);
break;
}
console.log(intent.getAction());
}
}(mui)); 基本上是对着Native.js和百度的Android原生代码撸出来的。暂未测试多台机型。
(function($) {
var receiver, main, context, TelephonyManager;
$.plusReady(function() {
context = plus.android.importClass('android.content.Context'); //上下文
TelephonyManager = plus.android.importClass('android.telephony.TelephonyManager'); //通话管理
main = plus.android.runtimeMainActivity(); //获取activity
receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {
onReceive: doReceive //实现onReceiver回调函数
});
var IntentFilter = plus.android.importClass('android.content.IntentFilter');
var Intent = plus.android.importClass('android.content.Intent');
var filter = new IntentFilter();
//filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); //监听飞行模式
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); //监听电话状态
main.registerReceiver(receiver, filter); //注册监听
});
function doReceive(context, intent) {
plus.android.importClass(intent);
var phoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER),
telephony = context.getSystemService(context.TELEPHONY_SERVICE),
state = telephony.getCallState();
switch(state) {
case TelephonyManager.CALL_STATE_RINGING:
console.log("[Broadcast]等待接电话=" + phoneNumber);
break;
case TelephonyManager.CALL_STATE_IDLE:
console.log("[Broadcast]电话挂断=" + phoneNumber);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
console.log("[Broadcast]通话中=" + phoneNumber);
break;
}
console.log(intent.getAction());
}
}(mui)); 收起阅读 »
HBUILDER与支付宝的十宗罪
其实是支付宝和HB共同的坑
- 服务器公钥的配置,2个地方要配置,1是开放平台的 2是合作伙伴的,否则出现ATL65错误
- 不要使用最新网关https://openapi.alipay.com/gateway.do的参数配置,否则死的很惨,因为HB不支持。会出现ATL2075错误
- SIGN RSA私钥加密的字符串一定是key="value"&key="value"格式,这个不能错,否则签名有问题
- 私钥加密可以不用排序
- HB中提交的数据格式也一定是key="value"&key="value",否则出错
- 关于NOTIFY异步回传验证是否为支付宝,原HTTP地址不能用了,只能用HTTPS地址:https://mapi.alipay.com/gateway.do?service=notify_verify&partner=2088002396712354¬ify_id=RqPnCoPT3K9%252Fvwbh3I%252BFioE227%252BPfNMl8jwyZqMIiXQWxhOCmQ5MQO%252FWd93rvCB%252BaiGg
- NOTIFY SIGN验证要使用公钥
- 参数notify_data不在回传参数内,目前WAP网页支付还是支持
- 回传参数验证SIGN需要ksort排序,否则出错
- HB的支付提交错误返还的参数e.code没卵用
其实是支付宝和HB共同的坑
- 服务器公钥的配置,2个地方要配置,1是开放平台的 2是合作伙伴的,否则出现ATL65错误
- 不要使用最新网关https://openapi.alipay.com/gateway.do的参数配置,否则死的很惨,因为HB不支持。会出现ATL2075错误
- SIGN RSA私钥加密的字符串一定是key="value"&key="value"格式,这个不能错,否则签名有问题
- 私钥加密可以不用排序
- HB中提交的数据格式也一定是key="value"&key="value",否则出错
- 关于NOTIFY异步回传验证是否为支付宝,原HTTP地址不能用了,只能用HTTPS地址:https://mapi.alipay.com/gateway.do?service=notify_verify&partner=2088002396712354¬ify_id=RqPnCoPT3K9%252Fvwbh3I%252BFioE227%252BPfNMl8jwyZqMIiXQWxhOCmQ5MQO%252FWd93rvCB%252BaiGg
- NOTIFY SIGN验证要使用公钥
- 参数notify_data不在回传参数内,目前WAP网页支付还是支持
- 回传参数验证SIGN需要ksort排序,否则出错
- HB的支付提交错误返还的参数e.code没卵用
关于mui-slider组件动态生成之后无法滚动切换等问题
关于mui-slider组件动态生成之后无法滚动切换等问题
1.这个组件呢,里面具体的实现我不知道,但是动态生成造成部分功能缺失大概都是因为下面的原因
- 也就是说这个组件在浏览器检测到mui-slider类样式的时候就开始了初始化(纯属个人猜测)。
- 怎么解决呢?我们用这个滑动组件一般都是事先不知道有多少个,都是动态数据,这就是他们设计这个组件的时候的缺陷,这个必须改进
- 解决方案如下:
5.我们把整个slider组件的html都动态来生成也就是这样的
var temphtml = "<div id='slider' class='mui-slider mui-fullscreen reg_jacc'><div id='sliderSegmentedControl' class='mui-scroll-wrapper mui-slider-indicator mui-segmented-control mui-segmented-control-inverted'><div id='username' class='mui-scroll'></div></div><div id='userInfo' class='mui-slider-group'></div></div>";
var temphtmlnode = zqnb.dom(temphtml);
document.getElementById("tempHtml").appendChild(temphtmlnode);
6.请不要纠结生成dom并且放入dom树的代码,只是告诉你们步骤,拼接html字符串、转dom、放入dom树。 - 这样我们的滑动组件有了,滑动组件里面的容器也有了,下面的工作就是获取容器dom填充数据了。
- 谢谢。
关于mui-slider组件动态生成之后无法滚动切换等问题
1.这个组件呢,里面具体的实现我不知道,但是动态生成造成部分功能缺失大概都是因为下面的原因
- 也就是说这个组件在浏览器检测到mui-slider类样式的时候就开始了初始化(纯属个人猜测)。
- 怎么解决呢?我们用这个滑动组件一般都是事先不知道有多少个,都是动态数据,这就是他们设计这个组件的时候的缺陷,这个必须改进
- 解决方案如下:
5.我们把整个slider组件的html都动态来生成也就是这样的
var temphtml = "<div id='slider' class='mui-slider mui-fullscreen reg_jacc'><div id='sliderSegmentedControl' class='mui-scroll-wrapper mui-slider-indicator mui-segmented-control mui-segmented-control-inverted'><div id='username' class='mui-scroll'></div></div><div id='userInfo' class='mui-slider-group'></div></div>";
var temphtmlnode = zqnb.dom(temphtml);
document.getElementById("tempHtml").appendChild(temphtmlnode);
6.请不要纠结生成dom并且放入dom树的代码,只是告诉你们步骤,拼接html字符串、转dom、放入dom树。 - 这样我们的滑动组件有了,滑动组件里面的容器也有了,下面的工作就是获取容器dom填充数据了。
- 谢谢。
开源项目分享说明-DCloud产品技能分享大赛
分享的开源项目类型可以包括以下几种:
- 采用5+、MUI技术开发的App类项目(比如资讯、电商、金融、游戏等)。
- 基于5+、MUI的开源组件,建议大家分享可大幅节省开发时间的开源组件,目前推荐但不局限于以下几类:
-
跨平台适配:比如兼容5+ App、微信、QQ浏览器、UC浏览器的分享组件,兼容5+ App、微信、普通手机浏览器的支付组件;
-
基于mui现有组件实现扩展组件,比如:基于scroll控件实现左右滑动的专辑封面切换效果,基于图片轮播实现上下移动或渐隐渐现的轮播效果;
-
包含交互效果的模板,比如类似微信公众号消息列表的模板、朋友圈UI模板(包含图片预览、点赞、评论等交互功能)
参赛方式为进入HBuilder活动页面【点击HBuilder菜单帮助>>活动】点击立即参加然后提交项目链接,同时大家可以将已实现好的开源工程,在https://github.com/dcloudio/casecode提交pull Request,我们会关联展示。
分享的开源项目类型可以包括以下几种:
- 采用5+、MUI技术开发的App类项目(比如资讯、电商、金融、游戏等)。
- 基于5+、MUI的开源组件,建议大家分享可大幅节省开发时间的开源组件,目前推荐但不局限于以下几类:
-
跨平台适配:比如兼容5+ App、微信、QQ浏览器、UC浏览器的分享组件,兼容5+ App、微信、普通手机浏览器的支付组件;
-
基于mui现有组件实现扩展组件,比如:基于scroll控件实现左右滑动的专辑封面切换效果,基于图片轮播实现上下移动或渐隐渐现的轮播效果;
-
包含交互效果的模板,比如类似微信公众号消息列表的模板、朋友圈UI模板(包含图片预览、点赞、评论等交互功能)
参赛方式为进入HBuilder活动页面【点击HBuilder菜单帮助>>活动】点击立即参加然后提交项目链接,同时大家可以将已实现好的开源工程,在https://github.com/dcloudio/casecode提交pull Request,我们会关联展示。
收起阅读 »解决plus.nativeObj.View页面切换,点击事件无效问题。
下方有附件可直接下载使用。
页面一
HTML代码
<a class="_button" onclick="go()">Hbuilder</a>
CSS代码
._button{
padding:8px 10px;
background:#f60;
margin:50px auto;
display: block;
width:120px;
text-align:center;
color:#FFFFFF;
border-radius: 3px;
}
JS代码
function plusReady(){
//创建底部图片
issue = new plus.nativeObj.Bitmap('bmp');
issue.load('images/footImg.png',function(){
console.log('图片加载完成!');
createView();
},function(e){
console.log('图片加载失败!'+JSON.stringify(e));
});
}
// 创建原生View控件
function createView(){
view = new plus.nativeObj.View('FootImg',{top:'90%',left:'43%',height:'55px',width:'55px',background:'#f60'});
view.drawBitmap( issue, {top:'0px',left:'0px',width:'100%',height:'100%'}, {top:'auto',left:'auto',width:'100%',height:'100%'} );
view.show();
view.addEventListener("click",ViewClick, false);
}
//View点击事件
function ViewClick(){
alert('你点击的view');
}
if(window.plus){
plusReady();
}else{
document.addEventListener("plusready",plusReady,false);
}
/* 页面切换 */
function go(){
var subpage = mui.openWindow({
url:'list.html',
id:'list.html',
});
//页面转场的时候清除掉view。
subpage.addEventListener('loaded', function() {
subpage.show('slide-in-right', 200, function() {
view.clear();
});
});
}
//监听list返回
window.addEventListener('_title',function(){
//一监听到就可以创建View了,但是View的点击没用(事件应该是绑上了,用createView()的话会发现点击的时候会弹窗两次),应该是位置的问题吧。
view = new plus.nativeObj.View('FootImg',{top:'90%',left:'43%',height:'55px',width:'55px',background:'#f60'});
view.drawBitmap( issue, {top:'0px',left:'0px',width:'100%',height:'100%'}, {top:'auto',left:'auto',width:'100%',height:'100%'} );
view.show();
// createView(); 这样写的话点击会被执行两次。
//所以等待窗体动画到位在绑定事件
setTimeout(function(){
view.addEventListener("click",ViewClick, false);
},400);
});
页面二
JS代码
$('._back').on('tap',function(){
mui.init({
beforeback: function(){
// var viewPage = plus.webview.getWebviewById('view.html'); //如果不是首页面就用这个获取指定ID,否则用下面的获取首页窗体;
var viewPage = plus.webview.getLaunchWebview();
mui.fire(viewPage,'_title',{/* 这里可以传值 */});
return true;
}
});
mui.back();
})
下方有附件可直接下载使用。
页面一
HTML代码
<a class="_button" onclick="go()">Hbuilder</a>
CSS代码
._button{
padding:8px 10px;
background:#f60;
margin:50px auto;
display: block;
width:120px;
text-align:center;
color:#FFFFFF;
border-radius: 3px;
}
JS代码
function plusReady(){
//创建底部图片
issue = new plus.nativeObj.Bitmap('bmp');
issue.load('images/footImg.png',function(){
console.log('图片加载完成!');
createView();
},function(e){
console.log('图片加载失败!'+JSON.stringify(e));
});
}
// 创建原生View控件
function createView(){
view = new plus.nativeObj.View('FootImg',{top:'90%',left:'43%',height:'55px',width:'55px',background:'#f60'});
view.drawBitmap( issue, {top:'0px',left:'0px',width:'100%',height:'100%'}, {top:'auto',left:'auto',width:'100%',height:'100%'} );
view.show();
view.addEventListener("click",ViewClick, false);
}
//View点击事件
function ViewClick(){
alert('你点击的view');
}
if(window.plus){
plusReady();
}else{
document.addEventListener("plusready",plusReady,false);
}
/* 页面切换 */
function go(){
var subpage = mui.openWindow({
url:'list.html',
id:'list.html',
});
//页面转场的时候清除掉view。
subpage.addEventListener('loaded', function() {
subpage.show('slide-in-right', 200, function() {
view.clear();
});
});
}
//监听list返回
window.addEventListener('_title',function(){
//一监听到就可以创建View了,但是View的点击没用(事件应该是绑上了,用createView()的话会发现点击的时候会弹窗两次),应该是位置的问题吧。
view = new plus.nativeObj.View('FootImg',{top:'90%',left:'43%',height:'55px',width:'55px',background:'#f60'});
view.drawBitmap( issue, {top:'0px',left:'0px',width:'100%',height:'100%'}, {top:'auto',left:'auto',width:'100%',height:'100%'} );
view.show();
// createView(); 这样写的话点击会被执行两次。
//所以等待窗体动画到位在绑定事件
setTimeout(function(){
view.addEventListener("click",ViewClick, false);
},400);
});
页面二
JS代码
$('._back').on('tap',function(){
mui.init({
beforeback: function(){
// var viewPage = plus.webview.getWebviewById('view.html'); //如果不是首页面就用这个获取指定ID,否则用下面的获取首页窗体;
var viewPage = plus.webview.getLaunchWebview();
mui.fire(viewPage,'_title',{/* 这里可以传值 */});
return true;
}
});
mui.back();
}) 收起阅读 »
几行代码轻松实现瀑布流显示。
实现思路:创建左右两个容器,在数据导入的时候获取两个容器的高度,把即将要导入的数据,导进高度低的一个容器即可。
HTML代码
<body style="background-color: #f3f3f3;">
<!-- 商品列表 -->
<div class="twoRankedBox">
<ul class="BoxLeft">
</ul>
<ul class="BoxRight">
</ul>
</div>
</body>
CSS代码
*{
padding:0px;
margin:0px;
list-style: none;
font-style:normal;
font-family: arial;
font-family: Microsoft YaHei,arial;
}
.twoRankedBox{
margin:6px 8px;
overflow: hidden;
padding-bottom:25px;
}
.twoRankedBox ul{
width:49%;
float: left;
}
.twoRankedBox ul:last-child{
margin-left:2%;
}
.twoRankedBox ul li{
padding:5px;
margin-bottom:6px;
padding-bottom:8px;
background-color: #FFFFFF;
}
.twoRankedBox ul li p:first-child{
padding-top:0px;
}
.twoRankedBox ul li p{
padding-top:4px;
}
.product_picture img{
display: block;
width:100%;
}
.product_np{
overflow: hidden;
line-height:20px;
}
.product_np a{
display: block;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
}
.product_np a:first-child{
font-size:0.9em;
color:#58b7e3;
width:65%;
float: left;
}
.product_np a:last-child{
font-size:0.8em;
color:#f00;
float: right;
width:35%;
text-align: right;
}
.product_ie{
font-size:0.8em;
color:#777;
}
JS代码(需要JQ,因为获取高度是用JQ写的。可以自行修改)
//模拟JSON数据
var json = {
data:[
{name:'花瓣小小裙花瓣',price:'128',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_01.jpg'},
{name:'时尚牛仔短裤',price:'298',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_02.jpg'},
{name:'白色婚纱',price:'668',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_03.jpg'},
{name:'绿色防晒衣',price:'218',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_04.jpg'},
{name:'格纹小短裙',price:'88',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_05.jpg'},
{name:'复古旗袍',price:'128',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_06.jpg'},
{name:'花瓣小小裙花瓣',price:'128',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_07.jpg'},
{name:'时尚牛仔短裤',price:'298',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_08.jpg'},
{name:'白色婚纱',price:'668',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_09.jpg'},
{name:'绿色防晒衣',price:'218',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_10.jpg'},
{name:'格纹小短裙',price:'118',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_11.jpg'}
]
}
//模拟数据导入
for(var i=0;i<json.data.length;i++){
var chtml = '<li><p class="product_picture"><img src="'+json.data[i].src+'"></p>'
+'<p class="product_np"><a>'+json.data[i].name+'</a><a>¥'+json.data[i].price+'</a></p>'
+'<p class="product_ie">'+json.data[i].details+'</p></li>'
if($('.BoxLeft').height() < $('.BoxRight').height()){
$('.BoxLeft').append(chtml);
}else{
$('.BoxRight').append(chtml);
}
}
实现思路:创建左右两个容器,在数据导入的时候获取两个容器的高度,把即将要导入的数据,导进高度低的一个容器即可。
HTML代码
<body style="background-color: #f3f3f3;">
<!-- 商品列表 -->
<div class="twoRankedBox">
<ul class="BoxLeft">
</ul>
<ul class="BoxRight">
</ul>
</div>
</body>
CSS代码
*{
padding:0px;
margin:0px;
list-style: none;
font-style:normal;
font-family: arial;
font-family: Microsoft YaHei,arial;
}
.twoRankedBox{
margin:6px 8px;
overflow: hidden;
padding-bottom:25px;
}
.twoRankedBox ul{
width:49%;
float: left;
}
.twoRankedBox ul:last-child{
margin-left:2%;
}
.twoRankedBox ul li{
padding:5px;
margin-bottom:6px;
padding-bottom:8px;
background-color: #FFFFFF;
}
.twoRankedBox ul li p:first-child{
padding-top:0px;
}
.twoRankedBox ul li p{
padding-top:4px;
}
.product_picture img{
display: block;
width:100%;
}
.product_np{
overflow: hidden;
line-height:20px;
}
.product_np a{
display: block;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
}
.product_np a:first-child{
font-size:0.9em;
color:#58b7e3;
width:65%;
float: left;
}
.product_np a:last-child{
font-size:0.8em;
color:#f00;
float: right;
width:35%;
text-align: right;
}
.product_ie{
font-size:0.8em;
color:#777;
}
JS代码(需要JQ,因为获取高度是用JQ写的。可以自行修改)
//模拟JSON数据
var json = {
data:[
{name:'花瓣小小裙花瓣',price:'128',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_01.jpg'},
{name:'时尚牛仔短裤',price:'298',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_02.jpg'},
{name:'白色婚纱',price:'668',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_03.jpg'},
{name:'绿色防晒衣',price:'218',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_04.jpg'},
{name:'格纹小短裙',price:'88',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_05.jpg'},
{name:'复古旗袍',price:'128',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_06.jpg'},
{name:'花瓣小小裙花瓣',price:'128',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_07.jpg'},
{name:'时尚牛仔短裤',price:'298',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_08.jpg'},
{name:'白色婚纱',price:'668',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_09.jpg'},
{name:'绿色防晒衣',price:'218',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_10.jpg'},
{name:'格纹小短裙',price:'118',details:'质量超好特别的舒适,夏天首选。',src:'images/temporary/img_11.jpg'}
]
}
//模拟数据导入
for(var i=0;i<json.data.length;i++){
var chtml = '<li><p class="product_picture"><img src="'+json.data[i].src+'"></p>'
+'<p class="product_np"><a>'+json.data[i].name+'</a><a>¥'+json.data[i].price+'</a></p>'
+'<p class="product_ie">'+json.data[i].details+'</p></li>'
if($('.BoxLeft').height() < $('.BoxRight').height()){
$('.BoxLeft').append(chtml);
}else{
$('.BoxRight').append(chtml);
}
}
收起阅读 »






