
MUI 用了这么久感觉没有一个单独的文档来说明各种mui的css类
MUI 用了这么久感觉没有一个单独的文档来说明各种mui的css类,都是在文档中偶尔夹杂进行点说明,或者是我太笨没发现。比如:mui-action-menu是干什么的,mui-bar我知道是标题栏的,加上它后标栏就置顶不会动了,还有很多MUI的CSS类不知道怎么用,也不知道是什么意思。或者在MUI 文档加个搜索功能,一个一个点开来用浏览器搜也比较麻烦。
MUI 用了这么久感觉没有一个单独的文档来说明各种mui的css类,都是在文档中偶尔夹杂进行点说明,或者是我太笨没发现。比如:mui-action-menu是干什么的,mui-bar我知道是标题栏的,加上它后标栏就置顶不会动了,还有很多MUI的CSS类不知道怎么用,也不知道是什么意思。或者在MUI 文档加个搜索功能,一个一个点开来用浏览器搜也比较麻烦。
收起阅读 »
android 单个大文件断点续传
最近公司项目需求做大文件的单点续传
分享下
java类代码
后台异步切割文件 切完返回true
/**
* 切割文件保存到指定目录 根据指定名称保存
* @param pWebview
* @param array
*/
public void cutFile(final IWebview pWebview, JSONArray array){
final String CallBackID = array.optString(0);
final String filePath = array.optString(2);
final String cutPath = array.optString(3);
AsyncTask<String, Void, String> execute = new AsyncTask<String, Void, String>() {
public void execute(String taskId, String filePath, String cutPath) {
}
@Override
protected String doInBackground(String... params) {
java.net.HttpURLConnection connection = null;
byte[] buffer = new byte[readStep];
FileInputStream file = null;
File f =new File(filePath);
String fileName=f.getName();
try {
file = new FileInputStream(filePath);
int len = 0;
int AllLen = 0;
try {
FileInputStream fs = new FileInputStream(filePath);
fileSize = fs.available();
AllLen = fileSize / (readStep);
if(fileSize % (readStep) > 0){
AllLen++;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int nowCount = 1;
while ((len = file.read(buffer)) > 0) {
String strFilePath = cutPath+fileName+".part";
try {
File cutfile = new File(strFilePath);
if (!cutfile.exists()) {
Log.e("TestFile", "Create the file:" + strFilePath);
cutfile.getParentFile().mkdirs();
cutfile.createNewFile();
}
RandomAccessFile raf = new RandomAccessFile(cutfile, "rwd");
raf.seek(0);
raf.write(buffer,0,(int)len);
raf.close();
} catch (Exception e) {
Log.e("TestFile", "Error on write File:" + e);
}
nowCount++;
};
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "abc";
}
protected void onPostExecute(String result) {
Log.e("result",result);
if(result == "abc"){
JSONArray newArray = new JSONArray();
newArray.put(true);
JSUtil.execCallback(pWebview, CallBackID, newArray, JSUtil.OK, true);
}
}
}.execute();
}
后台异步提交文件夹中所有文件碎片
/**
*
* @param pWebview
* @param array
*
* taskId temp[0]
* AllLen temp[1]
* nowCount temp[2]
*/
public void sendTempFile(IWebview pWebview, JSONArray array){
String CallBackID = array.optString(0);
String cutPath = array.optString(1);
String URLPath = array.optString(2);
byte[] buffer = new byte[readStep];
File file = new File(cutPath);
File[] fs = file.listFiles();
for (File f : fs){
String newString = f.getName().toString().replace(".part","");
Pattern pen = Pattern.compile("_");
String[] temp = pen.split(newString);
String fileName = temp[3];
Log.e("fileName",temp[3]);
//获取文件大小
FileInputStream fst = null;
try {
fst = new FileInputStream(f.getPath());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
fileSize = fst.available();
} catch (IOException e) {
e.printStackTrace();
}
//执行异步上传提交
asyncSendTempFiles(URLPath+"&task_id="+temp[0]+"&fileSize="+fileSize,f.getPath(),fileName,buffer,0,Integer.parseInt(temp[1]),Integer.parseInt(temp[2]),pWebview,CallBackID);
}
}
public void asyncSendTempFiles(final String urlPath, final String filePath, final String fileName, final byte[] buffer, final int count, final int allLength, final int nowCount, final IWebview pWebview, final String CallBackID){
AsyncTask<String, Void, String> execute = new AsyncTask<String, Void, String>() {
public void execute(String urlPath, String filePath, String fileName, byte[] buffer, int count, int allLength, int nowCount) {
}
@Override
protected String doInBackground(String... params) {
java.net.HttpURLConnection connection = null;
try {
Log.e("urlPath",urlPath+"&allLength="+allLength+"&nowCount="+nowCount+"&fileName="+URLEncoder.encode(fileName, "UTF-8"));
URL url = new URL(urlPath+"&allLength="+allLength+"&nowCount="+nowCount+"&fileName="+URLEncoder.encode(fileName, "UTF-8"));
connection = (java.net.HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setDoOutput(true);
FileInputStream is = new FileInputStream(filePath);
byte[] b = new byte[is.available()];
Log.e("available",is.available()+"");
is.read(b);
OutputStream os = connection.getOutputStream();
os.write(b);
os.flush();
os.close();
if(connection.getResponseCode() == 200){
Log.e("ResponseMessage",connection.getResponseMessage());
return changeInputStream(connection.getInputStream(),"UTF-8");
}else{
}
} catch (IOException e) {
Log.e("urlPath","url error");
e.printStackTrace();
}
return "";
}
protected void onPostExecute(String result) {
Log.e("result",result);
try {
JSONObject jsonObject = new JSONObject(result);
//int resultCode = jsonObject.getInt("resultcode");
String data = jsonObject.getString("status");
Log.e("result-data",data);
if(data == "0"){
//传输成功 删除当前文件
File file=new File(filePath);
//文件是否存在
if(file.exists())
{
file.delete();
Log.e("result-data","文件已经被删除了");
}
}
} catch (JSONException e) {
Log.e("result",result);
e.printStackTrace();
}
// JSONArray newArray = new JSONArray();
// newArray.put(result);
// JSUtil.execCallback(pWebview, CallBackID, newArray, JSUtil.OK, true);
}
}.execute();
}
/**
* 将一个输入流转换成指定编码的字符串
*
* @param inputStream
* @param encode
* @return
*/
private static String changeInputStream(InputStream inputStream,
String encode) {
// 内存流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int len = 0;
String result = null;
if (inputStream != null) {
try {
while ((len = inputStream.read(data)) != -1) {
byteArrayOutputStream.write(data, 0, len);
}
result = new String(byteArrayOutputStream.toByteArray(), encode);
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
最近公司项目需求做大文件的单点续传
分享下
java类代码
后台异步切割文件 切完返回true
/**
* 切割文件保存到指定目录 根据指定名称保存
* @param pWebview
* @param array
*/
public void cutFile(final IWebview pWebview, JSONArray array){
final String CallBackID = array.optString(0);
final String filePath = array.optString(2);
final String cutPath = array.optString(3);
AsyncTask<String, Void, String> execute = new AsyncTask<String, Void, String>() {
public void execute(String taskId, String filePath, String cutPath) {
}
@Override
protected String doInBackground(String... params) {
java.net.HttpURLConnection connection = null;
byte[] buffer = new byte[readStep];
FileInputStream file = null;
File f =new File(filePath);
String fileName=f.getName();
try {
file = new FileInputStream(filePath);
int len = 0;
int AllLen = 0;
try {
FileInputStream fs = new FileInputStream(filePath);
fileSize = fs.available();
AllLen = fileSize / (readStep);
if(fileSize % (readStep) > 0){
AllLen++;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int nowCount = 1;
while ((len = file.read(buffer)) > 0) {
String strFilePath = cutPath+fileName+".part";
try {
File cutfile = new File(strFilePath);
if (!cutfile.exists()) {
Log.e("TestFile", "Create the file:" + strFilePath);
cutfile.getParentFile().mkdirs();
cutfile.createNewFile();
}
RandomAccessFile raf = new RandomAccessFile(cutfile, "rwd");
raf.seek(0);
raf.write(buffer,0,(int)len);
raf.close();
} catch (Exception e) {
Log.e("TestFile", "Error on write File:" + e);
}
nowCount++;
};
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "abc";
}
protected void onPostExecute(String result) {
Log.e("result",result);
if(result == "abc"){
JSONArray newArray = new JSONArray();
newArray.put(true);
JSUtil.execCallback(pWebview, CallBackID, newArray, JSUtil.OK, true);
}
}
}.execute();
}
后台异步提交文件夹中所有文件碎片
/**
*
* @param pWebview
* @param array
*
* taskId temp[0]
* AllLen temp[1]
* nowCount temp[2]
*/
public void sendTempFile(IWebview pWebview, JSONArray array){
String CallBackID = array.optString(0);
String cutPath = array.optString(1);
String URLPath = array.optString(2);
byte[] buffer = new byte[readStep];
File file = new File(cutPath);
File[] fs = file.listFiles();
for (File f : fs){
String newString = f.getName().toString().replace(".part","");
Pattern pen = Pattern.compile("_");
String[] temp = pen.split(newString);
String fileName = temp[3];
Log.e("fileName",temp[3]);
//获取文件大小
FileInputStream fst = null;
try {
fst = new FileInputStream(f.getPath());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
fileSize = fst.available();
} catch (IOException e) {
e.printStackTrace();
}
//执行异步上传提交
asyncSendTempFiles(URLPath+"&task_id="+temp[0]+"&fileSize="+fileSize,f.getPath(),fileName,buffer,0,Integer.parseInt(temp[1]),Integer.parseInt(temp[2]),pWebview,CallBackID);
}
}
public void asyncSendTempFiles(final String urlPath, final String filePath, final String fileName, final byte[] buffer, final int count, final int allLength, final int nowCount, final IWebview pWebview, final String CallBackID){
AsyncTask<String, Void, String> execute = new AsyncTask<String, Void, String>() {
public void execute(String urlPath, String filePath, String fileName, byte[] buffer, int count, int allLength, int nowCount) {
}
@Override
protected String doInBackground(String... params) {
java.net.HttpURLConnection connection = null;
try {
Log.e("urlPath",urlPath+"&allLength="+allLength+"&nowCount="+nowCount+"&fileName="+URLEncoder.encode(fileName, "UTF-8"));
URL url = new URL(urlPath+"&allLength="+allLength+"&nowCount="+nowCount+"&fileName="+URLEncoder.encode(fileName, "UTF-8"));
connection = (java.net.HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setDoOutput(true);
FileInputStream is = new FileInputStream(filePath);
byte[] b = new byte[is.available()];
Log.e("available",is.available()+"");
is.read(b);
OutputStream os = connection.getOutputStream();
os.write(b);
os.flush();
os.close();
if(connection.getResponseCode() == 200){
Log.e("ResponseMessage",connection.getResponseMessage());
return changeInputStream(connection.getInputStream(),"UTF-8");
}else{
}
} catch (IOException e) {
Log.e("urlPath","url error");
e.printStackTrace();
}
return "";
}
protected void onPostExecute(String result) {
Log.e("result",result);
try {
JSONObject jsonObject = new JSONObject(result);
//int resultCode = jsonObject.getInt("resultcode");
String data = jsonObject.getString("status");
Log.e("result-data",data);
if(data == "0"){
//传输成功 删除当前文件
File file=new File(filePath);
//文件是否存在
if(file.exists())
{
file.delete();
Log.e("result-data","文件已经被删除了");
}
}
} catch (JSONException e) {
Log.e("result",result);
e.printStackTrace();
}
// JSONArray newArray = new JSONArray();
// newArray.put(result);
// JSUtil.execCallback(pWebview, CallBackID, newArray, JSUtil.OK, true);
}
}.execute();
}
/**
* 将一个输入流转换成指定编码的字符串
*
* @param inputStream
* @param encode
* @return
*/
private static String changeInputStream(InputStream inputStream,
String encode) {
// 内存流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int len = 0;
String result = null;
if (inputStream != null) {
try {
while ((len = inputStream.read(data)) != -1) {
byteArrayOutputStream.write(data, 0, len);
}
result = new String(byteArrayOutputStream.toByteArray(), encode);
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
收起阅读 »

【公告】关于HBuilder 8.1.2不能正常启动,Android平台地图滑动卡顿、地图POI搜索后不显示数据等问题的解决办法
IDE
HBuilder不能正常启动
HBuilder启动时长时间停留在启动界面或闪退。
Android
Android平台地图滑动卡顿
Android平台下,创建plus.maps.Map控件时,不设置position参数默认使用static,会使得地图控件滑动非常卡顿,影响使用
Android平台修复地图POI搜索后不显示数据的问题
Android平台下,plus.maps.Map控件中搜索地点后数据不能正确标识在地图
解决办法
8.1.3及以上版本的HBuilder已修复以上问题,请更新或下载最新版HBuilder。
IDE
HBuilder不能正常启动
HBuilder启动时长时间停留在启动界面或闪退。
Android
Android平台地图滑动卡顿
Android平台下,创建plus.maps.Map控件时,不设置position参数默认使用static,会使得地图控件滑动非常卡顿,影响使用
Android平台修复地图POI搜索后不显示数据的问题
Android平台下,plus.maps.Map控件中搜索地点后数据不能正确标识在地图
解决办法
8.1.3及以上版本的HBuilder已修复以上问题,请更新或下载最新版HBuilder。
收起阅读 »
HBuilder 工具条插件 新手必备插件 【终身免费的】
HBuilder 工具条插件 新手必备插件
管理大大 觉得可以给加个精哦~!
功能:
1、集成常用网页开发手册 php js css jq 等
PHP超级手册【核心功能: 直接将常用近千个常用PHP命令汉化中文 解决很多新手小白 知道某些函数功能 但是苦于不知道是哪个命令 去百度搜索又不能很快的找到说明 那么此功能就帮助很大了 你只要知道你需要写的功能的大概汉语意思 就可以直接定位搜索出 英文函数命令哦】
2、工具 集成了常用的一些计算机工具 省却了在开发途中需要打开某些东西影响效率
3、编码 集成常用的一些文本编码换算 适合快速操作。
安装:
直接解压覆盖到HBuilder 根目录覆盖即可
请将此文件直接复制到 HBuilder安装根目录下。 直接替换。
启动办法:F10 或者HOME都可以呼出 呼出区别 F10 不吸附窗体 HOME键 吸附内嵌到HBuilder软件工具条
拖放移动:本软件上述两种模式均支持随意移动 鼠标移动到绿色工具条顶部边缘 鼠标按着不放 可以随意移动
作者:九六重生
QQ:14434001
作者官网:96wk.com
祝您使用愉悦!
下面贴上插件部分截图 喜欢的就下载吧
插件下载见附件 最底部哦
HBuilder 工具条插件 新手必备插件
管理大大 觉得可以给加个精哦~!
功能:
1、集成常用网页开发手册 php js css jq 等
PHP超级手册【核心功能: 直接将常用近千个常用PHP命令汉化中文 解决很多新手小白 知道某些函数功能 但是苦于不知道是哪个命令 去百度搜索又不能很快的找到说明 那么此功能就帮助很大了 你只要知道你需要写的功能的大概汉语意思 就可以直接定位搜索出 英文函数命令哦】
2、工具 集成了常用的一些计算机工具 省却了在开发途中需要打开某些东西影响效率
3、编码 集成常用的一些文本编码换算 适合快速操作。
安装:
直接解压覆盖到HBuilder 根目录覆盖即可
请将此文件直接复制到 HBuilder安装根目录下。 直接替换。
启动办法:F10 或者HOME都可以呼出 呼出区别 F10 不吸附窗体 HOME键 吸附内嵌到HBuilder软件工具条
拖放移动:本软件上述两种模式均支持随意移动 鼠标移动到绿色工具条顶部边缘 鼠标按着不放 可以随意移动
作者:九六重生
QQ:14434001
作者官网:96wk.com
祝您使用愉悦!
下面贴上插件部分截图 喜欢的就下载吧
插件下载见附件 最底部哦
收起阅读 »
【5+】跨webview多页面 触发事件
本文源地址:https://segmentfault.com/a/1190000008844889
在日常撸功能中,很多情况都需要用到通知页面,mui呢给我们已经内置写好啦,当当当,就是 mui.fire
我们来看看之前所写的用法
mui.fire
耶?这时候有童鞋就会问了,咋了之前不是写了mui.fire的文章了吗?为啥又有了这一篇捏?
哈哈,这篇文章我们主要来讲解5+的实现方案,不用mui.fire,就相当于自己写一个通知的js功能,让大家更明白其原理,以及更好地不止是拘束于非得用到mui.js
原理介绍
关键词
- plus.webview.evalJS
- dispatchEvent
在B页面通知A页面,我们暂时不管通知A页面的内容,只是希望B页面调用一段代码,能让A页面弹出一个alert
这时候我们就要用到webview的evalJS方法了
A.html
<header class="mui-bar mui-bar-nav">
<h1 class="mui-title">我是A页面</h1>
</header>
<div class="mui-content">
<button type="button" class="mui-btn mui-btn-blue">打开B页面</button>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript">
mui.init()
mui.plusReady(function(){
document.querySelector("button").addEventListener('tap',function(){
mui.openWindow('B.html')
})
})
</script>
B.html
<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">
<button type="button" class="mui-btn mui-btn-blue">通知A页面</button>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript">
mui.init()
mui.plusReady(function(){
document.querySelector("button").addEventListener('tap',function(){
// 通知A页面的方法
})
})
</script>
那么,怎么才能通知A弹出框呢?我们需要用到关键词所提到的 plus.webview.evalJS
嘿嘿, 我们现在B获取到A的Webview对象,然后通过evalJS来向A页面发送一段代码让其执行
// 通知A页面的方法
var A = plus.webview.getLaunchWebview()
A.evalJS('alert("我是被B的")')
点击一下按钮,果不其然,我们的弹出框就显示出来,当然我们也还可以定义其它的函数来接收响应
A
function faqme(){
alert('啊,乖乖站好!')
}
B
// 通知A页面的方法
var A = plus.webview.getLaunchWebview()
A.evalJS('faqme()')
当然,A页面执行了faqme函数,弹出了乖乖站好
其实,mui.fire的内部实现就是其原理
我们可以看一下其代码
这个 dispatchEvent 是什么呢?
我们可以将这个方法理解为用来触发dom事件
相关详细文档:
事件触发器-----dispatchEvent
这下条理就很清楚拉!
A页面自定义事件 => B页面触发A页面事件回调并传参
嘿嘿,就是这么简单,但是本文章还没有结束,既然都到这了,干脆我们来自己封装一下这个通知功能吧!
造轮子
我们新建一个文件,美其名曰:Broadcast.js
在这里我采用ES6 Class的方式编写
//页面通知
class Broadcast{
/**
* 构造器函数
*/
constructor(){
}
}
我们先来实现最基础的两个功能
- 监听事件(订阅)
- 触发事件(发布)
//页面通知
class Broadcast{
/**
* 构造器函数
*/
constructor(){
}
/**
* 事件监听
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
* @return {Broadcast} this
*/
on(eventName, callback){
document.addEventListener(eventName, e => {
callback.call(e, e.detail)
})
return this
}
/**
* 事件触发
* @param {String} eventName 事件名称
* @param {Object} data 参数
* @return {Broadcast} this
*/
emit(eventName, data){
// 获取所有的webview
var all = plus.webview.all()
// 遍历全部页面
for(var w in all){
// 挨个来evalJS
all[w].evalJS(`document.dispatchEvent(new CustomEvent('${eventName}', {
detail:JSON.parse('${JSON.stringify(data)}'),
bubbles: true,
cancelable: true
}));`)
}
return this
}
}
ok, 我们在页面中引用并尝试用一下
A
<header class="mui-bar mui-bar-nav">
<h1 class="mui-title">我是A页面</h1>
</header>
<div class="mui-content">
<button type="button" class="mui-btn mui-btn-blue">打开B页面</button>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript" src="js/Broadcast.js" ></script>
<script type="text/javascript">
mui.init()
mui.plusReady(function(){
document.querySelector("button").addEventListener('tap',function(){
mui.openWindow('B.html')
})
})
new Broadcast().on('say', function(data){
alert(JSON.stringify(data))
})
</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">
<button type="button" class="mui-btn mui-btn-blue">通知A页面</button>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript" src="js/Broadcast.js" ></script>
<script type="text/javascript">
mui.init()
mui.plusReady(function(){
document.querySelector("button").addEventListener('tap',function(){
// 通知A页面的方法
//var A = plus.webview.getLaunchWebview()
//A.evalJS('alert("我是被B的")')
new Broadcast().emit('say', {
from: '我是B啊',
id: 666
})
})
})
</script>
点击B页面的按钮
哇哈哈,基础功能已经实现了怎么样,
当然,这只是最基础的实现了监听,触发而已,后续还需要更多的优化,以及管理,辣么,下章见
上一章我们了解到通过webview evalJS的方法来跨页面通知事件,但是在其中还是有需要优化的地方,接下来我们慢慢的来分析。
上节回顾:【5+】跨webview多页面 触发事件(一)
代码:
//页面通知
class Broadcast{
/**
* 构造器函数
*/
constructor(){
}
/**
* 事件监听
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
* @return {Broadcast} this
*/
on(eventName, callback){
document.addEventListener(eventName, e => {
callback.call(e, e.detail)
})
return this
}
/**
* 事件触发
* @param {String} eventName 事件名称
* @param {Object} data 参数
* @return {Broadcast} this
*/
emit(eventName, data){
// 获取所有的webview
var all = plus.webview.all()
// 遍历全部页面
for(var w in all){
// 挨个来evalJS
all[w].evalJS(`document.dispatchEvent(new CustomEvent('${eventName}', {
detail:JSON.parse('${JSON.stringify(data)}'),
bubbles: true,
cancelable: true
}));`)
}
return this
}
}
自定义需要通知页面
可以看到,之前我们emit发送通知时,是对所有的webview进行获取通知,但是有时候我们并不想通知所有的页面,而且通知别人的时候也不想通知自己啊,怎么办,在这里我们在emit方法参数多加一个配置项
/**
* 事件触发
* @param {String} eventName 事件名称
* @param {Object} data 传参参数值
* @param {Object} options 其它配置参数
*/
emit(eventName, data, {
self = false, // 是否通知自己,默认不通知
views = [], // 为空数组时,默认通知全部,为string数组时,认为是id,为object时,认为是webview对象
} = {}) {
//code...
}
然后我们针对传进来的拓展参数,进行逻辑判断,得到最终我们需要通知的webview list
/**
* 事件触发
* @param {String} eventName 事件名称
* @param {Object} data 传参参数值
* @param {Object} options 其它配置参数
*/
emit(eventName, data, {
self = false, // 是否通知自己,默认不通知
views = [], // 为空数组时,默认通知全部,为string数组时,认为是id,为object时,认为是webview对象
} = {}) {
let all = []
// 获取 特定 webview 数组
if(views.length > 0) {
// 如果是string 类型,则统一处理获取为 webview对象
all.map(item => typeof item === 'string' ? plus.webview.getWebviewById(item) : item)
} else {
// 不特定通知的webview数组时,直接获取全部已存在的webview
all = plus.webview.all()
}
// 如果不需要通知到当前webview 则过滤
if(!self) {
let v = plus.webview.currentWebview()
all = all.filter(item => item.id !== v.id)
}
// 遍历所有需要通知的页面
for(let v of all) {
v.evalJS(`document.dispatchEvent(new CustomEvent('${eventName}', {
detail:JSON.parse('${JSON.stringify(data)}'),
bubbles: true,
cancelable: true
}));`)
}
}
如何调用
new Broadcast().emit('say',{
name: 'newsning',
age: 26
},{
self: true, // 通知当前页面 默认不通知
views: ['A.html','C.html'] // 默认通知所有页面,但不包括当前页面
})
// 如上代码就只通知到了3个页面, 当前页面, A页面, C页面
事件 - [ 订阅 | 发布 | 取消 ]
如果你遇到那种还需要移除监听事件,亦或者Once只监听一次的事件,再或是你看个代码不爽
ok!我们来撸一套简单的 守望先锋模式,哦不,是观察者模式
事件订阅
瞧瞧我们之前的代码,on方法是直接把传进来的函数作为调用,这样子在外部调用时移除事件就没路子了,包括Once也很是蛋疼
/**
* 事件监听
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
* @return {Broadcast} this
*/
on(eventName, callback){
document.addEventListener(eventName, e => {
callback.call(e, e.detail)
})
return this
}
我们先来定义好2个专门放置事件的存储对象,碧如 :
// 事件列表
const events = {
// 事件名称 : 事件方法数组
},
// 单次事件列表
events_one = {
}
之后我们修改一下on方法,并新增一个once方法
/**
* 事件监听
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
*/
on(eventName, callback) {
// 获取已存在的事件列表
if(!events[eventName]) {
events[eventName] = []
}
// 添加至数组
events[eventName].push(callback)
}
/**
* 事件监听 (单次)
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
*/
once(eventName, callback) {
// 获取已存在的单次事件列表
if(!events_one[eventName]) {
events_one[eventName] = []
}
// 添加至数组
events_one[eventName].push(callback)
}
酱紫,每次添加事件时,都会放入我们的事件列表中,但是!我们并没有给任何dom添加事件,而仅仅是放入所对应的事件列表中,奇怪了,看看我们之前的添加事件方法
给document监听一个事件
触发document事件
nonono , 我们不这么借助document亦或者其它dom的事件监听,还记得上一章的 evalJS('faqme()')么?我们就用亲切的函数来触发事件
事件发布
在事件订阅当中,我们仅仅只是把事件放入了事件列表中,我们该如何触发?
编写一个静态方法,用来触发当前页面的事件, 然后通过
static _emitSelf(eventName, data) {
if(typeof data === 'string') {
data = JSON.parse(data)
}
// 获取全部事件列表 和 单次事件列表,并且合并
let es = [...(events[eventName] || []), ...(events_one[eventName] || [])]
// 遍历触发
for(let f of es) {
f && f.call(f, data)
}
// 单次事件清空
events_one[eventName] = []
}
再配合修改一下 emit 里面的 evalJS
/**
* 事件触发
* @param {String} eventName 事件名称
* @param {Object} data 传参参数值
* @param {Object} options 其它配置参数
*/
emit(eventName, data, {
self = false, // 是否通知自己,默认不通知
views = [], // 为空数组时,默认通知全部,为string数组时,认为是id,为object时,认为是webview对象
} = {}) {
let all = []
// 获取 特定 webview 数组
if(views.length > 0) {
// 如果是string 类型,则统一处理获取为 webview对象
all.map(item => typeof item === 'string' ? plus.webview.getWebviewById(item) : item)
} else {
// 不特定通知的webview数组时,直接获取全部已存在的webview
all = plus.webview.all()
}
// 如果不需要通知到当前webview 则过滤
if(!self) {
let v = plus.webview.currentWebview()
all = all.filter(item => item.id !== v.id)
}
// 遍历所有需要通知的页面
for(let v of all) {
/////////////////////////
////////////////这里是重点, 调用Broadcast的静态方法
/////////////////////////
v.evalJS(`Broadcast && Broadcast._emitSelf && Broadcast._emitSelf('${eventName}', '${JSON.stringify(data)}')`)
}
}
这样子,就巧妙的触发了每个webview页面 相对应的事件,并且单次事件也得到了清除
事件移除
我们知道前面的事件订阅只是将事件存起来了,事件移除相应的就是把事件列表清空
static _offSelf(eventName) {
//清空事件列表
events[eventName] = []
events_one[eventName] = []
}
最后收尾
所定义的2个静态方法,触发 和 移除 事件,我们在内部代理2个相应的方法
/**
* 当前页面事件触发
* @param {String} eventName 事件名称
* @param {Object} data 传参参数值
*/
emitSelf(eventName) {
Broadcast._emitSelf(eventName, data)
}
/**
* 清空当前页面事件
* @param {String} eventName 事件名称
*/
offSelf(eventName) {
Broadcast._offSelf(eventName)
}
最后,成果已经出现
A.html
var b = new Broadcast()
b.on('say', function(data){
alert(JSON.stringify(data))
// 删除本页面say事件
//b.offSelf('say')
})
b.once('say', function(data){
//单次
alert('单次:'+JSON.stringify(data))
})
B.html
new Broadcast().emit('say', {
from: '我是B啊',
id: 666
})
最后附上源码:
/**
* 5+ Broadcast.js by NewsNing 宁大大
*/
// 获取当前webview
const getIndexView = (() => {
// 缓存
let indexView = null
return(update = false) => {
if(update || indexView === null) {
indexView = plus.webview.currentWebview()
}
return indexView
}
})(),
// 获取全部webview
getAllWebview = (() => {
// 缓存
let allView = null
return(update = false) => {
if(update || allView === null) {
allView = plus.webview.all()
}
return allView
}
})()
// 事件列表
const events = {
},
// 单次事件列表
events_one = {
}
//页面通知类
class Broadcast {
/**
* 构造器函数
*/
constructor() {
}
/**
* 事件监听
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
*/
on(eventName, callback) {
// 获取已存在的事件列表
if(!events[eventName]) {
events[eventName] = []
}
// 添加至数组
events[eventName].push(callback)
}
/**
* 事件监听 (单次)
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
*/
once(eventName, callback) {
// 获取已存在的单次事件列表
if(!events_one[eventName]) {
events_one[eventName] = []
}
// 添加至数组
events_one[eventName].push(callback)
}
/**
* 事件触发
* @param {String} eventName 事件名称
* @param {Object} data 传参参数值
* @param {Object} options 其它配置参数
*/
emit(eventName, data, {
self = false, // 是否通知自己,默认不通知
views = [], // 为空数组时,默认通知全部,为string数组时,认为是id,为object时,认为是webview对象
} = {}) {
let jsstr = `Broadcast && Broadcast._emitSelf && Broadcast._emitSelf('${eventName}', '${JSON.stringify(data)}')`
this._sendMessage(jsstr, self, views)
}
/**
* 当前页面事件触发
* @param {String} eventName 事件名称
* @param {Object} data 传参参数值
*/
emitSelf(eventName) {
Broadcast._emitSelf(eventName, data)
}
/**
* 事件关闭移除
* @param {String} eventName 事件名称
* @param {Object} options 其它配置参数
*/
off(eventName, {
self = false, // 是否通知自己,默认不通知
views = [] // 为空数组时,默认通知全部,为string数组时,认为是id,为object时,认为是webview对象
} = {}) {
let jsstr = `Broadcast && Broadcast._offSelf && Broadcast._offSelf('${eventName}')`
this._sendMessage(jsstr, self, views)
}
/**
* 清空当前页面事件
* @param {String} eventName 事件名称
*/
offSelf(eventName) {
Broadcast._offSelf(eventName)
}
/**
* 页面通知
* @param {String} jsstr 需要运行的js代码
* @param {Boolean} self 是否通知自己,默认不通知
* @param {Array} views 为空数组时,默认通知全部,为string数组时,认为是id,为object时,认为是webview对象
*/
_sendMessage(
jsstr = '',
self = false,
views = []
) {
let all = []
// 获取 特定 webview 数组
if(views.length > 0) {
// 如果是string 类型,则统一处理获取为 webview对象
all.map(item => typeof item === 'string' ? plus.webview.getWebviewById(item) : item)
} else {
// 不特定通知的webview数组时,直接获取全部已存在的webview
all = getAllWebview(true)
}
// 如果不需要通知到当前webview 则过滤
if(!self) {
let v = getIndexView()
all = all.filter(item => item.id !== v.id)
}
// 遍历全部页面
for(let v of all) {
v.evalJS(jsstr)
}
}
static _emitSelf(eventName, data) {
if(typeof data === 'string') {
data = JSON.parse(data)
}
// 获取全部事件列表 和 单次事件列表,并且合并
let es = [...(events[eventName] || []), ...(events_one[eventName] || [])]
// 遍历触发
for(let f of es) {
f && f.call(f, data)
}
// 单次事件清空
events_one[eventName] = []
}
static _offSelf(eventName) {
//清空事件列表
events[eventName] = []
events_one[eventName] = []
}
}
您也可以通过babel在线转化成es5 在线转换地址
最后您还可以在github上看到一些其它5+ Api封装的源码 [5+ api整合]
https://github.com/NewsNIng/ni
class Man{
constructor(){
this.name = 'newsning'
}
say(){
console.log('天行健, 君子以自强不息. ')
}
}
本文源地址:https://segmentfault.com/a/1190000008844889
在日常撸功能中,很多情况都需要用到通知页面,mui呢给我们已经内置写好啦,当当当,就是 mui.fire
我们来看看之前所写的用法
mui.fire
耶?这时候有童鞋就会问了,咋了之前不是写了mui.fire的文章了吗?为啥又有了这一篇捏?
哈哈,这篇文章我们主要来讲解5+的实现方案,不用mui.fire,就相当于自己写一个通知的js功能,让大家更明白其原理,以及更好地不止是拘束于非得用到mui.js
原理介绍
关键词
- plus.webview.evalJS
- dispatchEvent
在B页面通知A页面,我们暂时不管通知A页面的内容,只是希望B页面调用一段代码,能让A页面弹出一个alert
这时候我们就要用到webview的evalJS方法了
A.html
<header class="mui-bar mui-bar-nav">
<h1 class="mui-title">我是A页面</h1>
</header>
<div class="mui-content">
<button type="button" class="mui-btn mui-btn-blue">打开B页面</button>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript">
mui.init()
mui.plusReady(function(){
document.querySelector("button").addEventListener('tap',function(){
mui.openWindow('B.html')
})
})
</script>
B.html
<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">
<button type="button" class="mui-btn mui-btn-blue">通知A页面</button>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript">
mui.init()
mui.plusReady(function(){
document.querySelector("button").addEventListener('tap',function(){
// 通知A页面的方法
})
})
</script>
那么,怎么才能通知A弹出框呢?我们需要用到关键词所提到的 plus.webview.evalJS
嘿嘿, 我们现在B获取到A的Webview对象,然后通过evalJS来向A页面发送一段代码让其执行
// 通知A页面的方法
var A = plus.webview.getLaunchWebview()
A.evalJS('alert("我是被B的")')
点击一下按钮,果不其然,我们的弹出框就显示出来,当然我们也还可以定义其它的函数来接收响应
A
function faqme(){
alert('啊,乖乖站好!')
}
B
// 通知A页面的方法
var A = plus.webview.getLaunchWebview()
A.evalJS('faqme()')
当然,A页面执行了faqme函数,弹出了乖乖站好
其实,mui.fire的内部实现就是其原理
我们可以看一下其代码
这个 dispatchEvent 是什么呢?
我们可以将这个方法理解为用来触发dom事件
相关详细文档:
事件触发器-----dispatchEvent
这下条理就很清楚拉!
A页面自定义事件 => B页面触发A页面事件回调并传参
嘿嘿,就是这么简单,但是本文章还没有结束,既然都到这了,干脆我们来自己封装一下这个通知功能吧!
造轮子
我们新建一个文件,美其名曰:Broadcast.js
在这里我采用ES6 Class的方式编写
//页面通知
class Broadcast{
/**
* 构造器函数
*/
constructor(){
}
}
我们先来实现最基础的两个功能
- 监听事件(订阅)
- 触发事件(发布)
//页面通知
class Broadcast{
/**
* 构造器函数
*/
constructor(){
}
/**
* 事件监听
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
* @return {Broadcast} this
*/
on(eventName, callback){
document.addEventListener(eventName, e => {
callback.call(e, e.detail)
})
return this
}
/**
* 事件触发
* @param {String} eventName 事件名称
* @param {Object} data 参数
* @return {Broadcast} this
*/
emit(eventName, data){
// 获取所有的webview
var all = plus.webview.all()
// 遍历全部页面
for(var w in all){
// 挨个来evalJS
all[w].evalJS(`document.dispatchEvent(new CustomEvent('${eventName}', {
detail:JSON.parse('${JSON.stringify(data)}'),
bubbles: true,
cancelable: true
}));`)
}
return this
}
}
ok, 我们在页面中引用并尝试用一下
A
<header class="mui-bar mui-bar-nav">
<h1 class="mui-title">我是A页面</h1>
</header>
<div class="mui-content">
<button type="button" class="mui-btn mui-btn-blue">打开B页面</button>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript" src="js/Broadcast.js" ></script>
<script type="text/javascript">
mui.init()
mui.plusReady(function(){
document.querySelector("button").addEventListener('tap',function(){
mui.openWindow('B.html')
})
})
new Broadcast().on('say', function(data){
alert(JSON.stringify(data))
})
</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">
<button type="button" class="mui-btn mui-btn-blue">通知A页面</button>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript" src="js/Broadcast.js" ></script>
<script type="text/javascript">
mui.init()
mui.plusReady(function(){
document.querySelector("button").addEventListener('tap',function(){
// 通知A页面的方法
//var A = plus.webview.getLaunchWebview()
//A.evalJS('alert("我是被B的")')
new Broadcast().emit('say', {
from: '我是B啊',
id: 666
})
})
})
</script>
点击B页面的按钮
哇哈哈,基础功能已经实现了怎么样,
当然,这只是最基础的实现了监听,触发而已,后续还需要更多的优化,以及管理,辣么,下章见
上一章我们了解到通过webview evalJS的方法来跨页面通知事件,但是在其中还是有需要优化的地方,接下来我们慢慢的来分析。
上节回顾:【5+】跨webview多页面 触发事件(一)
代码:
//页面通知
class Broadcast{
/**
* 构造器函数
*/
constructor(){
}
/**
* 事件监听
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
* @return {Broadcast} this
*/
on(eventName, callback){
document.addEventListener(eventName, e => {
callback.call(e, e.detail)
})
return this
}
/**
* 事件触发
* @param {String} eventName 事件名称
* @param {Object} data 参数
* @return {Broadcast} this
*/
emit(eventName, data){
// 获取所有的webview
var all = plus.webview.all()
// 遍历全部页面
for(var w in all){
// 挨个来evalJS
all[w].evalJS(`document.dispatchEvent(new CustomEvent('${eventName}', {
detail:JSON.parse('${JSON.stringify(data)}'),
bubbles: true,
cancelable: true
}));`)
}
return this
}
}
自定义需要通知页面
可以看到,之前我们emit发送通知时,是对所有的webview进行获取通知,但是有时候我们并不想通知所有的页面,而且通知别人的时候也不想通知自己啊,怎么办,在这里我们在emit方法参数多加一个配置项
/**
* 事件触发
* @param {String} eventName 事件名称
* @param {Object} data 传参参数值
* @param {Object} options 其它配置参数
*/
emit(eventName, data, {
self = false, // 是否通知自己,默认不通知
views = [], // 为空数组时,默认通知全部,为string数组时,认为是id,为object时,认为是webview对象
} = {}) {
//code...
}
然后我们针对传进来的拓展参数,进行逻辑判断,得到最终我们需要通知的webview list
/**
* 事件触发
* @param {String} eventName 事件名称
* @param {Object} data 传参参数值
* @param {Object} options 其它配置参数
*/
emit(eventName, data, {
self = false, // 是否通知自己,默认不通知
views = [], // 为空数组时,默认通知全部,为string数组时,认为是id,为object时,认为是webview对象
} = {}) {
let all = []
// 获取 特定 webview 数组
if(views.length > 0) {
// 如果是string 类型,则统一处理获取为 webview对象
all.map(item => typeof item === 'string' ? plus.webview.getWebviewById(item) : item)
} else {
// 不特定通知的webview数组时,直接获取全部已存在的webview
all = plus.webview.all()
}
// 如果不需要通知到当前webview 则过滤
if(!self) {
let v = plus.webview.currentWebview()
all = all.filter(item => item.id !== v.id)
}
// 遍历所有需要通知的页面
for(let v of all) {
v.evalJS(`document.dispatchEvent(new CustomEvent('${eventName}', {
detail:JSON.parse('${JSON.stringify(data)}'),
bubbles: true,
cancelable: true
}));`)
}
}
如何调用
new Broadcast().emit('say',{
name: 'newsning',
age: 26
},{
self: true, // 通知当前页面 默认不通知
views: ['A.html','C.html'] // 默认通知所有页面,但不包括当前页面
})
// 如上代码就只通知到了3个页面, 当前页面, A页面, C页面
事件 - [ 订阅 | 发布 | 取消 ]
如果你遇到那种还需要移除监听事件,亦或者Once只监听一次的事件,再或是你看个代码不爽
ok!我们来撸一套简单的 守望先锋模式,哦不,是观察者模式
事件订阅
瞧瞧我们之前的代码,on方法是直接把传进来的函数作为调用,这样子在外部调用时移除事件就没路子了,包括Once也很是蛋疼
/**
* 事件监听
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
* @return {Broadcast} this
*/
on(eventName, callback){
document.addEventListener(eventName, e => {
callback.call(e, e.detail)
})
return this
}
我们先来定义好2个专门放置事件的存储对象,碧如 :
// 事件列表
const events = {
// 事件名称 : 事件方法数组
},
// 单次事件列表
events_one = {
}
之后我们修改一下on方法,并新增一个once方法
/**
* 事件监听
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
*/
on(eventName, callback) {
// 获取已存在的事件列表
if(!events[eventName]) {
events[eventName] = []
}
// 添加至数组
events[eventName].push(callback)
}
/**
* 事件监听 (单次)
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
*/
once(eventName, callback) {
// 获取已存在的单次事件列表
if(!events_one[eventName]) {
events_one[eventName] = []
}
// 添加至数组
events_one[eventName].push(callback)
}
酱紫,每次添加事件时,都会放入我们的事件列表中,但是!我们并没有给任何dom添加事件,而仅仅是放入所对应的事件列表中,奇怪了,看看我们之前的添加事件方法
给document监听一个事件
触发document事件
nonono , 我们不这么借助document亦或者其它dom的事件监听,还记得上一章的 evalJS('faqme()')么?我们就用亲切的函数来触发事件
事件发布
在事件订阅当中,我们仅仅只是把事件放入了事件列表中,我们该如何触发?
编写一个静态方法,用来触发当前页面的事件, 然后通过
static _emitSelf(eventName, data) {
if(typeof data === 'string') {
data = JSON.parse(data)
}
// 获取全部事件列表 和 单次事件列表,并且合并
let es = [...(events[eventName] || []), ...(events_one[eventName] || [])]
// 遍历触发
for(let f of es) {
f && f.call(f, data)
}
// 单次事件清空
events_one[eventName] = []
}
再配合修改一下 emit 里面的 evalJS
/**
* 事件触发
* @param {String} eventName 事件名称
* @param {Object} data 传参参数值
* @param {Object} options 其它配置参数
*/
emit(eventName, data, {
self = false, // 是否通知自己,默认不通知
views = [], // 为空数组时,默认通知全部,为string数组时,认为是id,为object时,认为是webview对象
} = {}) {
let all = []
// 获取 特定 webview 数组
if(views.length > 0) {
// 如果是string 类型,则统一处理获取为 webview对象
all.map(item => typeof item === 'string' ? plus.webview.getWebviewById(item) : item)
} else {
// 不特定通知的webview数组时,直接获取全部已存在的webview
all = plus.webview.all()
}
// 如果不需要通知到当前webview 则过滤
if(!self) {
let v = plus.webview.currentWebview()
all = all.filter(item => item.id !== v.id)
}
// 遍历所有需要通知的页面
for(let v of all) {
/////////////////////////
////////////////这里是重点, 调用Broadcast的静态方法
/////////////////////////
v.evalJS(`Broadcast && Broadcast._emitSelf && Broadcast._emitSelf('${eventName}', '${JSON.stringify(data)}')`)
}
}
这样子,就巧妙的触发了每个webview页面 相对应的事件,并且单次事件也得到了清除
事件移除
我们知道前面的事件订阅只是将事件存起来了,事件移除相应的就是把事件列表清空
static _offSelf(eventName) {
//清空事件列表
events[eventName] = []
events_one[eventName] = []
}
最后收尾
所定义的2个静态方法,触发 和 移除 事件,我们在内部代理2个相应的方法
/**
* 当前页面事件触发
* @param {String} eventName 事件名称
* @param {Object} data 传参参数值
*/
emitSelf(eventName) {
Broadcast._emitSelf(eventName, data)
}
/**
* 清空当前页面事件
* @param {String} eventName 事件名称
*/
offSelf(eventName) {
Broadcast._offSelf(eventName)
}
最后,成果已经出现
A.html
var b = new Broadcast()
b.on('say', function(data){
alert(JSON.stringify(data))
// 删除本页面say事件
//b.offSelf('say')
})
b.once('say', function(data){
//单次
alert('单次:'+JSON.stringify(data))
})
B.html
new Broadcast().emit('say', {
from: '我是B啊',
id: 666
})
最后附上源码:
/**
* 5+ Broadcast.js by NewsNing 宁大大
*/
// 获取当前webview
const getIndexView = (() => {
// 缓存
let indexView = null
return(update = false) => {
if(update || indexView === null) {
indexView = plus.webview.currentWebview()
}
return indexView
}
})(),
// 获取全部webview
getAllWebview = (() => {
// 缓存
let allView = null
return(update = false) => {
if(update || allView === null) {
allView = plus.webview.all()
}
return allView
}
})()
// 事件列表
const events = {
},
// 单次事件列表
events_one = {
}
//页面通知类
class Broadcast {
/**
* 构造器函数
*/
constructor() {
}
/**
* 事件监听
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
*/
on(eventName, callback) {
// 获取已存在的事件列表
if(!events[eventName]) {
events[eventName] = []
}
// 添加至数组
events[eventName].push(callback)
}
/**
* 事件监听 (单次)
* @param {String} eventName 事件名称
* @param {Function} callback 事件触发后执行的回调函数
*/
once(eventName, callback) {
// 获取已存在的单次事件列表
if(!events_one[eventName]) {
events_one[eventName] = []
}
// 添加至数组
events_one[eventName].push(callback)
}
/**
* 事件触发
* @param {String} eventName 事件名称
* @param {Object} data 传参参数值
* @param {Object} options 其它配置参数
*/
emit(eventName, data, {
self = false, // 是否通知自己,默认不通知
views = [], // 为空数组时,默认通知全部,为string数组时,认为是id,为object时,认为是webview对象
} = {}) {
let jsstr = `Broadcast && Broadcast._emitSelf && Broadcast._emitSelf('${eventName}', '${JSON.stringify(data)}')`
this._sendMessage(jsstr, self, views)
}
/**
* 当前页面事件触发
* @param {String} eventName 事件名称
* @param {Object} data 传参参数值
*/
emitSelf(eventName) {
Broadcast._emitSelf(eventName, data)
}
/**
* 事件关闭移除
* @param {String} eventName 事件名称
* @param {Object} options 其它配置参数
*/
off(eventName, {
self = false, // 是否通知自己,默认不通知
views = [] // 为空数组时,默认通知全部,为string数组时,认为是id,为object时,认为是webview对象
} = {}) {
let jsstr = `Broadcast && Broadcast._offSelf && Broadcast._offSelf('${eventName}')`
this._sendMessage(jsstr, self, views)
}
/**
* 清空当前页面事件
* @param {String} eventName 事件名称
*/
offSelf(eventName) {
Broadcast._offSelf(eventName)
}
/**
* 页面通知
* @param {String} jsstr 需要运行的js代码
* @param {Boolean} self 是否通知自己,默认不通知
* @param {Array} views 为空数组时,默认通知全部,为string数组时,认为是id,为object时,认为是webview对象
*/
_sendMessage(
jsstr = '',
self = false,
views = []
) {
let all = []
// 获取 特定 webview 数组
if(views.length > 0) {
// 如果是string 类型,则统一处理获取为 webview对象
all.map(item => typeof item === 'string' ? plus.webview.getWebviewById(item) : item)
} else {
// 不特定通知的webview数组时,直接获取全部已存在的webview
all = getAllWebview(true)
}
// 如果不需要通知到当前webview 则过滤
if(!self) {
let v = getIndexView()
all = all.filter(item => item.id !== v.id)
}
// 遍历全部页面
for(let v of all) {
v.evalJS(jsstr)
}
}
static _emitSelf(eventName, data) {
if(typeof data === 'string') {
data = JSON.parse(data)
}
// 获取全部事件列表 和 单次事件列表,并且合并
let es = [...(events[eventName] || []), ...(events_one[eventName] || [])]
// 遍历触发
for(let f of es) {
f && f.call(f, data)
}
// 单次事件清空
events_one[eventName] = []
}
static _offSelf(eventName) {
//清空事件列表
events[eventName] = []
events_one[eventName] = []
}
}
您也可以通过babel在线转化成es5 在线转换地址
最后您还可以在github上看到一些其它5+ Api封装的源码 [5+ api整合]
https://github.com/NewsNIng/ni
class Man{
constructor(){
this.name = 'newsning'
}
say(){
console.log('天行健, 君子以自强不息. ')
}
}
收起阅读 »

咨询一下wap2app,能否支持打包成独立的app安装版本
如题,测试了一下,我们线下有很多客户,他们委托我们给他们开发了很多html5移动页面应用,可以在微信里面使用,现在他们希望能够转换成独立的app,我试用了你们的wap2app,发现只能打包成流应用,能够直接打包成独立app?
如题,测试了一下,我们线下有很多客户,他们委托我们给他们开发了很多html5移动页面应用,可以在微信里面使用,现在他们希望能够转换成独立的app,我试用了你们的wap2app,发现只能打包成流应用,能够直接打包成独立app?

Hbuilder集成微信支付教程(简单流程)
整个系统运作的流程大致是这样:
(1)APP 向 服务器 发出需要付款的请求
(2)服务器 请求 微信服务端 下单
(3)服务器 将下单数据回复给 APP
(4)APP 向微信服务端 发起请求并输入密码进行支付
关键字用加粗表示,APP指用户正在使用的APP,服务器指自己的业务服务器,微信服务端指微信端的服务器。
那整个流程具体怎么实现?请看下文,将会从申请接口开始讲述。
第一步
在浏览器新标签页中打开https://open.weixin.qq.com/,注册一个账号,并且审核开发者资质(个人或者是企业)。
创建一个APP移动应用,应用的开发信息需要填写完整,如下载页面地址、Bundle ID(IOS)和应用签名(Android)等。应用签名不要填错,怎么获取它可以网上搜索方法。
接下来为该应用申请微信支付,填写好相应的资料,等待审核成功。
第二步
申请成功后,邮箱会收到这么一封邮件。
用这封邮件上显示的账号密码,登录微信支付,地址是:https://pay.weixin.qq.com/index.php/core/home/login
把网页上提示需要设置的都设置好,需要的控件也都给它装上。最好使用IE浏览器登录微信支付,谷歌浏览器会出现问题,原因是它们的插件不是很兼容非IE浏览器。
API密钥可以先设置好,证书也可以先下载下来,后面会用到。
第三步
之前做支付宝接口的时候,这一步基本都是开始进行小额测试了,但是微信为了广大的开发者能够在真枪实弹之前先熟悉这一切,所以就增加了一个“验收”的过程(个人表示这一步略坑,文档写的不清楚,走了些弯路)。
验收的指引文档在这里:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_1
这个“验收”就是在实际支付交易之前,先进行一些虚拟的交易。交易过程同真实交易一样,也是先在APP上买东西,调用微信支付,然后付款,但是不用真正的付款,商户账号也不会收到钱。
千万别忘记,要先打开微信,关注“微信支付商户接入验收助手”,然后绑定自己的微信支付账号。
依次点击“验收case”->“app支付”->“APP支付验收用例”,就可看到完成“验收”过程需要哪些步骤了。
标注了“必选”的用例都要去做掉,“可选”的可以不用管它。
每个用例都规定了交易的金额,一定要按照这个金额来支付,否则不会成功。
第四步
“验收”其实就是把整个支付流程全部跑一遍,所以APP中要记得集成微信支付插件。
Hbuilder在云打包时会自动集成微信支付,只要在manifest.json的“SDK配置”中填写好相关信息就可以了。
原生APP需要自己去集成,具体方法就要自己看文档实现了。
服务端程序需要按照https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1文档中的API去实现,“验收”过程中,所有的URL地址都需要加上sandboxnew,而且API密钥不能用上文提到自己去填写的(这是验收结束后真枪实弹时用的),而是从https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey获取的,这些在验收指引文档中都有说明。
坑1提示:“验收”过程中,在调用微信客户端支付时,微信会提示APP ID没有绑定PAY SIGN KEY。其实这个时候已经算是支付成功了,别管它,直接点确定!
坑2提示:服务器从微信服务端获取到下单数据,要给APP回复时,如果用Hbuilder,其实回复的是一串JSON数据,别把XML数据回复过去了(会提示支付失败-1)。格式如下:
{“appid”:”应用APPID”,”noncestr”:”随机数”,”package”:”Sign=WXPay”,”partnerid”:”微信支付商户号”,”prepayid”:”XXXXXXXXXXXX”,”timestamp”:时间戳,”sign”:”签名”}
将XML数据转成以上的JSON数据回给APP就可以了,记得重新签名要重新生成!
第五步
每完成一个验收流程,都要去微信公众号的“我的验收”->“查询验收结果”->“查询用例接入结果”->“APP支付”中查看一下,确定是否成功。
等所有“必选”用例全部完成,那么恭喜你,验收完成。这时别再用验收时获取到的API密钥了,用自己填写的API密钥开始真枪实弹地小额测试一笔吧。
涉及到退款等资金回滚的API业务,微信支付要求使用证书(上文说要下载的)来验证安全,如果服务器用的PHP就在CURL中设置好证书地址,方法在微信支付文档中有。
微信支付相比支付宝支付有一点好处,就是退款后,微信支付会退回扣的千分之六手续费,而支付宝不会退。
整个系统运作的流程大致是这样:
(1)APP 向 服务器 发出需要付款的请求
(2)服务器 请求 微信服务端 下单
(3)服务器 将下单数据回复给 APP
(4)APP 向微信服务端 发起请求并输入密码进行支付
关键字用加粗表示,APP指用户正在使用的APP,服务器指自己的业务服务器,微信服务端指微信端的服务器。
那整个流程具体怎么实现?请看下文,将会从申请接口开始讲述。
第一步
在浏览器新标签页中打开https://open.weixin.qq.com/,注册一个账号,并且审核开发者资质(个人或者是企业)。
创建一个APP移动应用,应用的开发信息需要填写完整,如下载页面地址、Bundle ID(IOS)和应用签名(Android)等。应用签名不要填错,怎么获取它可以网上搜索方法。
接下来为该应用申请微信支付,填写好相应的资料,等待审核成功。
第二步
申请成功后,邮箱会收到这么一封邮件。
用这封邮件上显示的账号密码,登录微信支付,地址是:https://pay.weixin.qq.com/index.php/core/home/login
把网页上提示需要设置的都设置好,需要的控件也都给它装上。最好使用IE浏览器登录微信支付,谷歌浏览器会出现问题,原因是它们的插件不是很兼容非IE浏览器。
API密钥可以先设置好,证书也可以先下载下来,后面会用到。
第三步
之前做支付宝接口的时候,这一步基本都是开始进行小额测试了,但是微信为了广大的开发者能够在真枪实弹之前先熟悉这一切,所以就增加了一个“验收”的过程(个人表示这一步略坑,文档写的不清楚,走了些弯路)。
验收的指引文档在这里:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_1
这个“验收”就是在实际支付交易之前,先进行一些虚拟的交易。交易过程同真实交易一样,也是先在APP上买东西,调用微信支付,然后付款,但是不用真正的付款,商户账号也不会收到钱。
千万别忘记,要先打开微信,关注“微信支付商户接入验收助手”,然后绑定自己的微信支付账号。
依次点击“验收case”->“app支付”->“APP支付验收用例”,就可看到完成“验收”过程需要哪些步骤了。
标注了“必选”的用例都要去做掉,“可选”的可以不用管它。
每个用例都规定了交易的金额,一定要按照这个金额来支付,否则不会成功。
第四步
“验收”其实就是把整个支付流程全部跑一遍,所以APP中要记得集成微信支付插件。
Hbuilder在云打包时会自动集成微信支付,只要在manifest.json的“SDK配置”中填写好相关信息就可以了。
原生APP需要自己去集成,具体方法就要自己看文档实现了。
服务端程序需要按照https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1文档中的API去实现,“验收”过程中,所有的URL地址都需要加上sandboxnew,而且API密钥不能用上文提到自己去填写的(这是验收结束后真枪实弹时用的),而是从https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey获取的,这些在验收指引文档中都有说明。
坑1提示:“验收”过程中,在调用微信客户端支付时,微信会提示APP ID没有绑定PAY SIGN KEY。其实这个时候已经算是支付成功了,别管它,直接点确定!
坑2提示:服务器从微信服务端获取到下单数据,要给APP回复时,如果用Hbuilder,其实回复的是一串JSON数据,别把XML数据回复过去了(会提示支付失败-1)。格式如下:
{“appid”:”应用APPID”,”noncestr”:”随机数”,”package”:”Sign=WXPay”,”partnerid”:”微信支付商户号”,”prepayid”:”XXXXXXXXXXXX”,”timestamp”:时间戳,”sign”:”签名”}
将XML数据转成以上的JSON数据回给APP就可以了,记得重新签名要重新生成!
第五步
每完成一个验收流程,都要去微信公众号的“我的验收”->“查询验收结果”->“查询用例接入结果”->“APP支付”中查看一下,确定是否成功。
等所有“必选”用例全部完成,那么恭喜你,验收完成。这时别再用验收时获取到的API密钥了,用自己填写的API密钥开始真枪实弹地小额测试一笔吧。
涉及到退款等资金回滚的API业务,微信支付要求使用证书(上文说要下载的)来验证安全,如果服务器用的PHP就在CURL中设置好证书地址,方法在微信支付文档中有。
微信支付相比支付宝支付有一点好处,就是退款后,微信支付会退回扣的千分之六手续费,而支付宝不会退。
原文地址:http://blog.luotiankeji.com/252.html
收起阅读 »
IOS指纹识别插件开发方法
更新:HTML5+已经自带指纹识别。http://www.html5plus.org/doc/zh_cn/fingerprint.html。以下文档已过期。
之前一直考虑使用Native.js调用原生方法去实现指纹识别,但是,发现不行,因为Native.js如果调用原生方法中含有闭包的情况时,JS的回调函数无法正确识别参数的内容。
下面来说一下插件的开发,发现还是插件的开发灵活方便。
开发插件需要具备以下准备:
1、MAC系统并安装XCode。
2、按照官方文档配置好5+SDK的配置,并且调试成功。
以上准备工作完成后,就可以开发了:
1、在项目工程中,新建一个FingerprintIdent类,内容如下:
FingerprintIdent.h文件
#import <UIKit/UIKit.h>
#import <PGPlugin.h>
#import <PGMethod.h>
@interface FingerprintIdent : PGPlugin
// 是否支持指纹识别
- (void)canEvaluatePolicy:(PGMethod*)command;
// 弹出指纹识别窗口的方法
- (void)evaluatePolicy:(PGMethod*)command;
@end
FingerprintIdent.m文件
#import "FingerprintIdent.h"
#import <LocalAuthentication/LocalAuthentication.h>
@implementation FingerprintIdent
- (void)canEvaluatePolicy:(PGMethod*)command{
if(command) {
NSString* cbId = [command.arguments objectAtIndex:0];
LAContext *lacontent = [[LAContext alloc] init];
NSError *error = nil;
if([lacontent canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]){
[self toSucessCallback:cbId withInt:1];
} else {
[self toSucessCallback:cbId withInt:0];
}
}
}
- (void)evaluatePolicy:(PGMethod*)command{
if(command) {
NSString* cbId = [command.arguments objectAtIndex:0];
NSString* pArgument1 = [command.arguments objectAtIndex:1];
LAContext *lacontent = [[LAContext alloc] init];
NSError *error = nil;
if([lacontent canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]){
[lacontent evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:pArgument1 reply:^(BOOL success, NSError * _Nullable error) {
NSMutableDictionary *result = [NSMutableDictionary dictionary];
if(success){
[result setValue:@"" forKey:@"error"];
} else {
NSString *errorMsg;
switch (error.code) {
case LAErrorSystemCancel:
{
errorMsg = @"切换到其他APP,系统取消验证Touch ID";
break;
}
case LAErrorUserCancel:
{
errorMsg = @"用户取消验证Touch ID";
break;
}
case LAErrorUserFallback:
{
errorMsg = @"用户选择输入密码,切换主线程处理";
break;
}
default:
{
errorMsg = @"其他情况,切换主线程处理";
break;
}
}
[result setValue:errorMsg forKey:@"error"];
}
NSData *data=[NSJSONSerialization dataWithJSONObject:result options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonStr=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[self toSucessCallback:cbId withString:jsonStr];
}];
} else {
[self toSucessCallback:cbId withInt:0];
}
}
}
@end
2、接下来,设置几项内容。
在Xcode项目中找到PandoraApi.bundle >> feature.plist
在里面添加一项 key为FingerprintIdent, type为Dictionary。在里面新建一子项 key为class ,type为String, value为FingerprintIdent。在新建一个子项 key为global ,type为Boolean, value为NO。
3、编辑你的测试页面test.html
内容如下:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>登录</title>
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
</head>
<body>
<div class="content">
<div class="button" onclick="iscanEvaluatePolicy()">是否支持指纹识别</div>
<div class="button" onclick="toEvaluatePolicy()">指纹识别</div>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript">
document.addEventListener( "plusready", function() {
// 声明的JS“扩展插件别名”
var _BARCODE = 'FingerprintIdent',
B = window.plus.bridge;
var fingerprintIdent = {
canEvaluatePolicy : function (successCallback, errorCallback ) {
var success = typeof successCallback !== 'function' ? null : function(args) {
successCallback(args);
},
fail = typeof errorCallback !== 'function' ? null : function(code) {
errorCallback(code);
};
callbackID = B.callbackId(success, fail);
// 通知Native层plugintest扩展插件运行”PluginTestFunction”方法
return B.exec(_BARCODE, "canEvaluatePolicy", [callbackID]);
},
evaluatePolicy : function (Argus1, successCallback, errorCallback ) {
var success = typeof successCallback !== 'function' ? null : function(args) {
successCallback(args);
},
fail = typeof errorCallback !== 'function' ? null : function(code) {
errorCallback(code);
};
callbackID = B.callbackId(success, fail);
// 通知Native层plugintest扩展插件运行”PluginTestFunction”方法
return B.exec(_BARCODE, "evaluatePolicy", [callbackID, Argus1]);
}
};
window.plus.fingerprintIdent = fingerprintIdent;
}, true );
// 是否支持指纹识别
function iscanEvaluatePolicy() {
plus.fingerprintIdent.canEvaluatePolicy(function( result ) {
alert( result);
},
function(result){
//alert(result)
});
}
// 校验指纹识别
function toEvaluatePolicy() {
plus.fingerprintIdent.evaluatePolicy('请校验指纹', function( result ) {
var data = mui.parseJSON(result);
if(!data.error) {
alert('校验成功');
} else {
alert( '错误原因:'+data.error);
}
},
function(result){
//alert(result)
});
}
</script>
</body>
</html>
OK,至此,IOS指纹识别插件已经开发完成。但是记住,一定要在本地使用XCode调试并打包才会生效。看到官方文档里面的IOS插件实例还是空的,我这提供一个实例。哈哈。
更新:HTML5+已经自带指纹识别。http://www.html5plus.org/doc/zh_cn/fingerprint.html。以下文档已过期。
之前一直考虑使用Native.js调用原生方法去实现指纹识别,但是,发现不行,因为Native.js如果调用原生方法中含有闭包的情况时,JS的回调函数无法正确识别参数的内容。
下面来说一下插件的开发,发现还是插件的开发灵活方便。
开发插件需要具备以下准备:
1、MAC系统并安装XCode。
2、按照官方文档配置好5+SDK的配置,并且调试成功。
以上准备工作完成后,就可以开发了:
1、在项目工程中,新建一个FingerprintIdent类,内容如下:
FingerprintIdent.h文件
#import <UIKit/UIKit.h>
#import <PGPlugin.h>
#import <PGMethod.h>
@interface FingerprintIdent : PGPlugin
// 是否支持指纹识别
- (void)canEvaluatePolicy:(PGMethod*)command;
// 弹出指纹识别窗口的方法
- (void)evaluatePolicy:(PGMethod*)command;
@end
FingerprintIdent.m文件
#import "FingerprintIdent.h"
#import <LocalAuthentication/LocalAuthentication.h>
@implementation FingerprintIdent
- (void)canEvaluatePolicy:(PGMethod*)command{
if(command) {
NSString* cbId = [command.arguments objectAtIndex:0];
LAContext *lacontent = [[LAContext alloc] init];
NSError *error = nil;
if([lacontent canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]){
[self toSucessCallback:cbId withInt:1];
} else {
[self toSucessCallback:cbId withInt:0];
}
}
}
- (void)evaluatePolicy:(PGMethod*)command{
if(command) {
NSString* cbId = [command.arguments objectAtIndex:0];
NSString* pArgument1 = [command.arguments objectAtIndex:1];
LAContext *lacontent = [[LAContext alloc] init];
NSError *error = nil;
if([lacontent canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]){
[lacontent evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:pArgument1 reply:^(BOOL success, NSError * _Nullable error) {
NSMutableDictionary *result = [NSMutableDictionary dictionary];
if(success){
[result setValue:@"" forKey:@"error"];
} else {
NSString *errorMsg;
switch (error.code) {
case LAErrorSystemCancel:
{
errorMsg = @"切换到其他APP,系统取消验证Touch ID";
break;
}
case LAErrorUserCancel:
{
errorMsg = @"用户取消验证Touch ID";
break;
}
case LAErrorUserFallback:
{
errorMsg = @"用户选择输入密码,切换主线程处理";
break;
}
default:
{
errorMsg = @"其他情况,切换主线程处理";
break;
}
}
[result setValue:errorMsg forKey:@"error"];
}
NSData *data=[NSJSONSerialization dataWithJSONObject:result options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonStr=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[self toSucessCallback:cbId withString:jsonStr];
}];
} else {
[self toSucessCallback:cbId withInt:0];
}
}
}
@end
2、接下来,设置几项内容。
在Xcode项目中找到PandoraApi.bundle >> feature.plist
在里面添加一项 key为FingerprintIdent, type为Dictionary。在里面新建一子项 key为class ,type为String, value为FingerprintIdent。在新建一个子项 key为global ,type为Boolean, value为NO。
3、编辑你的测试页面test.html
内容如下:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>登录</title>
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
</head>
<body>
<div class="content">
<div class="button" onclick="iscanEvaluatePolicy()">是否支持指纹识别</div>
<div class="button" onclick="toEvaluatePolicy()">指纹识别</div>
</div>
<script src="js/mui.min.js"></script>
<script type="text/javascript">
document.addEventListener( "plusready", function() {
// 声明的JS“扩展插件别名”
var _BARCODE = 'FingerprintIdent',
B = window.plus.bridge;
var fingerprintIdent = {
canEvaluatePolicy : function (successCallback, errorCallback ) {
var success = typeof successCallback !== 'function' ? null : function(args) {
successCallback(args);
},
fail = typeof errorCallback !== 'function' ? null : function(code) {
errorCallback(code);
};
callbackID = B.callbackId(success, fail);
// 通知Native层plugintest扩展插件运行”PluginTestFunction”方法
return B.exec(_BARCODE, "canEvaluatePolicy", [callbackID]);
},
evaluatePolicy : function (Argus1, successCallback, errorCallback ) {
var success = typeof successCallback !== 'function' ? null : function(args) {
successCallback(args);
},
fail = typeof errorCallback !== 'function' ? null : function(code) {
errorCallback(code);
};
callbackID = B.callbackId(success, fail);
// 通知Native层plugintest扩展插件运行”PluginTestFunction”方法
return B.exec(_BARCODE, "evaluatePolicy", [callbackID, Argus1]);
}
};
window.plus.fingerprintIdent = fingerprintIdent;
}, true );
// 是否支持指纹识别
function iscanEvaluatePolicy() {
plus.fingerprintIdent.canEvaluatePolicy(function( result ) {
alert( result);
},
function(result){
//alert(result)
});
}
// 校验指纹识别
function toEvaluatePolicy() {
plus.fingerprintIdent.evaluatePolicy('请校验指纹', function( result ) {
var data = mui.parseJSON(result);
if(!data.error) {
alert('校验成功');
} else {
alert( '错误原因:'+data.error);
}
},
function(result){
//alert(result)
});
}
</script>
</body>
</html>
OK,至此,IOS指纹识别插件已经开发完成。但是记住,一定要在本地使用XCode调试并打包才会生效。看到官方文档里面的IOS插件实例还是空的,我这提供一个实例。哈哈。
收起阅读 »
滚动条不回归开始位置
官方教程,滚动区域需要加入如下代码
<div class="mui-scroll-wrapper">
<div class="mui-scroll">
<!--这里放置真实显示的DOM内容-->
</div>
</div>
options = {
scrollY: true, //是否竖向滚动
scrollX: false, //是否横向滚动
startX: 0, //初始化时滚动至x
startY: 0, //初始化时滚动至y
indicators: true, //是否显示滚动条
deceleration:0.0006, //阻尼系数,系数越小滑动越灵敏
bounce: true //是否启用回弹
}
mui('.mui-scroll-wrapper').scroll(options);
这样添加好代码,当内容滚动一段距离,如果有需求需要更换滚动区域的内容,特别是后加载的内容比之前少,会发现看不到数据,需要下拉一下滚动区域。
查看了一下 滚动区域是通过 transform 实现的,可以动态的去修改 transform 就可以实现回归位置
var scroll= mui(".mui-scroll-wrapper .mui-scroll")[0];
scroll.style.transform ="translate3d(0px, 0px, 0px) translateZ(0px)";
官方教程,滚动区域需要加入如下代码
<div class="mui-scroll-wrapper">
<div class="mui-scroll">
<!--这里放置真实显示的DOM内容-->
</div>
</div>
options = {
scrollY: true, //是否竖向滚动
scrollX: false, //是否横向滚动
startX: 0, //初始化时滚动至x
startY: 0, //初始化时滚动至y
indicators: true, //是否显示滚动条
deceleration:0.0006, //阻尼系数,系数越小滑动越灵敏
bounce: true //是否启用回弹
}
mui('.mui-scroll-wrapper').scroll(options);
这样添加好代码,当内容滚动一段距离,如果有需求需要更换滚动区域的内容,特别是后加载的内容比之前少,会发现看不到数据,需要下拉一下滚动区域。
查看了一下 滚动区域是通过 transform 实现的,可以动态的去修改 transform 就可以实现回归位置
var scroll= mui(".mui-scroll-wrapper .mui-scroll")[0];
scroll.style.transform ="translate3d(0px, 0px, 0px) translateZ(0px)";