HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

基于mui整页滚动的下拉刷新和上拉加载

mui

避免双webview,使用整页滚动,更流畅;

demo和文档见github
地址:pullToRefresh.js

避免双webview,使用整页滚动,更流畅;

demo和文档见github
地址:pullToRefresh.js

App升级问题 -- 使用升级包(.wgt)格式升级

HTML5

安装升级包失败[10]:End Of Central Directory signature not found, 文件的路径是正确的,
path ="_downloads/1481102169419011845(8).wgt";
function installWgt(path) {
plus.nativeUI.showWaiting("正在安装升级包,请稍等....");
plus.runtime.install(path, {}, function() {
plus.nativeUI.alert("应用资源更新完成!", function() {
plus.nativeUI.closeWaiting();
plus.runtime.restart();
});
}, function(e) {
plus.nativeUI.closeWaiting();
plus.nativeUI.alert("安装升级包失败[" e.code "]:" e.message); //图片上面弹出的位置
console.log("安装升级包失败[" e.code "]:" e.message);
});
}

望大神们帮忙!

继续阅读 »

安装升级包失败[10]:End Of Central Directory signature not found, 文件的路径是正确的,
path ="_downloads/1481102169419011845(8).wgt";
function installWgt(path) {
plus.nativeUI.showWaiting("正在安装升级包,请稍等....");
plus.runtime.install(path, {}, function() {
plus.nativeUI.alert("应用资源更新完成!", function() {
plus.nativeUI.closeWaiting();
plus.runtime.restart();
});
}, function(e) {
plus.nativeUI.closeWaiting();
plus.nativeUI.alert("安装升级包失败[" e.code "]:" e.message); //图片上面弹出的位置
console.log("安装升级包失败[" e.code "]:" e.message);
});
}

望大神们帮忙!

收起阅读 »

一天记录一点点....

一直想做一个本地生活的平台。之前有做成功。然后腾讯云的服务器到期了...服务端全部被删除了。然后电脑硬盘坏了,客户端又毁了。

这是个悲伤的故事.现在重新开始。

一、页面布局。

代码就是基本的布局代码,如下

     <nav class="mui-bar mui-bar-tab">  
            <a class="mui-tab-item mui-active" href="#" id="main">  
                <span class="mui-icon mui-icon-pengyouquan"></span>  
                <span class="mui-tab-label">圈子</span>  
            </a>  
            <a class="mui-tab-item" href="#" id="chat">  
                <span class="mui-icon mui-icon-chatboxes"></span>  
                <span class="mui-tab-label">聊天</span>  
            </a>  
            <a class="mui-tab-item" href="#" id="discover">  
                <span class="mui-icon mui-icon-paperplane"></span>  
                <span class="mui-tab-label">发现</span>  
            </a>  
            <a class="mui-tab-item" href="#" id="settings">  
                <span class="mui-icon mui-icon-gear"><span class="mui-badge mui-badge-danger"></span></span>  
                <span class="mui-tab-label">设置</span>  
            </a>  
    </nav>

然后是创建webview
<script type="text/javascript" charset="utf-8">

mui.init({  
    subpages:[{  
        url:'main.html',  
        id:'main.html',  
        styles:{  
            top:'45px',//mui标题栏默认高度为45px;  
            bottom:'50px'//默认为0px,可不定义;  
        }  
    }]  
});  
//main点击事件  
document.getElementById('main').addEventListener('tap', function() {  
    mui.openWindow({  
        url: 'main.html',  
        id:'main',  
        styles:{  
            top:'45px',  
            bottom:'50px'  
        }  
    });  
});  
//chat按钮点击事件  
document.getElementById('chat').addEventListener('tap', function() {  
    mui.openWindow({  
        url: 'pullrefresh_sub.html',  
        id:'chat',  
        styles:{  
            top:'45px',  
            bottom:'50px'  
        }  
    });  
});  
//discover按钮点击事件  
document.getElementById("discover").addEventListener('tap',function() {  
    mui.openWindow({  
        url: 'pullrefresh_sub.html',  
        id:'discover',  
        styles:{  
            top:'45px',  
            bottom:'50px'  
        }  
    });  
});  
//settings按钮点击事件  
document.getElementById("settings").addEventListener('tap',function() {  
    mui.openWindow({  
        url: 'pullrefresh_sub.html',  
        id:'settings',  
        styles:{  
            top:'45px',  
            bottom:'50px'  
        }  
    });  
});  

</script>

继续阅读 »

