HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

Native.js 安卓连接蓝牙打印机【可连续打印】

Native.JS

自己摸索了一下,并参考其他人的代码,并修复了原来代码存在的问题,
问题1:字符串的getBytes函数,返回null【需要通过new的方式创建字符串】
问题2:初始化打印一次,之后无法使用【不要重复调用device.createInsecureRfcommSocketToServiceRecord(uuid)或重复引入CLASS】

代码如下,可正常运行【注意,蓝牙打印机必须先匹配,保证手机蓝牙打开】

    mui.plusReady(function() {  
                main = plus.android.runtimeMainActivity();  
                BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter");  
                UUID = plus.android.importClass("java.util.UUID");  
                uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");//不需要更改  
                BAdapter = BluetoothAdapter.getDefaultAdapter();  
                BAdapter.cancelDiscovery(); //停止扫描  
                device = BAdapter.getRemoteDevice("DC:1D:30:25:19:23");//这里是蓝牙打印机的蓝牙地址  
                plus.android.importClass(device);  
                bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(uuid);  
                plus.android.importClass(bluetoothSocket);  
            });  

            function print() {  

                if(!bluetoothSocket.isConnected()) {  
                    console.log('断开了,需要重新连接,连接中');  
                    bluetoothSocket.connect();  
                }  

                if(bluetoothSocket.isConnected()) {  
                    console.log('连接成功');  
                    var outputStream = bluetoothSocket.getOutputStream();  
                    plus.android.importClass(outputStream);  
                    var s = plus.android.importClass('java.lang.String');  
                    var string = new s("测试数据"+new Date().getMilliseconds()+'\n\n\n\n');//必须以创建字符串对象的形式创建对象,否则返回NULL  
                    var bytes = string.getBytes('gbk');  
                    console.log(bytes);  
                    outputStream.write(bytes);  
                    outputStream.flush();  
                } else {  
                    console.log('fail');  
                }  

            }  

至于打印的内容和格式,请参考各自打印机提供的打印指令集,把它拼成字符串调用getBytes函数即可打印。

继续阅读 »

自己摸索了一下,并参考其他人的代码,并修复了原来代码存在的问题,
问题1:字符串的getBytes函数,返回null【需要通过new的方式创建字符串】
问题2:初始化打印一次,之后无法使用【不要重复调用device.createInsecureRfcommSocketToServiceRecord(uuid)或重复引入CLASS】

代码如下,可正常运行【注意,蓝牙打印机必须先匹配,保证手机蓝牙打开】

    mui.plusReady(function() {  
                main = plus.android.runtimeMainActivity();  
                BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter");  
                UUID = plus.android.importClass("java.util.UUID");  
                uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");//不需要更改  
                BAdapter = BluetoothAdapter.getDefaultAdapter();  
                BAdapter.cancelDiscovery(); //停止扫描  
                device = BAdapter.getRemoteDevice("DC:1D:30:25:19:23");//这里是蓝牙打印机的蓝牙地址  
                plus.android.importClass(device);  
                bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(uuid);  
                plus.android.importClass(bluetoothSocket);  
            });  

            function print() {  

                if(!bluetoothSocket.isConnected()) {  
                    console.log('断开了,需要重新连接,连接中');  
                    bluetoothSocket.connect();  
                }  

                if(bluetoothSocket.isConnected()) {  
                    console.log('连接成功');  
                    var outputStream = bluetoothSocket.getOutputStream();  
                    plus.android.importClass(outputStream);  
                    var s = plus.android.importClass('java.lang.String');  
                    var string = new s("测试数据"+new Date().getMilliseconds()+'\n\n\n\n');//必须以创建字符串对象的形式创建对象,否则返回NULL  
                    var bytes = string.getBytes('gbk');  
                    console.log(bytes);  
                    outputStream.write(bytes);  
                    outputStream.flush();  
                } else {  
                    console.log('fail');  
                }  

            }  

至于打印的内容和格式,请参考各自打印机提供的打印指令集,把它拼成字符串调用getBytes函数即可打印。

收起阅读 »

native.js唤起微信扫一扫

Native.JS html5plus HTML5+ 微信 扫一扫

没有废话直接上代码


var Intent = plus.android.importClass("android.content.Intent");  
var intent = new Intent(Intent.ACTION_MAIN);  
intent.addCategory(Intent.CATEGORY_LAUNCHER);  
var ComponentName = plus.android.importClass("android.content.ComponentName");  
var comp = new ComponentName("com.tencent.mm","com.tencent.mm.ui.LauncherUI");  
intent.setComponent(comp);  
//只想唤起微信就不要下面这句传参代码  
intent.putExtra("LauncherUI.From.Scaner.Shortcut", true);  
intent.setAction("android.intent.action.VIEW");  
var main = plus.android.runtimeMainActivity();  
main.startActivity(intent);  

用得上就点个赞,仅此而已

继续阅读 »

没有废话直接上代码


var Intent = plus.android.importClass("android.content.Intent");  
var intent = new Intent(Intent.ACTION_MAIN);  
intent.addCategory(Intent.CATEGORY_LAUNCHER);  
var ComponentName = plus.android.importClass("android.content.ComponentName");  
var comp = new ComponentName("com.tencent.mm","com.tencent.mm.ui.LauncherUI");  
intent.setComponent(comp);  
//只想唤起微信就不要下面这句传参代码  
intent.putExtra("LauncherUI.From.Scaner.Shortcut", true);  
intent.setAction("android.intent.action.VIEW");  
var main = plus.android.runtimeMainActivity();  
main.startActivity(intent);  

用得上就点个赞,仅此而已

收起阅读 »

ios调试基座打包方法

调试基座 5+sdk iOS

可下载附件中工程进行打包测试,工程下载后解压到SDK的根目录下(与SDK里其他两个示例工程同级目录)

1 下载最新SDK http://ask.dcloud.net.cn/article/103

2 调试基座的工程名称和target名称应当为DCloud_Pandora
(也可以将编译生成的app的名称,修改为DCloud_Pandora.app, 修改后重新压缩成IPA文件,放到HBuilder指定目录下即可)

3 在Xcode工程的Info.plist文件中添加UIFileSharingEnabled键,并将键值设置为YES

4 修改control.xml文件
在control.xml文件的hbuilder节点下添加属性debug='true' 和syncDebug="false"

<?xml version="1.0"?>  
<hbuilder version="1.9.3.40219" debug="true" syncDebug="false">  
        <apps>  
                <app appid="HBuilder" appver="8.9.0"/>  
        </apps>  
</hbuilder>

5 配置第三方插件
第三方插件配置方法请参考文档
消息推送(Push)插件配置
分享(Share)插件配置
地图(Maps)插件配置
统计(Statistic)插件配置
支付(Payment)插件配置
登录鉴权(Oauth)插件配置

