HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

东翌学院和Dcloud官方合作跨平台APP开发培训机构

mui HBuilder

东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;
东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 ,谢谢Dcloud提供这么好的平台!
咨询报名QQ:2971611409 欢迎有意向学习的朋友加好友咨询!

继续阅读 »

东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;
东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 ,谢谢Dcloud提供这么好的平台!
咨询报名QQ:2971611409 欢迎有意向学习的朋友加好友咨询!

收起阅读 »

东翌学院和Dcloud官方合作跨平台APP开发培训机构

js HTML5
    东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!  
    东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;  
    东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 ,谢谢Dcloud提供这么好的平台!  
    咨询报名QQ:3391832203  欢迎有意向学习的朋友加好友咨询!
继续阅读 »
    东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!  
    东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;  
    东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 ,谢谢Dcloud提供这么好的平台!  
    咨询报名QQ:3391832203  欢迎有意向学习的朋友加好友咨询!
收起阅读 »

【文档】解决 MUI v3.2.0 headers 为 {'Content-Type': 'application/json'} 发起 POST 请求异常的问题

ajax headers application json mui post

Mui v3.2.0中ajax设置headers为{'Content-Type': 'application/json'}发起post请求,后端接收不到数据的解决方案(php为例)

问题场景

php部分

<?php  
    $name = $_POST['name'];  
    $password = $_POST['password'];  
    var_dump($name);  
    var_dump($password);  
?>  

mui.ajax()部分

mui.ajax({  
    url: 'http://192.168.12.74:80/test01.php',  
    type: 'post',  
        headers:{'Content-Type': 'application/json'},  
    data: {  
        name: 'dcloud',  
        password: '123456'  
    },  
    success: function(data) {  
        console.log(data);  
    },  
    error: function(xhr, type, errorThrown) {  
        console.log(type);  
    }  
});

控制台信息

Notice: Undefined index: name in test01.php on line 2
Notice: Undefined index: password in test01.php on line 3
我们按照通常的post方法去读取数据,发现并没有name和password这两个参数。

问题分析

可以参看下这篇文章《四种常见的 POST 提交数据方式》
当application/json这个Content-Type作为响应头时,我们需要手动处理一下:
从php://input 里获得原始输入流,再json_decode成对象。

方案一

php部分

<?php  
if ($_SERVER["CONTENT_TYPE"] == "application/json") {  
    $input = file_get_contents('php://input');  
    var_dump($input);  
    $object = json_decode($input);  
    $name = $object->name;  
    var_dump($name);  
}  
?>  

控制台信息一

'name=dcloud&password=123456' test01.php on line 4
null test01.php on line 7
此时,$input并不是一串json字符串,所以我们用json_decode去转换依旧是失败的,并不能拿到我们想要的数据。

mui.ajax()部分

mui.ajax()默认会对data里面的数据进行序列化,最终导致php接受到的是序列化以后的字符串。我们需要禁用对data的序列化(processData:false),并把参数对象序列化成json字符串(JSON.stringify())传给data。

mui.ajax({  
    url: 'http://192.168.12.74:80/test01.php',  
    type: 'post',  
    headers: {  
        'Content-Type': 'application/json'  
    },  
    processData: false,  
    data: JSON.stringify({  
        name: 'dcloud',  
        password: '123456'  
    }),  
    success: function(data) {  
        console.log(data);  
    },  
    error: function(xhr, type, errorThrown) {  
        console.log(type);  
    }  
});  

控制台信息二

'dcloud' test01.php on line 7
name参数的值被正确解析,问题解决。

方案二

只需修改php部分即可,方案一中我们在未设置processData属性为false时,获取的是一串序列化后的字符串'name=dcloud&password=123456'。我们对字符串进行截取,同样可以解析出我们想要的参数数据。

php部分

<?php  
    if($_SERVER["CONTENT_TYPE"]=="application/json"){  
        $input = file_get_contents('php://input');  
        $arr = explode("&", $input);  
    $narr = explode("=", $arr[0]);  
    $parr = explode("=", $arr[1]);  
    $name = $narr[1];  
    $password = $parr[1];  
        var_dump($name);  
        var_dump($password);  
    }  
?>  

mui.ajax()部分:

mui.ajax({  
    url: 'http://192.168.12.74:80/test02.php',  
    type: 'post',  
    headers: {  
        'Content-Type': 'application/json'  
    },  
    data: {  
        name: 'dcloud',  
        password: '123456'  
    },  
    success: function(data) {  
        console.log(data);  
    },  
    error: function(xhr, type, errorThrown) {  
        console.log(type);  
    }  
});  

控制台信息

'dcloud' test02.php on line 9
'123456' test02.php on line 10
通过对字符串的截取分组,最终取得我们想要的参数数据,但是此方法的缺点在于参数的顺序不明或数量太多会非常繁琐。

后续解决

Mui v3.3.0,将对此情况进行更加精确的处理,3.2.0版本遇到此问题可按照上面的方式进行处理数据。

继续阅读 »

Mui v3.2.0中ajax设置headers为{'Content-Type': 'application/json'}发起post请求,后端接收不到数据的解决方案(php为例)

问题场景

php部分

<?php  
    $name = $_POST['name'];  
    $password = $_POST['password'];  
    var_dump($name);  
    var_dump($password);  
?>  

mui.ajax()部分

mui.ajax({  
    url: 'http://192.168.12.74:80/test01.php',  
    type: 'post',  
        headers:{'Content-Type': 'application/json'},  
    data: {  
        name: 'dcloud',  
        password: '123456'  
    },  
    success: function(data) {  
        console.log(data);  
    },  
    error: function(xhr, type, errorThrown) {  
        console.log(type);  
    }  
});