一直想做一个本地生活的平台。之前有做成功。然后腾讯云的服务器到期了...服务端全部被删除了。然后电脑硬盘坏了,客户端又毁了。

这是个悲伤的故事.现在重新开始。

一、页面布局。

代码就是基本的布局代码,如下

     <nav class="mui-bar mui-bar-tab">  
            <a class="mui-tab-item mui-active" href="#" id="main">  
                <span class="mui-icon mui-icon-pengyouquan"></span>  
                <span class="mui-tab-label">圈子</span>  
            </a>  
            <a class="mui-tab-item" href="#" id="chat">  
                <span class="mui-icon mui-icon-chatboxes"></span>  
                <span class="mui-tab-label">聊天</span>  
            </a>  
            <a class="mui-tab-item" href="#" id="discover">  
                <span class="mui-icon mui-icon-paperplane"></span>  
                <span class="mui-tab-label">发现</span>  
            </a>  
            <a class="mui-tab-item" href="#" id="settings">  
                <span class="mui-icon mui-icon-gear"><span class="mui-badge mui-badge-danger"></span></span>  
                <span class="mui-tab-label">设置</span>  
            </a>  
    </nav>

然后是创建webview
<script type="text/javascript" charset="utf-8">

mui.init({  
    subpages:[{  
        url:'main.html',  
        id:'main.html',  
        styles:{  
            top:'45px',//mui标题栏默认高度为45px;  
            bottom:'50px'//默认为0px,可不定义;  
        }  
    }]  
});  
//main点击事件  
document.getElementById('main').addEventListener('tap', function() {  
    mui.openWindow({  
        url: 'main.html',  
        id:'main',  
        styles:{  
            top:'45px',  
            bottom:'50px'  
        }  
    });  
});  
//chat按钮点击事件  
document.getElementById('chat').addEventListener('tap', function() {  
    mui.openWindow({  
        url: 'pullrefresh_sub.html',  
        id:'chat',  
        styles:{  
            top:'45px',  
            bottom:'50px'  
        }  
    });  
});  
//discover按钮点击事件  
document.getElementById("discover").addEventListener('tap',function() {  
    mui.openWindow({  
        url: 'pullrefresh_sub.html',  
        id:'discover',  
        styles:{  
            top:'45px',  
            bottom:'50px'  
        }  
    });  
});  
//settings按钮点击事件  
document.getElementById("settings").addEventListener('tap',function() {  
    mui.openWindow({  
        url: 'pullrefresh_sub.html',  
        id:'settings',  
        styles:{  
            top:'45px',  
            bottom:'50px'  
        }  
    });  
});  

</script>

收起阅读 »

解决安卓下拉刷新异常问题

mui

一、安卓下拉刷新异常解决问题
兼容ios、安卓版本

解决方法:
1、使用mui底部选项卡-webview模式
2、这边使用第二选项卡为例,在第二选项卡使用双监听
//启用双击监听
mui.init({
gestureConfig:{
doubletap:true
},
subpages:[{
url:'内容页.html',
id:'内容页.html',
styles:{
top: '45px',
bottom: '0px',
}
}]
});
var contentWebview = null;
document.querySelector('header').addEventListener('doubletap',function () {
if(contentWebview==null){
contentWebview = plus.webview.currentWebview().children()[0];
}
contentWebview.evalJS("mui('#pullrefresh').pullRefresh().scrollTo(0,0,100)");
});
3、所有内容都定义在:内容页.html文件中

二、自定义选项卡标题
1、使用mui底部选项卡-webview模式
2、去掉头部标题栏部分在选项卡内容页做定义
注:此部分为自定义标题栏比如添加搜索、按钮、以及下拉效果均可

继续阅读 »

一、安卓下拉刷新异常解决问题
兼容ios、安卓版本

解决方法:
1、使用mui底部选项卡-webview模式
2、这边使用第二选项卡为例,在第二选项卡使用双监听
//启用双击监听
mui.init({
gestureConfig:{
doubletap:true
},
subpages:[{
url:'内容页.html',
id:'内容页.html',
styles:{
top: '45px',
bottom: '0px',
}
}]
});
var contentWebview = null;
document.querySelector('header').addEventListener('doubletap',function () {
if(contentWebview==null){
contentWebview = plus.webview.currentWebview().children()[0];
}
contentWebview.evalJS("mui('#pullrefresh').pullRefresh().scrollTo(0,0,100)");
});
3、所有内容都定义在:内容页.html文件中