6 引入扩展插件
扩展插件编写和引入方法请参考文档iOS平台5+插件开发

7 自定义基座包使用方法请参考文档真机运行自定义基座包使用说明

8 用户自己创建工程时请参考文档iOS创建最精简离线打包工程,创建基础工程后在工程里添加libliblog.a

继续阅读 »

可下载附件中工程进行打包测试,工程下载后解压到SDK的根目录下(与SDK里其他两个示例工程同级目录)

1 下载最新SDK http://ask.dcloud.net.cn/article/103

2 调试基座的工程名称和target名称应当为DCloud_Pandora
(也可以将编译生成的app的名称,修改为DCloud_Pandora.app, 修改后重新压缩成IPA文件,放到HBuilder指定目录下即可)

3 在Xcode工程的Info.plist文件中添加UIFileSharingEnabled键,并将键值设置为YES

4 修改control.xml文件
在control.xml文件的hbuilder节点下添加属性debug='true' 和syncDebug="false"

<?xml version="1.0"?>  
<hbuilder version="1.9.3.40219" debug="true" syncDebug="false">  
        <apps>  
                <app appid="HBuilder" appver="8.9.0"/>  
        </apps>  
</hbuilder>

5 配置第三方插件
第三方插件配置方法请参考文档
消息推送(Push)插件配置
分享(Share)插件配置
地图(Maps)插件配置
统计(Statistic)插件配置
支付(Payment)插件配置
登录鉴权(Oauth)插件配置

6 引入扩展插件
扩展插件编写和引入方法请参考文档iOS平台5+插件开发

7 自定义基座包使用方法请参考文档真机运行自定义基座包使用说明

8 用户自己创建工程时请参考文档iOS创建最精简离线打包工程,创建基础工程后在工程里添加libliblog.a

收起阅读 »

开启扫一扫 示例教程

wap2app 扫一扫 示例 扫一扫 二维码扫描

需求明确

开启常见的条码(二维码及一维码)的扫描识别功能,可调用设备的摄像头对条码图片扫描进行数据输入。通过plus.barcode可获取条码码管理对象。

知识点明确

Barcode模块:plus.barcode,提供开启摄像头扫描功能。
Gallery模块:plus.gallery,提供读取相册二维码图片功能。

效果展示

实现步骤

  1. 创建条码扫描识别控件实例对象,涉及到Barcode模块,具体参数设置可参考5+ API Barcode
    在plusReady事件触发之后创建一个Barcode实例对象,此对象提供四个方法:
    start: 开始条码识别
    cancel: 结束条码识别
    close: 关闭条码识别控件
    setFlash: 是否开启闪光灯
    和两个事件:
    onmarked: 条码识别成功事件
    onerror: 条码识别错误事件
function plusReady() {  
    if(ws || !window.plus || !domready) {  
        return;  
    }  
    // 获取窗口对象  
    ws = plus.webview.currentWebview();  
    // 开始扫描  
    ws.addEventListener('show', function() {  
        scan = new plus.barcode.Barcode('bcid');  
        // 定义识别成功事件  
        scan.onmarked = onmarked;  
        // 定义开始条码识别  
        scan.start({  
            conserve: true, // 是否保存成功扫描到的条码数据时的截图  
            filename: '_doc/barcode/'  // 保存成功扫描到的条码数据时的图片路径  
        });  
    }, false);  
    // 显示页面并关闭等待框  
    ws.show('pop-in');  
}  

// 二维码扫描成功  
function onmarked(type, result, file) {  
    switch(type) {  
        case plus.barcode.QR:  
            type = 'QR';  
            break;  
        case plus.barcode.EAN13:  
            type = 'EAN13';  
            break;  
        case plus.barcode.EAN8:  
            type = 'EAN8';  
            break;  
        default:  
            type = '其它' + type;  
            break;  
    }  
    result = result.replace(/\n/g, '');  
    plus.nativeUI.alert('扫描结果:' + JSON.stringify(result), function() {  
        console.log('扫描成功')  
    }, "helloW2A", "OK");  
    back();  
}

2.从相册中选择图片识别,涉及到Gallery模块,具体参数设置可参考5+ API:Gallery

// 从相册中选择二维码图片   
function scanPicture() {  
    plus.gallery.pick(function(path) {  
        plus.barcode.scan(path, onmarked, function(error) {  
            plus.nativeUI.alert('无法识别此图片');  
        });  
    }, function(err) {  
        console.log('Failed: ' + err.message);  
    });  
}  

3.DOM结构参考

<body style="background-color: #000000;">  
    <!--指定Barcode对象的在界面中关联div标签的id号。-->  
    <div id="bcid">  
        <div style="height:40%"></div>  
        <p class="tip">...载入中...</p>  
    </div>  
    <footer>  
        <div class="fbt" onclick="back()">取  消</div> <!--退出页面-->  
        <div class="fbt" onclick="scanPicture()">从相册选择二维码</div>  
    </footer>  
</body>

示例工程已上传,供开发者参考

继续阅读 »

需求明确

开启常见的条码(二维码及一维码)的扫描识别功能,可调用设备的摄像头对条码图片扫描进行数据输入。通过plus.barcode可获取条码码管理对象。

知识点明确

Barcode模块:plus.barcode,提供开启摄像头扫描功能。
Gallery模块:plus.gallery,提供读取相册二维码图片功能。

效果展示

实现步骤

  1. 创建条码扫描识别控件实例对象,涉及到Barcode模块,具体参数设置可参考5+ API Barcode
    在plusReady事件触发之后创建一个Barcode实例对象,此对象提供四个方法:
    start: 开始条码识别
    cancel: 结束条码识别
    close: 关闭条码识别控件
    setFlash: 是否开启闪光灯
    和两个事件:
    onmarked: 条码识别成功事件
    onerror: 条码识别错误事件
function plusReady() {  
    if(ws || !window.plus || !domready) {  
        return;  
    }  
    // 获取窗口对象  
    ws = plus.webview.currentWebview();  
    // 开始扫描  
    ws.addEventListener('show', function() {  
        scan = new plus.barcode.Barcode('bcid');  
        // 定义识别成功事件  
        scan.onmarked = onmarked;  
        // 定义开始条码识别  
        scan.start({  
            conserve: true, // 是否保存成功扫描到的条码数据时的截图  
            filename: '_doc/barcode/'  // 保存成功扫描到的条码数据时的图片路径  
        });  
    }, false);  
    // 显示页面并关闭等待框  
    ws.show('pop-in');  
}  