控制台信息

Notice: Undefined index: name in test01.php on line 2
Notice: Undefined index: password in test01.php on line 3
我们按照通常的post方法去读取数据,发现并没有name和password这两个参数。

问题分析

可以参看下这篇文章《四种常见的 POST 提交数据方式》
当application/json这个Content-Type作为响应头时,我们需要手动处理一下:
从php://input 里获得原始输入流,再json_decode成对象。

方案一

php部分

<?php  
if ($_SERVER["CONTENT_TYPE"] == "application/json") {  
    $input = file_get_contents('php://input');  
    var_dump($input);  
    $object = json_decode($input);  
    $name = $object->name;  
    var_dump($name);  
}  
?>  

控制台信息一

'name=dcloud&password=123456' test01.php on line 4
null test01.php on line 7
此时,$input并不是一串json字符串,所以我们用json_decode去转换依旧是失败的,并不能拿到我们想要的数据。

mui.ajax()部分

mui.ajax()默认会对data里面的数据进行序列化,最终导致php接受到的是序列化以后的字符串。我们需要禁用对data的序列化(processData:false),并把参数对象序列化成json字符串(JSON.stringify())传给data。

mui.ajax({  
    url: 'http://192.168.12.74:80/test01.php',  
    type: 'post',  
    headers: {  
        'Content-Type': 'application/json'  
    },  
    processData: false,  
    data: JSON.stringify({  
        name: 'dcloud',  
        password: '123456'  
    }),  
    success: function(data) {  
        console.log(data);  
    },  
    error: function(xhr, type, errorThrown) {  
        console.log(type);  
    }  
});  

控制台信息二

'dcloud' test01.php on line 7
name参数的值被正确解析,问题解决。

方案二

只需修改php部分即可,方案一中我们在未设置processData属性为false时,获取的是一串序列化后的字符串'name=dcloud&password=123456'。我们对字符串进行截取,同样可以解析出我们想要的参数数据。

php部分

<?php  
    if($_SERVER["CONTENT_TYPE"]=="application/json"){  
        $input = file_get_contents('php://input');  
        $arr = explode("&", $input);  
    $narr = explode("=", $arr[0]);  
    $parr = explode("=", $arr[1]);  
    $name = $narr[1];  
    $password = $parr[1];  
        var_dump($name);  
        var_dump($password);  
    }  
?>  

mui.ajax()部分:

mui.ajax({  
    url: 'http://192.168.12.74:80/test02.php',  
    type: 'post',  
    headers: {  
        'Content-Type': 'application/json'  
    },  
    data: {  
        name: 'dcloud',  
        password: '123456'  
    },  
    success: function(data) {  
        console.log(data);  
    },  
    error: function(xhr, type, errorThrown) {  
        console.log(type);  
    }  
});  

控制台信息

'dcloud' test02.php on line 9
'123456' test02.php on line 10
通过对字符串的截取分组,最终取得我们想要的参数数据,但是此方法的缺点在于参数的顺序不明或数量太多会非常繁琐。

后续解决

Mui v3.3.0,将对此情况进行更加精确的处理,3.2.0版本遇到此问题可按照上面的方式进行处理数据。

收起阅读 »

我是设计,需要设计的找我,价格公道

外包

专业设计,价格公道,态度友好,两年设计经验,需要设计的找我。
扣扣:80883080

专业设计,价格公道,态度友好,两年设计经验,需要设计的找我。
扣扣:80883080

style.less的使用

HBuilder