二、自定义选项卡标题
1、使用mui底部选项卡-webview模式
2、去掉头部标题栏部分在选项卡内容页做定义
注:此部分为自定义标题栏比如添加搜索、按钮、以及下拉效果均可

收起阅读 »

还在为了没有后端发愁?? hoa 为您提供学习后端开放源,学习app不用自己做后端了! 申请加精谢谢

移动APP mui

学习app开发的你恰巧又是做前端的你:
是不是没有后端数据总是觉得自己做的就是一层表皮,搭建后端似乎有些复杂?
需要服务器 需要配置服务器 需要设计数据库 制作接口.....

现在 福利来了!!
HOA 基础版正式发布!!
HCoder Open Api 简称 HOA 是由 www.hcoder.net 提供的一套api数据源,提供了日常app开发学习过程中常用的数据源,适用于基于 mui hui h5+的app开发。

官网地址
http://www.hcoder.net/api

我们为您提供学习app开发后端所需的基础数据,并提供项目案例源码(官网上可以下载样例)!快来吧!
测试版数据不断扩展中,目前提供基础的 post get 图片轮播 新闻列表 新闻详情数据源。
后期我们将提供用户体系数据源涵盖 用户 登陆 注册等....

本周6晚上8点 hcoder 项目开发直播课程报名中(收费5元 防止放鸽子),想听课的加QQ 1265928288

继续阅读 »

学习app开发的你恰巧又是做前端的你:
是不是没有后端数据总是觉得自己做的就是一层表皮,搭建后端似乎有些复杂?
需要服务器 需要配置服务器 需要设计数据库 制作接口.....

现在 福利来了!!
HOA 基础版正式发布!!
HCoder Open Api 简称 HOA 是由 www.hcoder.net 提供的一套api数据源,提供了日常app开发学习过程中常用的数据源,适用于基于 mui hui h5+的app开发。

官网地址
http://www.hcoder.net/api

我们为您提供学习app开发后端所需的基础数据,并提供项目案例源码(官网上可以下载样例)!快来吧!
测试版数据不断扩展中,目前提供基础的 post get 图片轮播 新闻列表 新闻详情数据源。
后期我们将提供用户体系数据源涵盖 用户 登陆 注册等....

本周6晚上8点 hcoder 项目开发直播课程报名中(收费5元 防止放鸽子),想听课的加QQ 1265928288

收起阅读 »

纯js 头像裁剪

头像裁剪 图片裁剪

引用cropper.js 纯js,无需其余第三方插件,完成图片裁剪功能,使用例子在附件中

<!DOCTYPE html>  
<html>  
    <head>  
        <meta charset="utf-8">  
        <title></title>  
        <link rel="stylesheet" href="js/cropperjs-master/dist/cropper.min.css" />  
        <link rel="stylesheet" href="css/mui.min.css" />  
        <style>  
            #redo{  
                position: fixed;  
                bottom: 20px;  
                left :20px;  
                font-size: 30px;  
            }  
            #undo{  
                position: fixed;  
                bottom: 20px;  
                right :20px;  
                font-size: 30px;  
            }  
        </style>  
    </head>  
    <body>  
        <header class="mui-bar mui-bar-nav blueBackground">  
          <h1 id="patientId" class="mui-title">截取头像</h1>  
          <a id="save" style="vertical-align: middle;color:#8dc14f;line-height:2.5em;" class="mui-pull-right"><span>保存</span></a>  
        </header>  
        <div style="" class="mui-content">  
            <div style="">  
                <img style="width: 98%;" id="image" src="">  
            </div>  
            <button id="redo" type="button" class="mui-btn mui-btn-danger mui-btn-outlined mui-pull-left"><span class="mui-icon mui-icon-redo"></span></button>  
            <button id="undo" type="button" class="mui-btn mui-btn-danger mui-btn-outlined mui-pull-right"><span class="mui-icon mui-icon-undo"></button>  
        </div>  
        <script type="text/javascript" src="js/mui.min.js" ></script>  
        <script type="text/javascript" src="js/cropperjs-master/dist/cropper.min.js" ></script>  
        <script>  
            var image = document.getElementById('image');  
            var cropper = null;  
            var resImg = null;  
            //在选择或者拍摄完成后跳出裁剪页面并把图片路径传递到此页面  
            //image.src = plus.webview.currentWebview().imgSrc;  
            image.src = "img/head-default.jpg";  
            initCropper();  
            document.getElementById("save").addEventListener("tap",getImg);  
            document.getElementById("redo").addEventListener("tap",function(){  
                cropper.rotate(90);  
            });  
            document.getElementById("undo").addEventListener("tap",function(){  
                cropper.rotate(-90);  
            });  
            function initCropper(){  
                cropper = new Cropper(image, {  
                    aspectRatio: 1/1,  
                    dragMode:'move',  
                    rotatable:true,  
                    minCropBoxWidth:200,  
                    minCropBoxHeight:200,  
                    minCanvasWidth:200,  
                    minCanvasHeight:200,  
                    minContainerWidth:200,  
                    minContainerHeight:200,  
                    crop: function(data) {  
                     }  
                });  
            }  
            function getImg(){  
                resImg =  cropper.getCroppedCanvas({  
                      width: 200,  
                      height: 200  
                }).toDataURL();  
                console.log(resImg)  
                //裁剪完毕后将新的图片路径传递到需要显示的页面即可显示 结果为base64格式  
                //mui.fire(plus.webview.getWebviewById("personalInfoPage"),"cropperImg",{resImg:resImg});  
                //mui.back();  
            }  

        </script>  
    </body>  