// 二维码扫描成功  
function onmarked(type, result, file) {  
    switch(type) {  
        case plus.barcode.QR:  
            type = 'QR';  
            break;  
        case plus.barcode.EAN13:  
            type = 'EAN13';  
            break;  
        case plus.barcode.EAN8:  
            type = 'EAN8';  
            break;  
        default:  
            type = '其它' + type;  
            break;  
    }  
    result = result.replace(/\n/g, '');  
    plus.nativeUI.alert('扫描结果:' + JSON.stringify(result), function() {  
        console.log('扫描成功')  
    }, "helloW2A", "OK");  
    back();  
}

2.从相册中选择图片识别,涉及到Gallery模块,具体参数设置可参考5+ API:Gallery

// 从相册中选择二维码图片   
function scanPicture() {  
    plus.gallery.pick(function(path) {  
        plus.barcode.scan(path, onmarked, function(error) {  
            plus.nativeUI.alert('无法识别此图片');  
        });  
    }, function(err) {  
        console.log('Failed: ' + err.message);  
    });  
}  

3.DOM结构参考

<body style="background-color: #000000;">  
    <!--指定Barcode对象的在界面中关联div标签的id号。-->  
    <div id="bcid">  
        <div style="height:40%"></div>  
        <p class="tip">...载入中...</p>  
    </div>  
    <footer>  
        <div class="fbt" onclick="back()">取  消</div> <!--退出页面-->  
        <div class="fbt" onclick="scanPicture()">从相册选择二维码</div>  
    </footer>  
</body>

示例工程已上传,供开发者参考

收起阅读 »

iOS中个推SDK升级

个推SDK

原文链接:
iOS中5+SDK项目升级个推静态库.a为.framework
说明
上篇写了升级5+SDK的文章:
iOS离线打包项目升级5+SDK

本文属于上文补充,因为要适配iPhone X,原谅我穷买不起真机,只能用模拟机调试,在调试过程中发现一个个推致命的bug:

malloc: error for object 0x170242490: Invalid pointer dequeued from free list set a breakpoint in malloc_error_break to debug
1
查资料后发现,是个推在模拟器上运行的产生的错误,我使用的是1.6.3-SDK。他们已经在最新SDK中修改了这个错误。

问题:个推静态库文件导致模拟机崩溃
解决办法:升级个推静态库文件为最新
新问题:
个推老版本使用的都是.a格式的静态库文件,而从官网下载下来的最新SDK使用的是.framework格式。如何平滑替换?

开工
(1)备份项目(这是我开始大改动必须的工作)

(2)删除5+SDK中Feature-iOS中指定的静态库文件
liblibPush.a
libGeTuiPush.a
libGeTuiSdk.a
libGtExtensionSdk

(3)将最新SDK中相应库文件复制到.a文件相应的位置,方便管理。我使用的文件如下图:
选择noidfa文件
引入后在项目中Build Phase -> Link Binary With Libraries引入framework库到项目中

(4)添加系统依赖库
根据个推官网添加系统依赖库,如图所示:
添加系统依赖库

(5)5+SDK中LinkerFlags不变

(6)删除原项目中GeTuiSdk.h文件,导入头文件:

import <GTSDK/GeTuiSdk.h>

1
(7)将插件部分用到的方法名更换为最新即可

  • (void) bindAlias:(PGMethod )cmds {
    NSString
    alias = [cmds.arguments objectAtIndex:1];
    [GeTuiSdk bindAlias:alias andSequenceNum:@"seq-1"];
    }

  • (void) unbindAlias:(PGMethod )cmds {
    NSString
    alias = [cmds.arguments objectAtIndex:1];
    [GeTuiSdk clearAllNotificationForNotificationBar];
    [GeTuiSdk unbindAlias:alias andSequenceNum:@"seq-1" andIsSelf:YES];
    }

继续阅读 »

原文链接:
iOS中5+SDK项目升级个推静态库.a为.framework
说明
上篇写了升级5+SDK的文章:
iOS离线打包项目升级5+SDK

本文属于上文补充,因为要适配iPhone X,原谅我穷买不起真机,只能用模拟机调试,在调试过程中发现一个个推致命的bug:

malloc: error for object 0x170242490: Invalid pointer dequeued from free list set a breakpoint in malloc_error_break to debug
1
查资料后发现,是个推在模拟器上运行的产生的错误,我使用的是1.6.3-SDK。他们已经在最新SDK中修改了这个错误。

问题:个推静态库文件导致模拟机崩溃
解决办法:升级个推静态库文件为最新
新问题:
个推老版本使用的都是.a格式的静态库文件,而从官网下载下来的最新SDK使用的是.framework格式。如何平滑替换?

开工
(1)备份项目(这是我开始大改动必须的工作)

(2)删除5+SDK中Feature-iOS中指定的静态库文件
liblibPush.a
libGeTuiPush.a
libGeTuiSdk.a
libGtExtensionSdk

(3)将最新SDK中相应库文件复制到.a文件相应的位置,方便管理。我使用的文件如下图:
选择noidfa文件
引入后在项目中Build Phase -> Link Binary With Libraries引入framework库到项目中

(4)添加系统依赖库
根据个推官网添加系统依赖库,如图所示:
添加系统依赖库

(5)5+SDK中LinkerFlags不变

(6)删除原项目中GeTuiSdk.h文件,导入头文件:

import <GTSDK/GeTuiSdk.h>

1
(7)将插件部分用到的方法名更换为最新即可

  • (void) bindAlias:(PGMethod )cmds {
    NSString
    alias = [cmds.arguments objectAtIndex:1];
    [GeTuiSdk bindAlias:alias andSequenceNum:@"seq-1"];
    }

  • (void) unbindAlias:(PGMethod )cmds {
    NSString
    alias = [cmds.arguments objectAtIndex:1];
    [GeTuiSdk clearAllNotificationForNotificationBar];
    [GeTuiSdk unbindAlias:alias andSequenceNum:@"seq-1" andIsSelf:YES];
    }

收起阅读 »

mui开发移动应用+java写后台

技巧 Runtime HBuilder 移动APP 入门 HTML5

本人主要是用mui编写移动应用,还可以用java写后台接口,同时还可以做页面,有需要的同志,联系我,谢谢。QQ:1094836761

本人主要是用mui编写移动应用,还可以用java写后台接口,同时还可以做页面,有需要的同志,联系我,谢谢。QQ:1094836761

使用 uploader 进行七牛图片上传

七牛 uploader

.

说明

我是七牛的忠实拥趸。
个人网站、公司项目,文件和图片的存储方案使用的都是七牛。
这两天在封装 DC 的七牛图片上传,遇到了点问题,不过最后还是解决了。
这里只分享下简单的思路和代码。
.

开发思路

  1. 生成七牛上传令牌
    因为有安全隐患,七牛官方推荐开发者向自己的业务服务器发送 ajax 进行获取。
    我在贴出的代码中略过了这一步,你们自己处理。
    .
  2. 选取图片
    使用摄像头(plus.camera)或者相册(plus.gallery)都可以。
    .
  3. 上传图片
    最主要就是设置 “令牌”、“图片名称” 等参数。
    不过需要的注意就是添加文件(addFile)后面一定要加 {"key":"file"},这是固定值,不要改,别问我为什么。