@width: 200px; //定义一个变量width,里面存储了一个数据100px
@height: 200px;
@color1: rgba(188,166,188,0.8);
@color2: red;
@color3: aqua;
/*

  • 变量的作用,可以实现修改一处变幻多处的目的,同时缩小代码维护的范围,
  • 提高代码维护的效率,减少代码维护的成本。
    /
    /
  • 混入:将公用的一段代码写入到一个对应的class选择器中,将来使用到该段代码的部分我们可以用
  • 该class选择器替换,这个过程叫混入
  • 混入分为带参数的混入和不带参数的混入,但是为了提高代码的可复用性,我们一般使用带参数
  • 混入,另外参数可以设置默认值,多个参数之间用","隔开。
  • 注意:不带参数的混入适用于操作固定的时候,比如过渡效果,如果过渡时间相同时,我们可以使用
    /
    .transition(@time:1s) {
    -webkit-transition: @time;
    -moz-transition: @time;
    -ms-transition: @time;
    -o-transition: @time;
    transition: @time;
    }
    .translate(@distanceX:0, @distanceY:0) {
    -webkit-transform: translate(@distanceX,@distanceY);
    -moz-transform: translate(@distanceX,@distanceY);
    -ms-transform: translate(@distanceX,@distanceY);
    -o-transform: translate(@distanceX,@distanceY);
    transform: translate(@distanceX,@distanceY);
    }
    .out {
    width: (2
    @width);
    height: (2*@height);
    background-color: @color1;
    .first {
    width: @width;
    height: @height;
    background-color: @color3;
    .transition(2s);
    }
    .first:hover {
    .translate(0,800px);
    }
    .last {
    width: @width;
    height: @height;
    background-color: @color2;
    .transition(5s);
    }
    .last:hover {
    .translate(500px,-300px);
    }
    }
继续阅读 »

@width: 200px; //定义一个变量width,里面存储了一个数据100px
@height: 200px;
@color1: rgba(188,166,188,0.8);
@color2: red;
@color3: aqua;
/*

  • 变量的作用,可以实现修改一处变幻多处的目的,同时缩小代码维护的范围,
  • 提高代码维护的效率,减少代码维护的成本。
    /
    /
  • 混入:将公用的一段代码写入到一个对应的class选择器中,将来使用到该段代码的部分我们可以用
  • 该class选择器替换,这个过程叫混入
  • 混入分为带参数的混入和不带参数的混入,但是为了提高代码的可复用性,我们一般使用带参数
  • 混入,另外参数可以设置默认值,多个参数之间用","隔开。
  • 注意:不带参数的混入适用于操作固定的时候,比如过渡效果,如果过渡时间相同时,我们可以使用
    /
    .transition(@time:1s) {
    -webkit-transition: @time;
    -moz-transition: @time;
    -ms-transition: @time;
    -o-transition: @time;
    transition: @time;
    }
    .translate(@distanceX:0, @distanceY:0) {
    -webkit-transform: translate(@distanceX,@distanceY);
    -moz-transform: translate(@distanceX,@distanceY);
    -ms-transform: translate(@distanceX,@distanceY);
    -o-transform: translate(@distanceX,@distanceY);
    transform: translate(@distanceX,@distanceY);
    }
    .out {
    width: (2
    @width);
    height: (2*@height);
    background-color: @color1;
    .first {
    width: @width;
    height: @height;
    background-color: @color3;
    .transition(2s);
    }
    .first:hover {
    .translate(0,800px);
    }
    .last {
    width: @width;
    height: @height;
    background-color: @color2;
    .transition(5s);
    }
    .last:hover {
    .translate(500px,-300px);
    }
    }
收起阅读 »

让 dtpicker 可选择秒钟

让 dtpicker 可选择秒钟

效果图

使用方法
1.引入js
2.type =fulldatetime

     <link href="../../css/mui.picker.min.css" rel="stylesheet"/>  
     <script src="../../js/mui.picker.js"></script>    

      <link href="../../css/mui.ext.dtpicker.css" rel="stylesheet"/>  
     <script src="../../js/mui.ext.dtpicker.js"></script>  

<span  class="mui-badge mui-badge-inverted mui-badge-none mui-custom-date" data-options='{"type":"fulldatetime"}'  data-current='false'></span>

下面有附件可以下在 mui.ext.dtpicker.css 及 mui.ext.dtpicker.js

继续阅读 »

让 dtpicker 可选择秒钟

效果图

使用方法
1.引入js
2.type =fulldatetime

     <link href="../../css/mui.picker.min.css" rel="stylesheet"/>  
     <script src="../../js/mui.picker.js"></script>    

      <link href="../../css/mui.ext.dtpicker.css" rel="stylesheet"/>  
     <script src="../../js/mui.ext.dtpicker.js"></script>  

<span  class="mui-badge mui-badge-inverted mui-badge-none mui-custom-date" data-options='{"type":"fulldatetime"}'  data-current='false'></span>

下面有附件可以下在 mui.ext.dtpicker.css 及 mui.ext.dtpicker.js

收起阅读 »

东翌学院和Dcloud官方合作跨平台APP开发培训机构

PHP HTML5+
  东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!  
  东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 。  
  咨询报名QQ:3391832203  欢迎有意向学习的朋友加好友咨询! 谢谢Dcloud提供这么好的平台!
继续阅读 »
  东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!  
  东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 。  
  咨询报名QQ:3391832203  欢迎有意向学习的朋友加好友咨询! 谢谢Dcloud提供这么好的平台!
收起阅读 »

东翌学院和Dcloud官方合作跨平台APP开发培训机构

HTML5 mui HBuilder

东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,
HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
咨询报名QQ:2971611409欢迎有意向学习的朋友加好友咨询!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;
东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 ,

今天就晚上vip课程八点就要开班了,没有报名学习的小伙伴们抓紧时间报名学习啦,没有钱报名vip也可以学习的,可以分期0首付 12个月免利息 一个月也就是316. 是vip学员没有开权限的同学联系我给你们开权限!详情咨询QQ :2971611409Tel:17090057793

谢谢Dcloud提供这么好的平台!

继续阅读 »

东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,
HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
咨询报名QQ:2971611409欢迎有意向学习的朋友加好友咨询!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;
东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 ,

今天就晚上vip课程八点就要开班了,没有报名学习的小伙伴们抓紧时间报名学习啦,没有钱报名vip也可以学习的,可以分期0首付 12个月免利息 一个月也就是316. 是vip学员没有开权限的同学联系我给你们开权限!详情咨询QQ :2971611409Tel:17090057793

谢谢Dcloud提供这么好的平台!

收起阅读 »

东翌学院和Dcloud官方合作跨平台APP开发培训机构

PHP HTML5+ iOS
     东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,  

HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验。
咨询报名QQ:3391832203 欢迎有意向学习的朋友加好友咨询! 谢谢Dcloud提供这么好的平台!

继续阅读 »
     东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,  

HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验。
咨询报名QQ:3391832203 欢迎有意向学习的朋友加好友咨询! 谢谢Dcloud提供这么好的平台!

收起阅读 »

【交流分享】从小白的角度谈谈Android集成5+SDK的几种方式的应用场景

技术分享 Runtime widget 离线打包 5+sdk

背景

前一段时间因为项目需求,需要从Hbuilder中转移到原生层做开发,无奈只是熟悉一些java概念,但几乎没接触过Android开发,所以折腾了好久的离线打包。在你决定看这片文章之前,应该也要做好使劲折腾的心理准备。同时,最好看这篇文章之前对集成5 +sdk要有一些基本的概念,所以最好先看看下面这几篇文章,可能就不用继续看我的这点东西了。

1. 官方文档

相关集成概念

结合所有的官方文档以及官方SDK中的Hello-Integrate项目。我认为,官方对于离线打包有下面的这几种概念(叫法):
1.WebView集成方式 2. Widget集成方式 3. 独立应用集成方式 4. runtime集成方式 5. webApp集成方式

                                                                       
(截图取自官方文档及运行后的Hello-Integrate项目)

相信我,对于我这种首次接触集成SDK的小白来说,看到这一大堆名词及概念的时候,我是这样的

                                                                       

我猜想这么多的概念(叫法)也许是HB的开发者在开发的过程中遗留的问题,可能是项目组成员变动啊,文档整理人员变动啊巴拉巴拉导致的最终概念没有统一,纯属瞎猜。but……项目需求摆在那里,任务摆在那里,你总要解决对吧,懵逼也得硬着头皮上啊。我们开始折腾吧,先不管上面提到的五种叫法或者概念,直接开搞。

开搞

参照上面的那些文档中的方式,每一种集成弄他至少一遍,折腾的过程中可以查查资料,了解一下安卓原生开发的一些基本概念,比如Activity(关于Activity此处可以参考@AronWOng 分享的文章,简洁的介绍了Activity的意思 Android开机自启应用)。或者熟悉下项目的包结构,哪些文件是干啥的,比如Androidmanifest.xml是个什么鬼。折腾了好长一段时间之后,得出了以下的几个结论,注意此结论中并未指定集成方式的叫法(概念),暂时先直接讲要怎么做

  • 如果你只需要离线打包,比如在无法使用HB的云端打包情况下,那么就使用该篇文章中的方式 集成方式a1, 或者集成方式a2,该模式下,不涉及到自己写原生代码,只要按照官方介绍,将自己HB中的项目集成到eclipse或者Android Studio中打包。换种说法就是,如果你没有任何涉及原生开发的需求,并且需要在eclipse或者Android Studio中打包,就采用该模式。

  • 如果你有需求会涉及到原生开发,同时又要集成5 + app。以我的项目需求为例,我需要在PDA上开发5 + app,这款PDA就是个基于Android的手机,但是多了一个硬件:扫描器。我需要在App中监听到PDA上的扫描器相关事件,初始化扫描头,开始扫描,获取扫描结果等,并将扫描结果传入5 + App。由于NJS无法实现(或者可以说我不知道怎么使用NJS实现),这个时候我就要采用下面的文章中的做法 集成方式b1或者 集成方式b2。具体实现思路是,我在5 + App对应的Activity中,用java实现对扫描头的监听,并将扫描结果传入5 + app指定的webView,触发js事件,实现5 +app的监听(关于如何在集成SDK后,从java层获取指定webView并传入参数、触发js方法,参考android webApp集成方式 原生主动调用JS方法,此处感谢@DCloud_SDK_骁骑@杰世 的无私帮助与解答)

  • 如果你已经在原生层开发好了了App,但是可能在原生层的某些需求中,比如单个页面需要使用5 + 的能力,这种时候采用下面文章中的做法集成方式c

  • 如果你需要在5 +App或者说5 +App的某个特定的webView中,通过js调用原生层的方法,并将原生层方法的执行结果返回至js。还是以我的项目为例,还是说PDA,我需要在5 App中主动调用扫描头,并将扫描头扫描的结果传回5 +App,触发相关js方法。那么采用下面文章中的的方式集成方式d

总结

讲到这里,相信大家会对目前官方的提供的几种操作方式有一定的了解,那么,现在用我的理解来套用官方的概念(叫法)

  • 离线打包:只要不是在HB中进行云端打包,其他方式我们都可以理解为离线打包,因为你都要涉及到将5 +SDK集成到原生层。即便是最傻瓜式的该方法 集成方式a1,也是相当于把集成的工作给你做好了而已。

  • runtime集成方式,就是离线打包,就是集成方式a1,就是集成方式a2

  • 独立应用集成方式,就是Widget集成方式,就是官方SDK中的Hello-Integrate项目里的webApp集成方式,就是 集成方式b1,就是 集成方式b2

  • WebView集成方式,就是集成方式c,也可以理解为集成方式d,此处参考官方SDK中的Hello-Integrate项目里的WebView集成方式

  • Android平台第三方插件开发指导,就是集成方式d

最后的话

作为HB的用户已经三个月了,感谢DC提供一款如此好用的工具,衷心希望DC越走越好。同时,该文章参考了论坛中很多其他开发者的总结,在此一并感谢。第一次写,文章格式看起来有点乱,审美比较差导致……最后如果我的总结没有太严重的错误的话,那我觉得官方文档中关于5 +SDK的部分概念说明,是时候改改了,也希望大家指出我的错误

继续阅读 »

背景

前一段时间因为项目需求,需要从Hbuilder中转移到原生层做开发,无奈只是熟悉一些java概念,但几乎没接触过Android开发,所以折腾了好久的离线打包。在你决定看这片文章之前,应该也要做好使劲折腾的心理准备。同时,最好看这篇文章之前对集成5 +sdk要有一些基本的概念,所以最好先看看下面这几篇文章,可能就不用继续看我的这点东西了。

1. 官方文档

相关集成概念

结合所有的官方文档以及官方SDK中的Hello-Integrate项目。我认为,官方对于离线打包有下面的这几种概念(叫法):
1.WebView集成方式 2. Widget集成方式 3. 独立应用集成方式 4. runtime集成方式 5. webApp集成方式

                                                                       
(截图取自官方文档及运行后的Hello-Integrate项目)

相信我,对于我这种首次接触集成SDK的小白来说,看到这一大堆名词及概念的时候,我是这样的

                                                                       

我猜想这么多的概念(叫法)也许是HB的开发者在开发的过程中遗留的问题,可能是项目组成员变动啊,文档整理人员变动啊巴拉巴拉导致的最终概念没有统一,纯属瞎猜。but……项目需求摆在那里,任务摆在那里,你总要解决对吧,懵逼也得硬着头皮上啊。我们开始折腾吧,先不管上面提到的五种叫法或者概念,直接开搞。

开搞

参照上面的那些文档中的方式,每一种集成弄他至少一遍,折腾的过程中可以查查资料,了解一下安卓原生开发的一些基本概念,比如Activity(关于Activity此处可以参考@AronWOng 分享的文章,简洁的介绍了Activity的意思 Android开机自启应用)。或者熟悉下项目的包结构,哪些文件是干啥的,比如Androidmanifest.xml是个什么鬼。折腾了好长一段时间之后,得出了以下的几个结论,注意此结论中并未指定集成方式的叫法(概念),暂时先直接讲要怎么做

  • 如果你只需要离线打包,比如在无法使用HB的云端打包情况下,那么就使用该篇文章中的方式 集成方式a1, 或者集成方式a2,该模式下,不涉及到自己写原生代码,只要按照官方介绍,将自己HB中的项目集成到eclipse或者Android Studio中打包。换种说法就是,如果你没有任何涉及原生开发的需求,并且需要在eclipse或者Android Studio中打包,就采用该模式。

  • 如果你有需求会涉及到原生开发,同时又要集成5 + app。以我的项目需求为例,我需要在PDA上开发5 + app,这款PDA就是个基于Android的手机,但是多了一个硬件:扫描器。我需要在App中监听到PDA上的扫描器相关事件,初始化扫描头,开始扫描,获取扫描结果等,并将扫描结果传入5 + App。由于NJS无法实现(或者可以说我不知道怎么使用NJS实现),这个时候我就要采用下面的文章中的做法 集成方式b1或者 集成方式b2。具体实现思路是,我在5 + App对应的Activity中,用java实现对扫描头的监听,并将扫描结果传入5 + app指定的webView,触发js事件,实现5 +app的监听(关于如何在集成SDK后,从java层获取指定webView并传入参数、触发js方法,参考android webApp集成方式 原生主动调用JS方法,此处感谢@DCloud_SDK_骁骑@杰世 的无私帮助与解答)

  • 如果你已经在原生层开发好了了App,但是可能在原生层的某些需求中,比如单个页面需要使用5 + 的能力,这种时候采用下面文章中的做法集成方式c

  • 如果你需要在5 +App或者说5 +App的某个特定的webView中,通过js调用原生层的方法,并将原生层方法的执行结果返回至js。还是以我的项目为例,还是说PDA,我需要在5 App中主动调用扫描头,并将扫描头扫描的结果传回5 +App,触发相关js方法。那么采用下面文章中的的方式集成方式d

总结

讲到这里,相信大家会对目前官方的提供的几种操作方式有一定的了解,那么,现在用我的理解来套用官方的概念(叫法)

  • 离线打包:只要不是在HB中进行云端打包,其他方式我们都可以理解为离线打包,因为你都要涉及到将5 +SDK集成到原生层。即便是最傻瓜式的该方法 集成方式a1,也是相当于把集成的工作给你做好了而已。

  • runtime集成方式,就是离线打包,就是集成方式a1,就是集成方式a2

  • 独立应用集成方式,就是Widget集成方式,就是官方SDK中的Hello-Integrate项目里的webApp集成方式,就是 集成方式b1,就是 集成方式b2

  • WebView集成方式,就是集成方式c,也可以理解为集成方式d,此处参考官方SDK中的Hello-Integrate项目里的WebView集成方式

  • Android平台第三方插件开发指导,就是集成方式d

最后的话

作为HB的用户已经三个月了,感谢DC提供一款如此好用的工具,衷心希望DC越走越好。同时,该文章参考了论坛中很多其他开发者的总结,在此一并感谢。第一次写,文章格式看起来有点乱,审美比较差导致……最后如果我的总结没有太严重的错误的话,那我觉得官方文档中关于5 +SDK的部分概念说明,是时候改改了,也希望大家指出我的错误

收起阅读 »

图像(头像)选择,截取,压缩,上传的分享

头像裁剪 技术分享

思路:

  1. 通过拍照或者选择一张照片
  2. 将照片作为底,一个正方形容器作为边界。通过移动正方形容器获取所需图形的边界。
  3. 截取图片,并压缩到指定大小。
  4. 上传到服务器。

具体实现:

  1. 获取照片资源
    1.1 从相册选择

    function chooseImgFromAlbums() {  
    plus.gallery.pick(function(file) {  
    changeToLocalUrl(file);  
    }, function(err) {  
    console.log(JSON.stringify(err));  
    }, {  
    filter: 'image',  
    multiple: false  
    });  
    }

    1.2 拍照

    function chooseImgFromPictures() {  
    var cmr = plus.camera.getCamera();  
    
    cmr.captureImage(function(file) {  
    changeToLocalUrl(file);  
    }, function(err) {  
    console.log(JSON.stringify(err));  
    }, {  
    index: '2',  
    });  
    }

    1.3 相册选择和拍照选择返回的路径都是绝对路径,为了让其显示在img里面,我们需要转换为本地路径URL地址。此处打开一张新页面来对图片进行处理

    function changeToLocalUrl(path) {  
    plus.io.resolveLocalFileSystemURL(path, function(entry) {  
    openWindow('uploadImg.html?src='   entry.toLocalURL());  
    });  
    }
  2. 以一个正方形容器截取图片。
    此处,自己写了一些简单的js来做图像截取,这些js修改起来也很方便。
    首先,看一下整个页面:

功能很简单:点击放大,缩小可以放大缩小正方形的区域。用手指移动正方形,来改变正方形所包含的内容。

实现的思路:通过监听正方形的touchstart和touchmove事件,改变它的top,left值。实现移动。

具体代码如下:

var Clip = {  
  size: 12, //这个表示正方形目前的边长,乘上一个基数就是当前的像素值  
  range: {}, //用来控制正方形left和top的极限值,以免移出边界  
  topCss: 0,  //表示当前的top值  
  leftCss: 0,  //表示当前的left值  
  touchX: 0,  //当前的手指所处的X坐标  
  touchY: 0, //当前手指的Y坐标  
  timer: null,  //用来做touchmove的函数节流,以免连续触发touchmove事件导致的效率问题  
  changeBase: function(index) {  //这个函数用来改变正方形的边长,一般还需要设置最大边长和最小边长  
    this.size  = index;  

    $('#clip').css({  
      height: this.size   'rem',  
      width: this.size   'rem',  
      lineHeight: this.size   'rem'  
    });  

    this.changeRange();  //边长改变,将引起当前top, left和range的变化,统一调changeRange的方法来修改  
  },  
  changeRange: function() {  //这个方法用来计算初始top, left以及边界值。其算法收到当前页面布局影响,需要自行修改  
    this.topCss =($('body').height() - baseSize * extraHeight - baseSize * this.size) / 2   baseSize * headerHeight;  
    this.leftCss = ($('body').width() - baseSize * this.size) / 2;  
    this.changeClipStyle(this.leftCss, this.topCss);  

    //极限值,需控制不超出图片区域  
    var minTop = ($('body').height() - baseSize * extraHeight - $('#img').height()) / 2   baseSize * headerHeight;  
    var maxTop = $('body').height() - ($('body').height() - baseSize * extraHeight - $('#img').height()) / 2 -   
              baseSize * footerHeght - baseSize * this.size;  

    var minLeft = 0;  
    var maxLeft = $('body').width() - baseSize * this.size;  
    this.range = {  
      minTop: minTop,  
      maxTop: maxTop,  
      minLeft: minLeft,  
      maxLeft: maxLeft  
    };  

  },  
  initEvent: function() {  //事件初始化  
    mui('body').on('tap', '#enlarge', function(e) {  
      Clip.changeBase(1);  
    });  
    mui('body').on('tap', '#reduce', function(e) {  
      Clip.changeBase(-1);  
    })  

    var clip = document.getElementById('clip');  

    //开始接触的时候,记录当前的手指位置  
    clip.addEventListener('touchstart', function(event) {  
      Clip.touchX = event.touches ? event.touches[0].clientX : event.screenX;  
      Clip.touchY = event.touches ? event.touches[0].clientY : event.screenY;  
      event.preventDefault();  
    });  

    //移动后,记录新的位置,设置新的top和left值  
    clip.addEventListener('touchmove', function(event) {  
      //设置20ms的事件  
      if(Clip.timer != null) {  //函数节流  
        return;  
      }  
      Clip.timer = setTimeout(function() {  
        var x = event.touches ? event.touches[0].clientX : event.screenX;  
        var y = event.touches ? event.touches[0].clientY : event.screenY;  

        var disX = x - Clip.touchX;  
        var disY = y - Clip.touchY;  

        var nowLeft = Clip.leftCss   disX;  
        var nowTop = Clip.topCss   disY;  

        if(nowLeft < Clip.range.minLeft) {  
          nowLeft = Clip.range.minLeft;  
        }  
        if(nowLeft > Clip.range.maxLeft) {  
          nowLeft = Clip.range.maxLeft;  
        }  
        if(nowTop < Clip.range.minTop) {  
          nowTop = Clip.range.minTop;  
        }  
        if(nowTop > Clip.range.maxTop) {  
          nowTop = Clip.range.maxTop;  
        }  

        Clip.changeClipStyle(nowLeft, nowTop);  

        Clip.touchX = x;  
        Clip.touchY = y;  
        Clip.timer = null;  
      }, 20);  

    });  

  },  
  //设置新的样式,并改变当前的top和left值  
  changeClipStyle: function(leftCss, topCss) {  
    $('#clip').css({  
      left: leftCss   'px',  
      top: topCss   'px'  
    });  
    Clip.leftCss = leftCss;  
    Clip.topCss = topCss;  
  }  
}
  1. 移动到正方形到合适的区域后,点击完成,就将完成截取图片和压缩图片的功能。
    主要思路是: 调用plus.zip.compressImage函数来完成截取和压缩

3.1. 首先,需要计算出宽高的百分比和离图片左上角的top和left的百分比。同样根据布局不同,计算方式不同。

//获取width和height的百分比  
var widthPix = (Clip.size * baseSize / $('#img').width()).toFixed(2) * 100;  
var heightPix = (Clip.size * baseSize / $('#img').height()).toFixed(2) * 100;  
//获取左上角位置百分比  
var topPix = ((Clip.topCss - Clip.range.minTop) / $('#img').height()).toFixed(2) * 100;  
var leftPix = (Clip.leftCss / $('#img').width()).toFixed(2) * 100;

3.2 截取

//对图片进行裁剪  
plus.zip.compressImage(  
  {  
    src: search.src, //src在这里是第一步Url里的src。也就是本地路径  
    dst: '_doc/a.jpg',  
    overwrite: true,  
    clip: {  
      top: topPix   '%',  
      left: leftPix   '%',  
      width: widthPix   '%',  
      height: heightPix   '%'  
    }  
  },  
  function(e) {  
    resizeImage(e.target); //压缩图片  
  }  
);

3.3 截取图片之后,我们还需要进行压缩。

//再对图片进行压缩为270*270,再上传到服务器  
function resizeImage(src) {  
  plus.zip.compressImage(  
    {  
      src: src,  
      dst: '_doc/a.jpg',  
      overwrite: true,  
      width: '270px', //这里指定了宽度,同样可以修改  
      format: 'jpg',  
      quality: 100  //图片质量不再修改,以免失真  
    },  
    function(e) {  
      plus.nativeUI.closeWaiting();  
      uploadImg(e.target);  //上传图片, e.target存的是本地路径!  
    },  
    function(err) {  
      plus.nativeUI.alert('未知错误!',function() {  
        mui.back();  
      });  
    }  
  );  
}
  1. 上传图片到服务器。上传图片用的是plus.uploader,数据格式符合Multipart/form-data规范,也就是平时input type='file'那样一样

    function uploadImg(src) {  
    var task = plus.uploader.createUpload(ajaxUrl, {  
    method: 'post',   
    blocksize:204800,  
    timeout: 10  
    });  
    
    task.addFile(src, {key: 'headImg'});  
    
    task.addData('type', 'uploadImg');  
    task.addData('userId', );  
    task.addEventListener('statechanged', stateChanged, false);  
    task.start();  
    
    function stateChanged(upload, status) {  
    if ( upload.state == 4 && status == 200 ) {  
      plus.uploader.clear();  //清除上传  
      console.log(upload.responseText);  //服务器返回存在这里  
    }  
    }  
    }

    好了,就这么多,代码比较简单,如果有其他能用的,欢迎修改。源码就不上传了,因为是公司项目的一个子功能,主要代码实现都在这里了。直接用了jQuery和mui。当然用原生写也OK。

继续阅读 »

思路:

  1. 通过拍照或者选择一张照片
  2. 将照片作为底,一个正方形容器作为边界。通过移动正方形容器获取所需图形的边界。
  3. 截取图片,并压缩到指定大小。
  4. 上传到服务器。

具体实现:

  1. 获取照片资源
    1.1 从相册选择

    function chooseImgFromAlbums() {  
    plus.gallery.pick(function(file) {  
    changeToLocalUrl(file);  
    }, function(err) {  
    console.log(JSON.stringify(err));  
    }, {  
    filter: 'image',  
    multiple: false  
    });  
    }

    1.2 拍照

    function chooseImgFromPictures() {  
    var cmr = plus.camera.getCamera();  
    
    cmr.captureImage(function(file) {  
    changeToLocalUrl(file);  
    }, function(err) {  
    console.log(JSON.stringify(err));  
    }, {  
    index: '2',  
    });  
    }

    1.3 相册选择和拍照选择返回的路径都是绝对路径,为了让其显示在img里面,我们需要转换为本地路径URL地址。此处打开一张新页面来对图片进行处理

    function changeToLocalUrl(path) {  
    plus.io.resolveLocalFileSystemURL(path, function(entry) {  
    openWindow('uploadImg.html?src='   entry.toLocalURL());  
    });  
    }
  2. 以一个正方形容器截取图片。
    此处,自己写了一些简单的js来做图像截取,这些js修改起来也很方便。
    首先,看一下整个页面:

功能很简单:点击放大,缩小可以放大缩小正方形的区域。用手指移动正方形,来改变正方形所包含的内容。

实现的思路:通过监听正方形的touchstart和touchmove事件,改变它的top,left值。实现移动。

具体代码如下:

var Clip = {  
  size: 12, //这个表示正方形目前的边长,乘上一个基数就是当前的像素值  
  range: {}, //用来控制正方形left和top的极限值,以免移出边界  
  topCss: 0,  //表示当前的top值  
  leftCss: 0,  //表示当前的left值  
  touchX: 0,  //当前的手指所处的X坐标  
  touchY: 0, //当前手指的Y坐标  
  timer: null,  //用来做touchmove的函数节流,以免连续触发touchmove事件导致的效率问题  
  changeBase: function(index) {  //这个函数用来改变正方形的边长,一般还需要设置最大边长和最小边长  
    this.size  = index;  

    $('#clip').css({  
      height: this.size   'rem',  
      width: this.size   'rem',  
      lineHeight: this.size   'rem'  
    });  

    this.changeRange();  //边长改变,将引起当前top, left和range的变化,统一调changeRange的方法来修改  
  },  
  changeRange: function() {  //这个方法用来计算初始top, left以及边界值。其算法收到当前页面布局影响,需要自行修改  
    this.topCss =($('body').height() - baseSize * extraHeight - baseSize * this.size) / 2   baseSize * headerHeight;  
    this.leftCss = ($('body').width() - baseSize * this.size) / 2;  
    this.changeClipStyle(this.leftCss, this.topCss);  

    //极限值,需控制不超出图片区域  
    var minTop = ($('body').height() - baseSize * extraHeight - $('#img').height()) / 2   baseSize * headerHeight;  
    var maxTop = $('body').height() - ($('body').height() - baseSize * extraHeight - $('#img').height()) / 2 -   
              baseSize * footerHeght - baseSize * this.size;  

    var minLeft = 0;  
    var maxLeft = $('body').width() - baseSize * this.size;  
    this.range = {  
      minTop: minTop,  
      maxTop: maxTop,  
      minLeft: minLeft,  
      maxLeft: maxLeft  
    };  

  },  
  initEvent: function() {  //事件初始化  
    mui('body').on('tap', '#enlarge', function(e) {  
      Clip.changeBase(1);  
    });  
    mui('body').on('tap', '#reduce', function(e) {  
      Clip.changeBase(-1);  
    })  

    var clip = document.getElementById('clip');  

    //开始接触的时候,记录当前的手指位置  
    clip.addEventListener('touchstart', function(event) {  
      Clip.touchX = event.touches ? event.touches[0].clientX : event.screenX;  
      Clip.touchY = event.touches ? event.touches[0].clientY : event.screenY;  
      event.preventDefault();  
    });  

    //移动后,记录新的位置,设置新的top和left值  
    clip.addEventListener('touchmove', function(event) {  
      //设置20ms的事件  
      if(Clip.timer != null) {  //函数节流  
        return;  
      }  
      Clip.timer = setTimeout(function() {  
        var x = event.touches ? event.touches[0].clientX : event.screenX;  
        var y = event.touches ? event.touches[0].clientY : event.screenY;  

        var disX = x - Clip.touchX;  
        var disY = y - Clip.touchY;  

        var nowLeft = Clip.leftCss   disX;  
        var nowTop = Clip.topCss   disY;  

        if(nowLeft < Clip.range.minLeft) {  
          nowLeft = Clip.range.minLeft;  
        }  
        if(nowLeft > Clip.range.maxLeft) {  
          nowLeft = Clip.range.maxLeft;  
        }  
        if(nowTop < Clip.range.minTop) {  
          nowTop = Clip.range.minTop;  
        }  
        if(nowTop > Clip.range.maxTop) {  
          nowTop = Clip.range.maxTop;  
        }  

        Clip.changeClipStyle(nowLeft, nowTop);  

        Clip.touchX = x;  
        Clip.touchY = y;  
        Clip.timer = null;  
      }, 20);  

    });  

  },  
  //设置新的样式,并改变当前的top和left值  
  changeClipStyle: function(leftCss, topCss) {  
    $('#clip').css({  
      left: leftCss   'px',  
      top: topCss   'px'  
    });  
    Clip.leftCss = leftCss;  
    Clip.topCss = topCss;  
  }  
}
  1. 移动到正方形到合适的区域后,点击完成,就将完成截取图片和压缩图片的功能。
    主要思路是: 调用plus.zip.compressImage函数来完成截取和压缩

3.1. 首先,需要计算出宽高的百分比和离图片左上角的top和left的百分比。同样根据布局不同,计算方式不同。

//获取width和height的百分比  
var widthPix = (Clip.size * baseSize / $('#img').width()).toFixed(2) * 100;  
var heightPix = (Clip.size * baseSize / $('#img').height()).toFixed(2) * 100;  
//获取左上角位置百分比  
var topPix = ((Clip.topCss - Clip.range.minTop) / $('#img').height()).toFixed(2) * 100;  
var leftPix = (Clip.leftCss / $('#img').width()).toFixed(2) * 100;

3.2 截取

//对图片进行裁剪  
plus.zip.compressImage(  
  {  
    src: search.src, //src在这里是第一步Url里的src。也就是本地路径  
    dst: '_doc/a.jpg',  
    overwrite: true,  
    clip: {  
      top: topPix   '%',  
      left: leftPix   '%',  
      width: widthPix   '%',  
      height: heightPix   '%'  
    }  
  },  
  function(e) {  
    resizeImage(e.target); //压缩图片  
  }  
);

3.3 截取图片之后,我们还需要进行压缩。

//再对图片进行压缩为270*270,再上传到服务器  
function resizeImage(src) {  
  plus.zip.compressImage(  
    {  
      src: src,  
      dst: '_doc/a.jpg',  
      overwrite: true,  
      width: '270px', //这里指定了宽度,同样可以修改  
      format: 'jpg',  
      quality: 100  //图片质量不再修改,以免失真  
    },  
    function(e) {  
      plus.nativeUI.closeWaiting();  
      uploadImg(e.target);  //上传图片, e.target存的是本地路径!  
    },  
    function(err) {  
      plus.nativeUI.alert('未知错误!',function() {  
        mui.back();  
      });  
    }  
  );  
}
  1. 上传图片到服务器。上传图片用的是plus.uploader,数据格式符合Multipart/form-data规范,也就是平时input type='file'那样一样

    function uploadImg(src) {  
    var task = plus.uploader.createUpload(ajaxUrl, {  
    method: 'post',   
    blocksize:204800,  
    timeout: 10  
    });  
    
    task.addFile(src, {key: 'headImg'});  
    
    task.addData('type', 'uploadImg');  
    task.addData('userId', );  
    task.addEventListener('statechanged', stateChanged, false);  
    task.start();  
    
    function stateChanged(upload, status) {  
    if ( upload.state == 4 && status == 200 ) {  
      plus.uploader.clear();  //清除上传  
      console.log(upload.responseText);  //服务器返回存在这里  
    }  
    }  
    }

    好了,就这么多,代码比较简单,如果有其他能用的,欢迎修改。源码就不上传了,因为是公司项目的一个子功能,主要代码实现都在这里了。直接用了jQuery和mui。当然用原生写也OK。

收起阅读 »