</html>  
继续阅读 »

引用cropper.js 纯js,无需其余第三方插件,完成图片裁剪功能,使用例子在附件中

<!DOCTYPE html>  
<html>  
    <head>  
        <meta charset="utf-8">  
        <title></title>  
        <link rel="stylesheet" href="js/cropperjs-master/dist/cropper.min.css" />  
        <link rel="stylesheet" href="css/mui.min.css" />  
        <style>  
            #redo{  
                position: fixed;  
                bottom: 20px;  
                left :20px;  
                font-size: 30px;  
            }  
            #undo{  
                position: fixed;  
                bottom: 20px;  
                right :20px;  
                font-size: 30px;  
            }  
        </style>  
    </head>  
    <body>  
        <header class="mui-bar mui-bar-nav blueBackground">  
          <h1 id="patientId" class="mui-title">截取头像</h1>  
          <a id="save" style="vertical-align: middle;color:#8dc14f;line-height:2.5em;" class="mui-pull-right"><span>保存</span></a>  
        </header>  
        <div style="" class="mui-content">  
            <div style="">  
                <img style="width: 98%;" id="image" src="">  
            </div>  
            <button id="redo" type="button" class="mui-btn mui-btn-danger mui-btn-outlined mui-pull-left"><span class="mui-icon mui-icon-redo"></span></button>  
            <button id="undo" type="button" class="mui-btn mui-btn-danger mui-btn-outlined mui-pull-right"><span class="mui-icon mui-icon-undo"></button>  
        </div>  
        <script type="text/javascript" src="js/mui.min.js" ></script>  
        <script type="text/javascript" src="js/cropperjs-master/dist/cropper.min.js" ></script>  
        <script>  
            var image = document.getElementById('image');  
            var cropper = null;  
            var resImg = null;  
            //在选择或者拍摄完成后跳出裁剪页面并把图片路径传递到此页面  
            //image.src = plus.webview.currentWebview().imgSrc;  
            image.src = "img/head-default.jpg";  
            initCropper();  
            document.getElementById("save").addEventListener("tap",getImg);  
            document.getElementById("redo").addEventListener("tap",function(){  
                cropper.rotate(90);  
            });  
            document.getElementById("undo").addEventListener("tap",function(){  
                cropper.rotate(-90);  
            });  
            function initCropper(){  
                cropper = new Cropper(image, {  
                    aspectRatio: 1/1,  
                    dragMode:'move',  
                    rotatable:true,  
                    minCropBoxWidth:200,  
                    minCropBoxHeight:200,  
                    minCanvasWidth:200,  
                    minCanvasHeight:200,  
                    minContainerWidth:200,  
                    minContainerHeight:200,  
                    crop: function(data) {  
                     }  
                });  
            }  
            function getImg(){  
                resImg =  cropper.getCroppedCanvas({  
                      width: 200,  
                      height: 200  
                }).toDataURL();  
                console.log(resImg)  
                //裁剪完毕后将新的图片路径传递到需要显示的页面即可显示 结果为base64格式  
                //mui.fire(plus.webview.getWebviewById("personalInfoPage"),"cropperImg",{resImg:resImg});  
                //mui.back();  
            }  

        </script>  
    </body>  
</html>  
收起阅读 »

测试程序进程