.

// 从相册获取图片  
plus.gallery.pick(function(ret){  

    // 获取图片名称  
    var path = ret;  
    var file = ret.substr(ret.lastIndexOf("/")+1);  
    var token = "xxxxxxx";    // 填写你的七牛上传令牌  

    // 上传图片  
    var url = "http://upload.qiniu.com/";  
    var uploader = plus.uploader.createUpload(url,{},function(up,state){  
        if( state==200 )  
            Console("上传成功");  
        else  
            Console("上传失败 - ",state);  
    });  

    uploader.addData("key",file);  
    uploader.addData("token",token);  
    uploader.addFile(path,{"key":"file"});      // 固定值,千万不要改!!!!!!  
    uploader.start();  

});
继续阅读 »

.

说明

我是七牛的忠实拥趸。
个人网站、公司项目,文件和图片的存储方案使用的都是七牛。
这两天在封装 DC 的七牛图片上传,遇到了点问题,不过最后还是解决了。
这里只分享下简单的思路和代码。
.

开发思路

  1. 生成七牛上传令牌
    因为有安全隐患,七牛官方推荐开发者向自己的业务服务器发送 ajax 进行获取。
    我在贴出的代码中略过了这一步,你们自己处理。
    .
  2. 选取图片
    使用摄像头(plus.camera)或者相册(plus.gallery)都可以。
    .
  3. 上传图片
    最主要就是设置 “令牌”、“图片名称” 等参数。
    不过需要的注意就是添加文件(addFile)后面一定要加 {"key":"file"},这是固定值,不要改,别问我为什么。

.

// 从相册获取图片  
plus.gallery.pick(function(ret){  

    // 获取图片名称  
    var path = ret;  
    var file = ret.substr(ret.lastIndexOf("/")+1);  
    var token = "xxxxxxx";    // 填写你的七牛上传令牌  

    // 上传图片  
    var url = "http://upload.qiniu.com/";  
    var uploader = plus.uploader.createUpload(url,{},function(up,state){  
        if( state==200 )  
            Console("上传成功");  
        else  
            Console("上传失败 - ",state);  
    });  

    uploader.addData("key",file);  
    uploader.addData("token",token);  
    uploader.addFile(path,{"key":"file"});      // 固定值,千万不要改!!!!!!  
    uploader.start();  

});
收起阅读 »

分享MUI搜索框动态赋值样式问题

项目中用到了MUI input search框

在动态赋值的时候没有获取焦点,所以搜素框里面的图标和placeholder文字都没有变,会重叠覆盖。

经过火狐调试官方input.html,查看在获取焦点的时候添加了mui-active 这个class

代码:<div class="mui-input-row mui-search mui-active>
<input class="mui-input-clear" placeholder="" data-input-clear="1" data-input-search="1" type="search"><span class="mui-icon mui-icon-clear mui-hidden"></span><span class="mui-placeholder"><span class="mui-icon mui-icon-search"></span><span></span></span>
</div>

所以大家以后在用到动态赋值的时候把值更新后,再控制下mui-active这个class是否添加就好了

大家以后遇到问题也不要过度依赖论坛,先自己试试看能否解决,实在没有办法再搜索

继续阅读 »

项目中用到了MUI input search框

在动态赋值的时候没有获取焦点,所以搜素框里面的图标和placeholder文字都没有变,会重叠覆盖。

经过火狐调试官方input.html,查看在获取焦点的时候添加了mui-active 这个class

代码:<div class="mui-input-row mui-search mui-active>
<input class="mui-input-clear" placeholder="" data-input-clear="1" data-input-search="1" type="search"><span class="mui-icon mui-icon-clear mui-hidden"></span><span class="mui-placeholder"><span class="mui-icon mui-icon-search"></span><span></span></span>
</div>

所以大家以后在用到动态赋值的时候把值更新后,再控制下mui-active这个class是否添加就好了

大家以后遇到问题也不要过度依赖论坛,先自己试试看能否解决,实在没有办法再搜索

收起阅读 »

【分享】快速获取matchUrls可用的匹配依据的值

分享 wap2app

需求简述

在 wap2app 开发中,matchUrls 可以使用多种匹配依据来匹配目标 page。
部分开发者对Location对象不够熟悉,不知道应该去匹配哪个部分,才能正确匹配到目标 page。

解决方案

准备工作

  • 在电脑上打开浏览器,最好是chrome
  • 访问要适配的 wap 站,F12打开控制台,并且切换到手机模式
  • 跳转到目标地址,也就是要匹配的地址

方案一

在控制台执行下面的代码,会将所有可用的匹配依据的值,都 log 出来。

(function() {  
  var _location = window.location;  
  var props = ['hash', 'host', 'hostname', 'href', 'pathname', 'port', 'protocol', 'search'];  
  for(var i = 0, len = props.length; i < len; i++) {  
    console.log(props[i] + ':' + _location[props[i]]);  
  }  
}());

方案二

也可以直接使用 console 本身的方法,以表格的形式将 window.location 的值展示出来。

console.table(window.location);

这个方法,会把所有的属性都列出来,找到可用的匹配依据的值就行了。

继续阅读 »

需求简述

在 wap2app 开发中,matchUrls 可以使用多种匹配依据来匹配目标 page。
部分开发者对Location对象不够熟悉,不知道应该去匹配哪个部分,才能正确匹配到目标 page。

解决方案

准备工作

  • 在电脑上打开浏览器,最好是chrome
  • 访问要适配的 wap 站,F12打开控制台,并且切换到手机模式
  • 跳转到目标地址,也就是要匹配的地址

方案一

在控制台执行下面的代码,会将所有可用的匹配依据的值,都 log 出来。

(function() {  
  var _location = window.location;  
  var props = ['hash', 'host', 'hostname', 'href', 'pathname', 'port', 'protocol', 'search'];  
  for(var i = 0, len = props.length; i < len; i++) {  
    console.log(props[i] + ':' + _location[props[i]]);  
  }  
}());

方案二

也可以直接使用 console 本身的方法,以表格的形式将 window.location 的值展示出来。

console.table(window.location);

这个方法,会把所有的属性都列出来,找到可用的匹配依据的值就行了。

收起阅读 »

iOS离线打包项目升级5+SDK

5+sdk iOS打包

原文链接:iOS离线打包项目升级5+SDK

(1)替换SDK
用最新SDK文件替换项目中SDK

(2) 将PandoraApi.bundle引入项目,引入时候勾选项如下图:
引入PandoraApi.bundle

(3) 将PandoraApi.bundle中feature.plist文件用原来项目中替换,当然如果没有写过插件,应该不需要。

(4)导入inc文件到项目中,打开SDK所在目录,拖动到项目中相应位置,此处,因我原生不会改动,所以设置如下:
导入inc文件

(5)修改control.xml中对应的appid等,修改时要注意和www文件中manifest.json文件中对应字段要完全一致,如下图:
修改control.xml文件

(6)导入相应的依赖库,及项目中相关设置,此处注意,下图中红框标注libcoreSupport.a文件一定要导入,否则会报错,当然还有其他库依赖的问题,可以根据提示解决。
项目中相关设置

(7)根据SDK最新demo,修改本项目中的主控制器中启动5+SDK的相关代码,我的启动位置在ViewController.m中,故更新为最新即可,由于适配了iPhone X有改动,需留意!

(8)到此处,文件配置基本没问题了,现在是不是可以启动应用了呢?哈哈哈,启动下试试吧,beng~,呃呃呃,程序是可以启动了,但是卡顿在index页面了,www文件我没有更改,不可能出错啊。用Safari调试后发现,是调用插件地方报错,怎么会这样?升级前是好好的,郁闷中~~

(9)最新SDK中注册插件有变动
最新SDK中注册插件不在document.addEventListener(‘plusready’)方法中了,直接注册即可。好程序可以启动了,恭喜��

(10)等等等,啊啊啊啊,报错,搜索了下,个推静态库在模拟机上报错,这个,这个,我只有模拟机,穷的买不起真机测试啊,啊啊啊啊,老板,我要真机,我要iPhone X。。。还是算了,升级个推SDK吧。升级这块在本文中不赘述,后期补充一篇文章,因为需要将本项目中.a静态库替换成个推最新的.frameworks框架了。

(11)血的教训!!!
最新的SDK注册插件不需要document.addEventListener(“plusready”, function(){},true);中注册插件,直接放外面注册就可以了
方法调用最好还是放在plusready事件之后, 是document.addEventListener(‘plusready’) ,不要用mui.plusready,或者直接加一个timeout也可以

(12)原生调用webview方式有变动
原来原生调用webview中需要根据id遍历查找,如下代码:

NSArray frames = [[[[PDRCore Instance] appManager] activeApp] appWindow].allFrames;
for (PDRCoreAppFrame
frame in frames)
if ([frame.frameName isEqualToString:@"rmsNews"]){
[frame stringByEvaluatingJavaScriptFromString:@"initChat()"];
}

改成如下方式即可:

PDRCoreAppWindow appWindow = [[[[PDRCore Instance] appManager] activeApp] appWindow];
PDRCoreAppFrame
frame = [appWindow getFrameByName:@"rmsNews"];
//同步
[frame stringByEvaluatingJavaScriptFromString:@"initChat()"];
//或者可以用异步
[frame evaluateJavaScript:@"initChat()" completionHandler:^(id result, NSError *error) {
}];
总结
升级之后,页面自动适配了iPhone X,同时运行流畅度和页面反应速度都有很大提升,感觉5+做的越来越好,虽然苹果在封杀类似这种混合式开发,但是不可否认,存在即合理,希望5+做的越来越好。

继续阅读 »

原文链接:iOS离线打包项目升级5+SDK

(1)替换SDK
用最新SDK文件替换项目中SDK

(2) 将PandoraApi.bundle引入项目,引入时候勾选项如下图:
引入PandoraApi.bundle

(3) 将PandoraApi.bundle中feature.plist文件用原来项目中替换,当然如果没有写过插件,应该不需要。

(4)导入inc文件到项目中,打开SDK所在目录,拖动到项目中相应位置,此处,因我原生不会改动,所以设置如下:
导入inc文件

(5)修改control.xml中对应的appid等,修改时要注意和www文件中manifest.json文件中对应字段要完全一致,如下图:
修改control.xml文件

(6)导入相应的依赖库,及项目中相关设置,此处注意,下图中红框标注libcoreSupport.a文件一定要导入,否则会报错,当然还有其他库依赖的问题,可以根据提示解决。
项目中相关设置

(7)根据SDK最新demo,修改本项目中的主控制器中启动5+SDK的相关代码,我的启动位置在ViewController.m中,故更新为最新即可,由于适配了iPhone X有改动,需留意!

(8)到此处,文件配置基本没问题了,现在是不是可以启动应用了呢?哈哈哈,启动下试试吧,beng~,呃呃呃,程序是可以启动了,但是卡顿在index页面了,www文件我没有更改,不可能出错啊。用Safari调试后发现,是调用插件地方报错,怎么会这样?升级前是好好的,郁闷中~~

(9)最新SDK中注册插件有变动
最新SDK中注册插件不在document.addEventListener(‘plusready’)方法中了,直接注册即可。好程序可以启动了,恭喜��

(10)等等等,啊啊啊啊,报错,搜索了下,个推静态库在模拟机上报错,这个,这个,我只有模拟机,穷的买不起真机测试啊,啊啊啊啊,老板,我要真机,我要iPhone X。。。还是算了,升级个推SDK吧。升级这块在本文中不赘述,后期补充一篇文章,因为需要将本项目中.a静态库替换成个推最新的.frameworks框架了。

(11)血的教训!!!
最新的SDK注册插件不需要document.addEventListener(“plusready”, function(){},true);中注册插件,直接放外面注册就可以了
方法调用最好还是放在plusready事件之后, 是document.addEventListener(‘plusready’) ,不要用mui.plusready,或者直接加一个timeout也可以

(12)原生调用webview方式有变动
原来原生调用webview中需要根据id遍历查找,如下代码:

NSArray frames = [[[[PDRCore Instance] appManager] activeApp] appWindow].allFrames;
for (PDRCoreAppFrame
frame in frames)
if ([frame.frameName isEqualToString:@"rmsNews"]){
[frame stringByEvaluatingJavaScriptFromString:@"initChat()"];
}

改成如下方式即可:

PDRCoreAppWindow appWindow = [[[[PDRCore Instance] appManager] activeApp] appWindow];
PDRCoreAppFrame
frame = [appWindow getFrameByName:@"rmsNews"];
//同步
[frame stringByEvaluatingJavaScriptFromString:@"initChat()"];
//或者可以用异步
[frame evaluateJavaScript:@"initChat()" completionHandler:^(id result, NSError *error) {
}];
总结
升级之后,页面自动适配了iPhone X,同时运行流畅度和页面反应速度都有很大提升,感觉5+做的越来越好,虽然苹果在封杀类似这种混合式开发,但是不可否认,存在即合理,希望5+做的越来越好。

收起阅读 »

flex布局