var needCheckVersion = true;
function getVersion(){
if(needCheckVersion!=true){
return false;
}
needCheckVersion = false;

$.ajax({      
    type:'post',          
    url:baseUrl+'/api/work.php?act=getVersion&t='+new Date(),      
    data:'',  
    dataType:'json',                      
    success:function(data){  
        //  
        //needGetVersion = true;  
        console.log("load done"+needCheckVersion);  
        var v = localStorage.version;  
        //console.log(v+'=='+data.v);  
        if(v!=data.v){  
            alert('有新版本,请到设置里点击在线更新进行更新 !');  
        }  
        //可能重装安装以后,localstorage数据就被清掉了  
        localStorage.new_version = data.v;  

    }      
});  

}

function plusReady(){
//从后台切换到前台时执行
document.addEventListener( "resume", resumeCallback);
function resumeCallback(){
console.log("resume");
getVersion();
}
//从前台切换到后台
document.addEventListener( "pause", pauseCallback );
function pauseCallback(){
console.log("pause");
needCheckVersion = true ;
}
}

继续阅读 »

var needCheckVersion = true;
function getVersion(){
if(needCheckVersion!=true){
return false;
}
needCheckVersion = false;

$.ajax({      
    type:'post',          
    url:baseUrl+'/api/work.php?act=getVersion&t='+new Date(),      
    data:'',  
    dataType:'json',                      
    success:function(data){  
        //  
        //needGetVersion = true;  
        console.log("load done"+needCheckVersion);  
        var v = localStorage.version;  
        //console.log(v+'=='+data.v);  
        if(v!=data.v){  
            alert('有新版本,请到设置里点击在线更新进行更新 !');  
        }  
        //可能重装安装以后,localstorage数据就被清掉了  
        localStorage.new_version = data.v;  

    }      
});  

}

function plusReady(){
//从后台切换到前台时执行
document.addEventListener( "resume", resumeCallback);
function resumeCallback(){
console.log("resume");
getVersion();
}
//从前台切换到后台
document.addEventListener( "pause", pauseCallback );
function pauseCallback(){
console.log("pause");
needCheckVersion = true ;
}
}

收起阅读 »

差量更新两个坑

差量更新

按照步骤 完成 包 遇到第一个问题 是www和update。xml 要一起压缩 不要放在一个文件夹下 第二个问题 出现各种版本不匹配
把update 里的版本 改成和现有的版本一致 www目录下的manifes里的版本要增加 就更新成功

按照步骤 完成 包 遇到第一个问题 是www和update。xml 要一起压缩 不要放在一个文件夹下 第二个问题 出现各种版本不匹配
把update 里的版本 改成和现有的版本一致 www目录下的manifes里的版本要增加 就更新成功

3年前端开发经验,用mui实战做过APP,现 找工作!求带走!

求职 招聘

性别:男
三年前端开发经验
由于现在公司经营不善,一不小心技术部解散,无奈,只好拂袖而去,现在待业在家,哪位老板愿带我回家,定不负所托,完成任务。

本人近况:之前公司是一家电商公司,当初去公司的时候我负责的就是整个前端开发组的小组长,带领2人完成整套APP的开发,现在已经全部开发完成,安卓市场,IOS商店均可下载,(由于自我保护,恕在下不能公布APP名称,想要招人的可以联系我QQ 245132346 )。
目前有公司想用mui 开发APP的公司 你要了我 等于要了一套APP代码,这都是小 关键本人 已熟练掌握 mui H5+核心要素 包括其调用手机底层功能 支付宝支付,微信支付等等。

本人目前所掌握的技能:require react webpack vue swiper less JQ zepto ...

去年我一直做的 手机站的 网页 对于移动端网页开发 有着深刻的理解 再加上一段APP开发的经历 更是深入我心,自认为 去任何一家公司 无需学习 无需培养 老夫衣袖一挥 对着电脑就是干。(语言颇有不妥 懂我者自懂 如果您的公司 是一家只知道工作 无一点自由 幽默 谈笑的空间 那对不起 请勿打扰)

有意向的公司 加QQ要我的简历 期待与您的合作。 245132346

继续阅读 »

性别:男
三年前端开发经验
由于现在公司经营不善,一不小心技术部解散,无奈,只好拂袖而去,现在待业在家,哪位老板愿带我回家,定不负所托,完成任务。

本人近况:之前公司是一家电商公司,当初去公司的时候我负责的就是整个前端开发组的小组长,带领2人完成整套APP的开发,现在已经全部开发完成,安卓市场,IOS商店均可下载,(由于自我保护,恕在下不能公布APP名称,想要招人的可以联系我QQ 245132346 )。
目前有公司想用mui 开发APP的公司 你要了我 等于要了一套APP代码,这都是小 关键本人 已熟练掌握 mui H5+核心要素 包括其调用手机底层功能 支付宝支付,微信支付等等。