布局的传统解决方案,基于盒模型,依赖display属性+position属性+float属性。它对于特殊布局非常不方便,如垂直居中就不容易实现。
2009年,w3c提出了一种新的方案---flex布局,可以简便、完整、响应式地实现各种页面布局。目前,已经得到了所有浏览器的支持。
flex布局将成为未来布局的首选方案。
Flex是Flexible Box的缩写,意为“弹性布局“,用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为flex布局。
.box { display:flex; }
行内元素也可以使用Flex布局。
.box{display: inline-flex;}
webkit内核的浏览器布局加上-webkit-前缀。
.box{display:-webkit-flex;display:flex;}
注意:设为flex布局后,子元素的float、clear和vertial-align属性将失效。
二、基本概念
采用Flex布局的元素,成为Flex容器(flex contatiner),简称“容器”。它的所有子元素自动成为容器成员,称为Flex(flex item),简称“项目”。
容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。
主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。
三、容器的属性
以下6个属性设置在容器上。
flex-direction
flex-wrap
flex-flow
justify-content
align-items
align-content
3.1flex-direction属性决定主轴的方向(即项目的排列方向)。
.box{flex-direction:row | row-reverse | column | column-reverse;}
row(默认值):主轴为水平方向,起点在左端。
row-reverse:主轴为水平方向,起点在右端。
column:主轴为垂直方向,起点在上沿。
column-reverse:主轴为垂直方向,起点在下沿。
3.2flex-wrap属性
定义如何换行
.box{flex-wrap:nowrap | wrap | wrap-reverse;}
nowrap:(默认)不换行
wrap:换行,第一行在上方。
wrap-reverse:换行,第一行在下方。
3.3 flex-flow
flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。
.box{flex-flow: <flex-direction> || <flex-wrap>};
3.4 justify-content属性
justify-content属性定义了项目在主轴上的对齐方式。
3.5 align-items属性
align-items属性定义项目在交叉轴上如何对齐。
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}
它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。
flex-start:交叉轴的起点对齐。
flex-end:交叉轴的终点对齐。
center:交叉轴的中点对齐。
baseline: 项目的第一行文字的基线对齐。
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。
3.6 align-content属性
align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
.box {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
该属性可能取6个值。
flex-start:与交叉轴的起点对齐。
flex-end:与交叉轴的终点对齐。
center:与交叉轴的中点对齐。
space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
stretch(默认值):轴线占满整个交叉轴。
四、项目的属性
以下6个属性设置在项目上。
order
flex-grow
flex-shrink
flex-basis
flex
align-self
4.1 order属性
order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。
.item {
order: <integer>;
}
4.2 flex-grow属性
flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
.item {
flex-grow: <number>; / default 0 /
}
如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。
4.3 flex-shrink属性
flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

.item {
flex-shrink: <number>; / default 1 /
}
如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

4.4 flex-basis属性
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
.item {
flex-basis: <length> | auto; / default auto /
}
它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。
4.5 flex属性
flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
4.6 align-self属性
align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
该属性可能取6个值,除了auto,其他都与align-items属性完全一致。

来源:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

继续阅读 »

布局的传统解决方案,基于盒模型,依赖display属性+position属性+float属性。它对于特殊布局非常不方便,如垂直居中就不容易实现。
2009年,w3c提出了一种新的方案---flex布局,可以简便、完整、响应式地实现各种页面布局。目前,已经得到了所有浏览器的支持。
flex布局将成为未来布局的首选方案。
Flex是Flexible Box的缩写,意为“弹性布局“,用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为flex布局。
.box { display:flex; }
行内元素也可以使用Flex布局。
.box{display: inline-flex;}
webkit内核的浏览器布局加上-webkit-前缀。
.box{display:-webkit-flex;display:flex;}
注意:设为flex布局后,子元素的float、clear和vertial-align属性将失效。
二、基本概念
采用Flex布局的元素,成为Flex容器(flex contatiner),简称“容器”。它的所有子元素自动成为容器成员,称为Flex(flex item),简称“项目”。
容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。
主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。
三、容器的属性
以下6个属性设置在容器上。
flex-direction
flex-wrap
flex-flow
justify-content
align-items
align-content
3.1flex-direction属性决定主轴的方向(即项目的排列方向)。
.box{flex-direction:row | row-reverse | column | column-reverse;}
row(默认值):主轴为水平方向,起点在左端。
row-reverse:主轴为水平方向,起点在右端。
column:主轴为垂直方向,起点在上沿。
column-reverse:主轴为垂直方向,起点在下沿。
3.2flex-wrap属性
定义如何换行
.box{flex-wrap:nowrap | wrap | wrap-reverse;}
nowrap:(默认)不换行
wrap:换行,第一行在上方。
wrap-reverse:换行,第一行在下方。
3.3 flex-flow
flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。
.box{flex-flow: <flex-direction> || <flex-wrap>};
3.4 justify-content属性
justify-content属性定义了项目在主轴上的对齐方式。
3.5 align-items属性
align-items属性定义项目在交叉轴上如何对齐。
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}
它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。
flex-start:交叉轴的起点对齐。
flex-end:交叉轴的终点对齐。
center:交叉轴的中点对齐。
baseline: 项目的第一行文字的基线对齐。
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。
3.6 align-content属性
align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
.box {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
该属性可能取6个值。
flex-start:与交叉轴的起点对齐。
flex-end:与交叉轴的终点对齐。
center:与交叉轴的中点对齐。
space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
stretch(默认值):轴线占满整个交叉轴。
四、项目的属性
以下6个属性设置在项目上。
order
flex-grow
flex-shrink
flex-basis
flex
align-self
4.1 order属性
order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。
.item {
order: <integer>;
}
4.2 flex-grow属性
flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
.item {
flex-grow: <number>; / default 0 /
}
如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。
4.3 flex-shrink属性
flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

.item {
flex-shrink: <number>; / default 1 /
}
如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

4.4 flex-basis属性
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
.item {
flex-basis: <length> | auto; / default auto /
}
它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。
4.5 flex属性
flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
4.6 align-self属性
align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
该属性可能取6个值,除了auto,其他都与align-items属性完全一致。

来源:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

收起阅读 »

Mui vue slider

mui HTML5+

如果你在开发中看见有这种类型的页面


你一定会记得在Mui的MuiDemo中有一个这样的页面

哇!
这不就是一样的么!!!!!!
于是屁颠屁颠的开工搞起了
心里想着今天又是愉快的一天 这个demo真的是好
是真的开心!
然而不管你用上面数据模版结合这个使用的时候你会发现
这个页面做出来是不能滑的

LZ用的是VUE(感觉有点像我的性格 小清新简单强大)

于是想办法
打断点 然而你会发现这种情况有点无从下手
决定是你了 于是开始百度大法了
LZ试过N种百度问法

解说大多数都是说:

$nextTick(function () {  
          var sliderMuiObj = mui("#slider");  
                sliderMuiObj.slider({  
                    interval: 3000  
                });  
})

然而上面的方法并没有什么卵用

好了 直接讲解决办法

1.上面的代码写到数据更新以后

  1. 在title标签下面添加<script src="html5plus://ready"></script>
  2. 把mui.plusReady(function () {})里面的方法写到外面 然后重新运行代码

然后可以惊奇的发现可以滑动了!!!!!!!!

当你解决一个问题的时候如果能够知道原理 那才是最有用的东西
那么我们来分析一下原理

首先数据绑定有三种方式:
发布者-订阅者模式(backbone.js)
脏值检查(angular.js)
数据劫持(vue.js)

三种实现双向绑定(响应式)的做法

发布者-订阅者模式(backbone.js)
脏值检查(angular.js)
数据劫持(vue.js)

  1. 发布者-订阅者模式: 一般通过sub, pub的方式实现数据和视图的绑定监听,更新数据方式通常做法是 vm.set('property', value),这种方式现在毕竟太low了,我们更希望通过 vm.property = value 这种方式更新数据,同时自动更新视图,于是有了下面两种方式

  2. 脏值检查: angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过 setInterval() 定时轮询检测数据变动,当然Google不会这么low,angular只有在指定的事件触发时进入脏值检测,大致如下:

DOM事件,譬如用户输入文本,点击按钮等。( ng-click )
XHR响应事件 ( $http )
浏览器Location变更事件 ( $location )
Timer事件( $timeout , $interval )
执行 $digest() 或 $apply()

  1. 数据劫持: vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

思路整理

已经了解到vue是通过数据劫持的方式来做数据绑定的,其中最核心的方法便是通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的,无疑这个方法是本文中最重要、最基础的内容之一,如果不熟悉defineProperty,可以去MDN上看看

整理了一下,要实现mvvm的双向绑定,就必须要实现以下几点:

1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
4、mvvm入口函数,整合以上三者
这里写一个小Demo
JS部分

(function (g, nui) {g.nui = nui;})(this, function(obj){  
  this.verson = '2.5.1';  
  this.el = obj.el;  
  this.data = {};  
  this.nodes = {};  
  var _self = this  
  if(!obj.data){obj.data = {};}  
  Object.keys(obj.data).forEach(function(key){  
    defineReactive(_self.data, key, obj.data[key]);  
  });  
  function defineReactive(data, key, val) {  
    Object.defineProperty(_self.data, key, {  
      enumerable: true,  
      configurable: false,  
      get: function() {return val;},  
      set: function(newVal){  
        val = newVal;  
        var cnode = _self.nodes[key];  
        if(cnode){for(var i = 0;  i < cnode.length; i++){cnode[i].textContent = newVal;}}  
      }  
    });  
  }  
  //设置变量值  
  this.setData = function(objs){Object.keys(objs).forEach(function(k){_self.data[k] = objs[k];});}  
  this.isElementNode = function(node) {return node.nodeType == 1;}  
  this.isTextNode = function(node){return node.nodeType == 3;}  
  this.compileText = function(node, varName){  
    var varName = varName.substring(2, varName.length - 2);  
    console.log(varName);  
    var value = _self.data[varName];  
    node.textContent = typeof value == 'undefined' ? '' : value;  
    if(!this.nodes[varName]){this.nodes[varName] = [];}  
    this.nodes[varName].push(node);  
  }  
  this.compileFor = function(node, varName){  
    var value = _self.data[varName];  
    if(!value){node.parentNode.removeChild(node); return false;}  
    var parentDom = node.parentNode;  
    for(var i = 0; i < value.length; i++){  
      var newNode = node.cloneNode(true);  
      newNode.removeAttribute('nui-for');  
      var html = newNode.innerHTML;  
      var newHtml = html.replace(/{{item}}/g, '{{'+varName+'['+i+']}}');  
      console.log(newHtml);  
      newNode.innerHTML = newHtml;  
      parentDom.appendChild(newNode);  
    }  
    parentDom.removeChild(node);  
    //编译列表  
    this.compileSons(parentDom);  
  }  
  this.compileSons = function(el){  
    var childNodes = el.childNodes;  
    [].slice.call(childNodes).forEach(function(node){  
      var reg = /{{.*?}}/g;  
      if (_self.isElementNode(node)){  
        _self.compileSons(node);  
      }else if (_self.isTextNode(node)){  
        var regs = node.textContent.match(reg);  
        if(regs){  
          if(regs.length == 1){_self.compileText(node, regs[0]);}else{  
            var ortherText = node.textContent.split(reg), newTextNodes = [];  
            for(var  i = 0; i < ortherText.length; i++){  
              node.parentNode.insertBefore(document.createTextNode(ortherText[i]), node);  
              if(regs[i]){  
                var cnode = document.createTextNode(regs[i]);  
                node.parentNode.insertBefore(cnode, node);  
                _self.compileText(cnode, regs[i]);  
              }  
            }  
            node.parentNode.removeChild(node);  
          }  
        }  
      }  
    });  
  }  
  this.compile = function () {  
    this.els = document.querySelector(this.el);  
    if(this.els  == null){return ;}  
    this.fragment = document.createDocumentFragment();  
    var child;  
    while(child = this.els.firstChild){this.fragment.appendChild(child);}  
    this.compileSons(this.fragment);  
    this.els.appendChild(this.fragment);  
  }  
  this.compile();  
});

html 部分

<!DOCTYPE html>  
<html>  
<head>  
<meta charset="UTF-8">  
<title></title>  
</head>  
<body>  

  {{myname}}...{{test}}123..<br />  
  {{age}}...  

<span>{{test}}</span>  

  <button onclick="t();">test</button>  

<script type="text/javascript" src="common.js"></script>  
<script type="text/javascript">  
var app = new nui({  
  el : "body",  
  data : {  
    myname : 'name',  
    age : 18,  
    test : 'test'  
  }  
});  
function t(){  
  app.setData({myname : 'name new ', test:'test new'});    
}  
</script>  
</body>  
</html>

滑动不了的原因是因为html部分代码是在plusReady环境之前运行
我们引入以后第二个步骤就是为了让所有的代码在plusReady之后执行
这样就不会引起阻塞这样就可以完美运行了
如果你够幸运开始就看见我的这篇又可以屁颠屁颠的开搞了!!!

可能由于我学识浅薄,导致您发现有严重谬误的地方,请一定在评论中指出,我会在第一时间修正我的博文,以避免误人子弟。

继续阅读 »

如果你在开发中看见有这种类型的页面


你一定会记得在Mui的MuiDemo中有一个这样的页面

哇!
这不就是一样的么!!!!!!
于是屁颠屁颠的开工搞起了
心里想着今天又是愉快的一天 这个demo真的是好
是真的开心!
然而不管你用上面数据模版结合这个使用的时候你会发现
这个页面做出来是不能滑的

LZ用的是VUE(感觉有点像我的性格 小清新简单强大)

于是想办法
打断点 然而你会发现这种情况有点无从下手
决定是你了 于是开始百度大法了
LZ试过N种百度问法

解说大多数都是说:

$nextTick(function () {  
          var sliderMuiObj = mui("#slider");  
                sliderMuiObj.slider({  
                    interval: 3000  
                });  
})

然而上面的方法并没有什么卵用

好了 直接讲解决办法

1.上面的代码写到数据更新以后

  1. 在title标签下面添加<script src="html5plus://ready"></script>
  2. 把mui.plusReady(function () {})里面的方法写到外面 然后重新运行代码

然后可以惊奇的发现可以滑动了!!!!!!!!

当你解决一个问题的时候如果能够知道原理 那才是最有用的东西
那么我们来分析一下原理

首先数据绑定有三种方式:
发布者-订阅者模式(backbone.js)
脏值检查(angular.js)
数据劫持(vue.js)

三种实现双向绑定(响应式)的做法

发布者-订阅者模式(backbone.js)
脏值检查(angular.js)
数据劫持(vue.js)

  1. 发布者-订阅者模式: 一般通过sub, pub的方式实现数据和视图的绑定监听,更新数据方式通常做法是 vm.set('property', value),这种方式现在毕竟太low了,我们更希望通过 vm.property = value 这种方式更新数据,同时自动更新视图,于是有了下面两种方式

  2. 脏值检查: angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过 setInterval() 定时轮询检测数据变动,当然Google不会这么low,angular只有在指定的事件触发时进入脏值检测,大致如下:

DOM事件,譬如用户输入文本,点击按钮等。( ng-click )
XHR响应事件 ( $http )
浏览器Location变更事件 ( $location )
Timer事件( $timeout , $interval )
执行 $digest() 或 $apply()

  1. 数据劫持: vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

思路整理

已经了解到vue是通过数据劫持的方式来做数据绑定的,其中最核心的方法便是通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的,无疑这个方法是本文中最重要、最基础的内容之一,如果不熟悉defineProperty,可以去MDN上看看

整理了一下,要实现mvvm的双向绑定,就必须要实现以下几点:

1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
4、mvvm入口函数,整合以上三者
这里写一个小Demo
JS部分

(function (g, nui) {g.nui = nui;})(this, function(obj){  
  this.verson = '2.5.1';  
  this.el = obj.el;  
  this.data = {};  
  this.nodes = {};  
  var _self = this  
  if(!obj.data){obj.data = {};}  
  Object.keys(obj.data).forEach(function(key){  
    defineReactive(_self.data, key, obj.data[key]);  
  });  
  function defineReactive(data, key, val) {  
    Object.defineProperty(_self.data, key, {  
      enumerable: true,  
      configurable: false,  
      get: function() {return val;},  
      set: function(newVal){  
        val = newVal;  
        var cnode = _self.nodes[key];  
        if(cnode){for(var i = 0;  i < cnode.length; i++){cnode[i].textContent = newVal;}}  
      }  
    });  
  }  
  //设置变量值  
  this.setData = function(objs){Object.keys(objs).forEach(function(k){_self.data[k] = objs[k];});}  
  this.isElementNode = function(node) {return node.nodeType == 1;}  
  this.isTextNode = function(node){return node.nodeType == 3;}  
  this.compileText = function(node, varName){  
    var varName = varName.substring(2, varName.length - 2);  
    console.log(varName);  
    var value = _self.data[varName];  
    node.textContent = typeof value == 'undefined' ? '' : value;  
    if(!this.nodes[varName]){this.nodes[varName] = [];}  
    this.nodes[varName].push(node);  
  }  
  this.compileFor = function(node, varName){  
    var value = _self.data[varName];  
    if(!value){node.parentNode.removeChild(node); return false;}  
    var parentDom = node.parentNode;  
    for(var i = 0; i < value.length; i++){  
      var newNode = node.cloneNode(true);  
      newNode.removeAttribute('nui-for');  
      var html = newNode.innerHTML;  
      var newHtml = html.replace(/{{item}}/g, '{{'+varName+'['+i+']}}');  
      console.log(newHtml);  
      newNode.innerHTML = newHtml;  
      parentDom.appendChild(newNode);  
    }  
    parentDom.removeChild(node);  
    //编译列表  
    this.compileSons(parentDom);  
  }  
  this.compileSons = function(el){  
    var childNodes = el.childNodes;  
    [].slice.call(childNodes).forEach(function(node){  
      var reg = /{{.*?}}/g;  
      if (_self.isElementNode(node)){  
        _self.compileSons(node);  
      }else if (_self.isTextNode(node)){  
        var regs = node.textContent.match(reg);  
        if(regs){  
          if(regs.length == 1){_self.compileText(node, regs[0]);}else{  
            var ortherText = node.textContent.split(reg), newTextNodes = [];  
            for(var  i = 0; i < ortherText.length; i++){  
              node.parentNode.insertBefore(document.createTextNode(ortherText[i]), node);  
              if(regs[i]){  
                var cnode = document.createTextNode(regs[i]);  
                node.parentNode.insertBefore(cnode, node);  
                _self.compileText(cnode, regs[i]);  
              }  
            }  
            node.parentNode.removeChild(node);  
          }  
        }  
      }  
    });  
  }  
  this.compile = function () {  
    this.els = document.querySelector(this.el);  
    if(this.els  == null){return ;}  
    this.fragment = document.createDocumentFragment();  
    var child;  
    while(child = this.els.firstChild){this.fragment.appendChild(child);}  
    this.compileSons(this.fragment);  
    this.els.appendChild(this.fragment);  
  }  
  this.compile();  
});

html 部分

<!DOCTYPE html>  
<html>  
<head>  
<meta charset="UTF-8">  
<title></title>  
</head>  
<body>  

  {{myname}}...{{test}}123..<br />  
  {{age}}...  

<span>{{test}}</span>  

  <button onclick="t();">test</button>  

<script type="text/javascript" src="common.js"></script>  
<script type="text/javascript">  
var app = new nui({  
  el : "body",  
  data : {  
    myname : 'name',  
    age : 18,  
    test : 'test'  
  }  
});  
function t(){  
  app.setData({myname : 'name new ', test:'test new'});    
}  
</script>  
</body>  
</html>

滑动不了的原因是因为html部分代码是在plusReady环境之前运行
我们引入以后第二个步骤就是为了让所有的代码在plusReady之后执行
这样就不会引起阻塞这样就可以完美运行了
如果你够幸运开始就看见我的这篇又可以屁颠屁颠的开搞了!!!

可能由于我学识浅薄,导致您发现有严重谬误的地方,请一定在评论中指出,我会在第一时间修正我的博文,以避免误人子弟。

收起阅读 »