本人目前所掌握的技能:require react webpack vue swiper less JQ zepto ...

去年我一直做的 手机站的 网页 对于移动端网页开发 有着深刻的理解 再加上一段APP开发的经历 更是深入我心,自认为 去任何一家公司 无需学习 无需培养 老夫衣袖一挥 对着电脑就是干。(语言颇有不妥 懂我者自懂 如果您的公司 是一家只知道工作 无一点自由 幽默 谈笑的空间 那对不起 请勿打扰)

有意向的公司 加QQ要我的简历 期待与您的合作。 245132346

收起阅读 »

关于.net的webservice的跨域访问

AJAX跨域

现象:在本机模拟器以及浏览器模式,可以正常访问,真机运行或打包成app到真机上都不行。
解决:
主要修改是在webconfig中的配置,除了必须的
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Authorization, Accept,X-Requested-With"/>
</customHeaders>
</httpProtocol>
</system.webServer>

还要配置协议
<webServices>
<protocols>
<add name="HttpSoap" />
<add name="HttpPost" />
<add name="HttpGet" />
</protocols>
</webServices>
奇怪的是,不配置协议时,默认情况只有soap,在模拟器上可以正常跑,到手机上就不行了。

继续阅读 »

现象:在本机模拟器以及浏览器模式,可以正常访问,真机运行或打包成app到真机上都不行。
解决:
主要修改是在webconfig中的配置,除了必须的
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Authorization, Accept,X-Requested-With"/>
</customHeaders>
</httpProtocol>
</system.webServer>

还要配置协议
<webServices>
<protocols>
<add name="HttpSoap" />
<add name="HttpPost" />
<add name="HttpGet" />
</protocols>
</webServices>
奇怪的是,不配置协议时,默认情况只有soap,在模拟器上可以正常跑,到手机上就不行了。

收起阅读 »

使用JavaScriptCore 实现OC与JS的交互

一、说明这篇文章记录自己在研究OC与JS交互中的所得,以及遇到的问题与解决
由于苹果的审核时间太漫长,一次审核不过,那又将进入另一个漫长的审核期。为了能在开发中方便更新,公司要求在项目中使用HTML5,这样就涉及到OC与JS的交互,不懂H5,不懂JS。在经过一段时间的摸索之后,将自己的研究记录下来,以做备忘。
OC与JS的交互实现方式有很多,之前用的比较多的是WebViewJavaScriptBridge,但在IOS7之后,苹果将JavaScriptCore框架开放。因此,这篇文章不讲理论,主要讲的是JavaScriptCore的实际使用。
文中所用的项目JavaScriptCoreDemo
废话说完了,下面进入正题

二、Demo项目中功能介绍

Demo首页
这个demo主要分为了三个部分来:
1.JS Call OC , JS调用OC的函数
2.OC Call JS , OC调用JS的函数
3.一个绘图的例子

在做OC与JS交互工作之前,我们需要做些准备工作
1.导入JavaScriptCore的头文件

import <JavaScriptCore/JavaScriptCore.h>

2.用webView加载HTML文件,这里用的是本地HTML;
[Objective-C] 查看源文件 复制代码
?
01
02
03
04
05
06
07
08
09
10

  • (void)viewDidLoad
    {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    self.title = @"js call oc";

NSString path = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"JSCallOC.html"];
NSURLRequest
request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]];
[self.webView loadRequest:request];
}

3.在JS交互中,很多事情都是在webView的delegate方法中完成的,通过JSContent创建一个使用JS的环境,所以这里,我们先将self.content在这里面初始化;
[Objective-C] 查看源文件 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13

  • (void)webViewDidFinishLoad:(UIWebView *)webView
    {
    //初始化content
    self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

// 打印异常,由于JS的异常信息是不会在OC中被直接打印的,所以我们在这里添加打印异常信息,
self.context.exceptionHandler =
^(JSContext context, JSValue exceptionValue)
{
context.exception = exceptionValue;
NSLog(@"%@", exceptionValue);
};
}

三、实际操作中 JS call OC先来看demo

JS Call OC

这个页面整个都是通过HTML实现的,
1 计算阶乘:在输入框中输入一个数字,然后在OC中计算出结果,最后显示在HTML的页面上;
2 测试log:点击后,在后台打印测试数据;
3 OC原生Alert :点击后,弹出OC的提示框;
4 addSubView:点击后,在OC中添加一个View;
5 push to second ViewController :跳转到下一个界面
总结:以上功能都是在OC获取HTML中按钮的点击事件,在后在OC中实现功能.

??如何获取HTML中的点击事件呢??
在HTML中,为一个元素添加点击时间有两种写法
<input type="button" value="计算阶乘" />或者
<input type="button" value="测试log" />
如果是第一种方法,那么就要用JSExport协议关联native的方法,要在webView的delegate里面添加
// 以 JSExport 协议关联 native 的方法self.content[@"native"] = self;添加完之后,要声明一个继承JSExport的协议,协议中声明供JS使用的OC的方法
[Objective-C] 查看源文件 复制代码
?
01
02
03
04
05
06
07
08
09
10
@protocol TestJSExport <JSExport>
JSExportAs
(calculateForJS /* handleFactorialCalculateWithNumber 作为js方法的别名 /,

  • (void)handleFactorialCalculateWithNumber:(NSNumber *)number
    );
    • (void)pushViewController:(NSString )view title:(NSString )title;

-(void)log:(NSString*)l;

@end

在OC中实现这些方法,这样就完成了!

如果是第二章方法,则只需要通过block的形式关联JavaScript function就可以了
!self.context[@"log"] = ^(NSString *str){NSLog(@"%@", str);};

三、OC调用JS

OC调用JS

在这个例子中,界面的所有View都是OC创建的,点击“交给JS处理计算阶乘”后,将textfild的数据传给JS,JS计算完成后在返回来!
这里面首先要获取JS里面的计算函数,在OC中,所有表示JS中对象,都用JSValue来创建,通过objectForKeyedSubscript方法或者直接使用下标的方法获取JS对象,然后使用callWithArguments方法来执行函数
[Objective-C] 查看源文件 复制代码
?
1
2
3
4
5
// 方法一. JSValue function = [self.context objectForKeyedSubscript:@"factorial"];
// 方法二.
JSValue
function = self.context[@"factorial"];
JSValue *result = [function callWithArguments:@[inputNumber]];
self.showLable.text = [NSString stringWithFormat:@"%@", [result toNumber]];

四、demo之外(慢慢在总结)1.JS注入
2.在OC中为JS创建对象
......

零碎的补充1:对于JS 函数中,参数中有函数的,在OC中用JSValue接收
[Objective-C] 查看源文件 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
// 比如:JS代码[/font] function myFunc({"text":"这里是文字","callbackFun":function(string){alert'string'}});

//OC代码中在.h的protocol中声明JS要调用的OC方法
//.h protocol中,函数名称要和JS中相同,这里接收的参数为JSValue
JSExportAs
(myFunc,
-(void) myFunc:(JSValue*)value
);

//在.m文件中,实现myFunc方法
-(void) myFunc:(JSValue*)value{

NSString * text = [value valueForProperty:@"text"];//打印"这里是文字"

JSValue * func = [value valueForProperty:@"callbackFun"]; //这里是JS参数中的func;

//调用这个函数
[func callWithArguments:@[@"这里是参数"]];

}

demo 直接下载:
[pan=https://github.com/shaojiankui/JavaScriptCore-Demo/archive/master.zip]|10[/pan]

继续阅读 »

一、说明这篇文章记录自己在研究OC与JS交互中的所得,以及遇到的问题与解决
由于苹果的审核时间太漫长,一次审核不过,那又将进入另一个漫长的审核期。为了能在开发中方便更新,公司要求在项目中使用HTML5,这样就涉及到OC与JS的交互,不懂H5,不懂JS。在经过一段时间的摸索之后,将自己的研究记录下来,以做备忘。
OC与JS的交互实现方式有很多,之前用的比较多的是WebViewJavaScriptBridge,但在IOS7之后,苹果将JavaScriptCore框架开放。因此,这篇文章不讲理论,主要讲的是JavaScriptCore的实际使用。
文中所用的项目JavaScriptCoreDemo
废话说完了,下面进入正题

二、Demo项目中功能介绍

Demo首页
这个demo主要分为了三个部分来:
1.JS Call OC , JS调用OC的函数
2.OC Call JS , OC调用JS的函数
3.一个绘图的例子

在做OC与JS交互工作之前,我们需要做些准备工作
1.导入JavaScriptCore的头文件

import <JavaScriptCore/JavaScriptCore.h>

2.用webView加载HTML文件,这里用的是本地HTML;
[Objective-C] 查看源文件 复制代码
?
01
02
03
04
05
06
07
08
09
10

  • (void)viewDidLoad
    {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    self.title = @"js call oc";

NSString path = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"JSCallOC.html"];
NSURLRequest
request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]];
[self.webView loadRequest:request];
}

3.在JS交互中,很多事情都是在webView的delegate方法中完成的,通过JSContent创建一个使用JS的环境,所以这里,我们先将self.content在这里面初始化;
[Objective-C] 查看源文件 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13

  • (void)webViewDidFinishLoad:(UIWebView *)webView
    {
    //初始化content
    self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

// 打印异常,由于JS的异常信息是不会在OC中被直接打印的,所以我们在这里添加打印异常信息,
self.context.exceptionHandler =
^(JSContext context, JSValue exceptionValue)
{
context.exception = exceptionValue;
NSLog(@"%@", exceptionValue);
};
}

三、实际操作中 JS call OC先来看demo

JS Call OC

这个页面整个都是通过HTML实现的,
1 计算阶乘:在输入框中输入一个数字,然后在OC中计算出结果,最后显示在HTML的页面上;
2 测试log:点击后,在后台打印测试数据;
3 OC原生Alert :点击后,弹出OC的提示框;
4 addSubView:点击后,在OC中添加一个View;
5 push to second ViewController :跳转到下一个界面
总结:以上功能都是在OC获取HTML中按钮的点击事件,在后在OC中实现功能.

??如何获取HTML中的点击事件呢??
在HTML中,为一个元素添加点击时间有两种写法
<input type="button" value="计算阶乘" />或者
<input type="button" value="测试log" />
如果是第一种方法,那么就要用JSExport协议关联native的方法,要在webView的delegate里面添加
// 以 JSExport 协议关联 native 的方法self.content[@"native"] = self;添加完之后,要声明一个继承JSExport的协议,协议中声明供JS使用的OC的方法
[Objective-C] 查看源文件 复制代码
?
01
02
03
04
05
06
07
08
09
10
@protocol TestJSExport <JSExport>
JSExportAs
(calculateForJS /* handleFactorialCalculateWithNumber 作为js方法的别名 /,

  • (void)handleFactorialCalculateWithNumber:(NSNumber *)number
    );
    • (void)pushViewController:(NSString )view title:(NSString )title;

-(void)log:(NSString*)l;

@end

在OC中实现这些方法,这样就完成了!

如果是第二章方法,则只需要通过block的形式关联JavaScript function就可以了
!self.context[@"log"] = ^(NSString *str){NSLog(@"%@", str);};

三、OC调用JS

OC调用JS

在这个例子中,界面的所有View都是OC创建的,点击“交给JS处理计算阶乘”后,将textfild的数据传给JS,JS计算完成后在返回来!
这里面首先要获取JS里面的计算函数,在OC中,所有表示JS中对象,都用JSValue来创建,通过objectForKeyedSubscript方法或者直接使用下标的方法获取JS对象,然后使用callWithArguments方法来执行函数
[Objective-C] 查看源文件 复制代码
?
1
2
3
4
5
// 方法一. JSValue function = [self.context objectForKeyedSubscript:@"factorial"];
// 方法二.
JSValue
function = self.context[@"factorial"];
JSValue *result = [function callWithArguments:@[inputNumber]];
self.showLable.text = [NSString stringWithFormat:@"%@", [result toNumber]];

四、demo之外(慢慢在总结)1.JS注入
2.在OC中为JS创建对象
......

零碎的补充1:对于JS 函数中,参数中有函数的,在OC中用JSValue接收
[Objective-C] 查看源文件 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
// 比如:JS代码[/font] function myFunc({"text":"这里是文字","callbackFun":function(string){alert'string'}});

//OC代码中在.h的protocol中声明JS要调用的OC方法
//.h protocol中,函数名称要和JS中相同,这里接收的参数为JSValue
JSExportAs
(myFunc,
-(void) myFunc:(JSValue*)value
);

//在.m文件中,实现myFunc方法
-(void) myFunc:(JSValue*)value{

NSString * text = [value valueForProperty:@"text"];//打印"这里是文字"

JSValue * func = [value valueForProperty:@"callbackFun"]; //这里是JS参数中的func;

//调用这个函数
[func callWithArguments:@[@"这里是参数"]];

}

demo 直接下载:
[pan=https://github.com/shaojiankui/JavaScriptCore-Demo/archive/master.zip]|10[/pan]

收起阅读 »