
多多客微信百度支付宝三端合一小程序平台正式上线
多多客DOODOOKE微信、百度、支付宝三端合一小程序SaaS平台今日正式上线!
开年集齐BAT,多多客DOODOOKE与你一起开启新篇章!
一次制作 三端发布 同时管理
商家只需要在多多客管理后台制作一次小程序,即可在微信、百度、支付宝三大平台同时发布和管理。
多多客三端合一小程序平台帮助商家快速布局小程序,跨越小程序开发的高门槛、高成本,一次性获取微信、支付宝、百度全域千亿级流量,同时节省小程序的制作时间和制作成本。
商家可以在同一个后台统一管理微信、百度、支付宝三端用户和订单等数据,大大优化和完善了商家对小程序的管理效率和使用体验,制定实时营销策略,更加高效运营,降低成本。
随着微信、百度、支付宝、今日头条等越来越多的流量巨头入局小程序,未来小程序将成为商家运营的标配,一款能够同时运行在不同“超级App”中的小程序就显得格外重要。
商家只需要在多多客(doodooke.com)后台通过在线制作,扫码授权,点击发布简单3步,即可轻松拥有微信、百度、支付宝三大平台的小程序。再加上多多客原有的完全可视化拖拽,N+营销工具引流,海量优质行业模板等能力,带给商家更高质量的小程序产品和更完善的小程序服务体系。
多多客DOODOOKE微信、百度、支付宝三端合一小程序SaaS平台今日正式上线!
开年集齐BAT,多多客DOODOOKE与你一起开启新篇章!
一次制作 三端发布 同时管理
商家只需要在多多客管理后台制作一次小程序,即可在微信、百度、支付宝三大平台同时发布和管理。
多多客三端合一小程序平台帮助商家快速布局小程序,跨越小程序开发的高门槛、高成本,一次性获取微信、支付宝、百度全域千亿级流量,同时节省小程序的制作时间和制作成本。
商家可以在同一个后台统一管理微信、百度、支付宝三端用户和订单等数据,大大优化和完善了商家对小程序的管理效率和使用体验,制定实时营销策略,更加高效运营,降低成本。
随着微信、百度、支付宝、今日头条等越来越多的流量巨头入局小程序,未来小程序将成为商家运营的标配,一款能够同时运行在不同“超级App”中的小程序就显得格外重要。
商家只需要在多多客(doodooke.com)后台通过在线制作,扫码授权,点击发布简单3步,即可轻松拥有微信、百度、支付宝三大平台的小程序。再加上多多客原有的完全可视化拖拽,N+营销工具引流,海量优质行业模板等能力,带给商家更高质量的小程序产品和更完善的小程序服务体系。
收起阅读 »
多个页面引入同一个组件,这个组件会被重复打包
uni-app开发小程序,index页面引入a、b、c三个组件,article页面引入b、c两个组件,打包之后,发现b、c组件被打到index页面中,也被打到了article页面中了;这样来看,组件不能单独存在,被多少页面使用,就会被重复打包多少次。
这样对小程序项目来说不太友好,因为小程序有项目代码大小限制,超过一定大小就不能开发了,组件不能重复打包的问题,导致小程序中有许多重复代码了。
有哪位大佬知道更好的解决方案,求告知!
uni-app开发小程序,index页面引入a、b、c三个组件,article页面引入b、c两个组件,打包之后,发现b、c组件被打到index页面中,也被打到了article页面中了;这样来看,组件不能单独存在,被多少页面使用,就会被重复打包多少次。
这样对小程序项目来说不太友好,因为小程序有项目代码大小限制,超过一定大小就不能开发了,组件不能重复打包的问题,导致小程序中有许多重复代码了。
有哪位大佬知道更好的解决方案,求告知!
收起阅读 »

DCloud产品使用许可说明
DCloud为开发者提供包括HBuilder、uni-app、uni-app x、uni小程序sdk、HTML5+、MUI、wap2app等开发工具,帮助开发者快速、低成本制作移动互联网多端应用。
DCloud上述开发工具均为免费产品。
您可以自由下载、使用这些工具而不需要向DCloud付费。
DCloud所拥有的知识产权,包括但不限于商标、专利、著作权、商业秘密、专有数据、源码,仍归DCloud所有。
您使用本工具开发的代码及输出物,包括但不限于网站、移动应用,其知识产权归属您所有。
如果您的移动应用中内嵌了DCloud的Runtime或sdk,该Runtime或sdk的知识产权仍然属于DCloud。
类似于您开发的应用内嵌了jvm或.net framework,虽然您的java代码的著作权属于您,但jvm等三方runtime的知识产权仍归原作者所有。
-
HBuilderX产品协议:见HBuilderX安装目录下的《license.md》。HBuilderX基于C++编写,其许可协议适用于任何大型公司。华为公司法务在审核HBuilderX许可协议后认为无需单独与DCloud签署协议,可直接在华为内部使用HBuilderX。
-
uni-app(含uni-app x、5+app)的开源部分为Apache开源协议:https://github.com/dcloudio/uni-app/blob/master/LICENSE。完整的用户协议见:https://dcloud.io/license/uni-app.html
-
使用DCloud的app引擎,按中国法律要求,需要在app的隐私协议中加入如下隐私协议:https://dcloud.io/license/appprivacy.html
-
如使用uni-ad广告变现服务,按中国法律要求,需要在app的隐私协议中加入如下隐私协议:https://dcloud.io/license/uni-ad.html
-
uni小程序sdk为免费产品,sdk包的根目录下有license.md文件,内容与uni-app相同。同时该产品面向大型公司签署保密协议后可开放源码。
-
MUI为MIT开源协议:https://github.com/dcloudio/mui
-
云打包:DCloud的App云打包服务为免费产品,同时也支持离线打包。开发者需注意节约免费的公共资源,调试时多使用自定义基座,避免频繁打包。如果云打包次数过于频繁,会收取资源占用费用。
-
DCloud通过论坛、qq群提供正常工作时间技术支持。对技术支持服务要求较高的开发者可额外购买付费技术支持
-
部分政府国企事业单位,对使用的产品和服务强制要求提供商业化的保障,不能使用免费产品。针对此类情况DCloud提供商业授权许可+企业级服务的打包产品,如需购买请联系 Email:bd@dcloud.io 。(请勿在本帖中评论,商务同事不在论坛中)。
-
如果您使用DCloud工具不是为了开发应用,而是基于DCloud工具二次开发,为其他开发者提供开发服务,除非您通过DCloud插件市场为开发者服务,否则您需要单独获取DCloud的书面许可。
-
uniCloud相关产品为代售模式,DCloud集成第三方云服务,并以优惠价格提供给开发者,另见协议:https://dcloud.io/license/uniCloud.html
DCloud为开发者提供包括HBuilder、uni-app、uni-app x、uni小程序sdk、HTML5+、MUI、wap2app等开发工具,帮助开发者快速、低成本制作移动互联网多端应用。
DCloud上述开发工具均为免费产品。
您可以自由下载、使用这些工具而不需要向DCloud付费。
DCloud所拥有的知识产权,包括但不限于商标、专利、著作权、商业秘密、专有数据、源码,仍归DCloud所有。
您使用本工具开发的代码及输出物,包括但不限于网站、移动应用,其知识产权归属您所有。
如果您的移动应用中内嵌了DCloud的Runtime或sdk,该Runtime或sdk的知识产权仍然属于DCloud。
类似于您开发的应用内嵌了jvm或.net framework,虽然您的java代码的著作权属于您,但jvm等三方runtime的知识产权仍归原作者所有。
-
HBuilderX产品协议:见HBuilderX安装目录下的《license.md》。HBuilderX基于C++编写,其许可协议适用于任何大型公司。华为公司法务在审核HBuilderX许可协议后认为无需单独与DCloud签署协议,可直接在华为内部使用HBuilderX。
-
uni-app(含uni-app x、5+app)的开源部分为Apache开源协议:https://github.com/dcloudio/uni-app/blob/master/LICENSE。完整的用户协议见:https://dcloud.io/license/uni-app.html
-
使用DCloud的app引擎,按中国法律要求,需要在app的隐私协议中加入如下隐私协议:https://dcloud.io/license/appprivacy.html
-
如使用uni-ad广告变现服务,按中国法律要求,需要在app的隐私协议中加入如下隐私协议:https://dcloud.io/license/uni-ad.html
-
uni小程序sdk为免费产品,sdk包的根目录下有license.md文件,内容与uni-app相同。同时该产品面向大型公司签署保密协议后可开放源码。
-
MUI为MIT开源协议:https://github.com/dcloudio/mui
-
云打包:DCloud的App云打包服务为免费产品,同时也支持离线打包。开发者需注意节约免费的公共资源,调试时多使用自定义基座,避免频繁打包。如果云打包次数过于频繁,会收取资源占用费用。
-
DCloud通过论坛、qq群提供正常工作时间技术支持。对技术支持服务要求较高的开发者可额外购买付费技术支持
-
部分政府国企事业单位,对使用的产品和服务强制要求提供商业化的保障,不能使用免费产品。针对此类情况DCloud提供商业授权许可+企业级服务的打包产品,如需购买请联系 Email:bd@dcloud.io 。(请勿在本帖中评论,商务同事不在论坛中)。
-
如果您使用DCloud工具不是为了开发应用,而是基于DCloud工具二次开发,为其他开发者提供开发服务,除非您通过DCloud插件市场为开发者服务,否则您需要单独获取DCloud的书面许可。
-
uniCloud相关产品为代售模式,DCloud集成第三方云服务,并以优惠价格提供给开发者,另见协议:https://dcloud.io/license/uniCloud.html

uni-push 1.0 使用指南
> 文档已迁移至新链接:https://uniapp.dcloud.net.cn/unipush-v1.html
> 如有疑问,可以单独发贴咨询。
> 文档已迁移至新链接:https://uniapp.dcloud.net.cn/unipush-v1.html
> 如有疑问,可以单独发贴咨询。

uni-app 中如何打开外部应用,如:浏览器、淘宝、AppStore、QQ等
我们在开发 App 应用中,经常会遇到打开第三方程序的场景,比如打开手机淘宝、通过第三方浏览器打开一个 url 等等。
App不像网页可以使用http超链接互相跳转,但手机os设计了scheme机制,可以通过特殊的链接互相调起。
比如手机淘宝,其安装后会在手机os中会注册一个scheme协议,taobao://
。
这种协议还支持参数,比如taobao://s.taobao.com/search?q=uni-app
启动淘宝并打开搜索页面搜索uni-app。
在uni-app/5+App中,可以通过scheme呼起其他App,也支持给自己的App设置scheme参数。
这个功能小程序并不支持,属于App端的扩展API。
打开外部scheme的API是plus.runtime.openURL()
。查看文档:http://www.html5plus.org/doc/zh_cn/runtime.html
打开第三方程序
打开第三方程序,我们需要使用 runtime 模块,下面我罗列两个相关的方法。其他操作请详读文档。
-
调用外部浏览器打开指定的URL
plus.runtime.openURL( url, errorCB, identity );
- url: ( String ) 必选 要打开的URL地址
字符串类型,各平台支持的地址类型存在差异,参考平台URL支持表。 - errorCB: ( OpenErrorCallback ) 可选 打开URL地址失败的回调
打开指定URL地址失败时回调,并返回失败信息。 - identity: ( String ) 可选 指定打开URL地址的程序名称
在iOS平台此参数被忽略,在Android平台为程序包名,如果指定的包名不存在,则打开URL地址失败。
<template> <view> <button class="button" type="primary" @click="open(0)">使用第三方程序打开指定URL</button> </view> </template>
<script> export default { data() { return { url: 'https://uniapp.dcloud.io/' }; }, onLoad(op) {}, methods: { open(types) { plus.runtime.openURL(this.url, function(res) { console.log(res); }); } } }; </script>
- url: ( String ) 必选 要打开的URL地址
-
调用第三方程序
plus.runtime.launchApplication( appInf, errorCB );
- appInf: ( ApplicationInf ) 必选 要启动第三方程序的描述信息
- errorCB: ( LaunchErrorCallback ) 必选 启动第三方程序操作失败的回调函数
启动第三方程序失败时回调,并返回失败信息。
<template> <view> <button class="button" type="primary" @click="launchApp">打开淘宝</button> </view> </template>
<script> export default { data() { return { url: 'https://uniapp.dcloud.io/' }; }, onLoad(op) {}, methods: { launchApp() { let _this = this; // 判断平台 if (plus.os.name == 'Android') { plus.runtime.launchApplication( { pname: 'com.taobao.taobao' }, function(e) { console.log('Open system default browser failed: ' + e.message); } ); } else if (plus.os.name == 'iOS') { plus.runtime.launchApplication({ action: 'taobao://' }, function(e) { console.log('Open system default browser failed: ' + e.message); }); } } } }; </script>
常用URLscheme
[
// 只在 ios 中生效
{
name: 'App Store',
scheme: 'itms-apps://'
},
{
name: '支付宝',
pname: 'com.eg.android.AlipayGphone',
scheme: 'alipay://'
},
{
name: '淘宝',
pname: 'com.taobao.taobao',
scheme: 'taobao://'
},
{
name: 'QQ',
pname: 'com.tencent.mobileqq',
scheme: 'mqq://'
},
{
name: '微信',
pname: 'com.tencent.mm',
scheme: 'weixin://'
},
{
name: '京东',
pname: 'com.jingdong.app.mall',
scheme: 'openApp.jdMobile://'
},
{
name: '新浪微博',
pname: 'com.sina.weibo',
scheme: 'sinaweibo://'
},
{
name: '优酷',
pname: 'com.youku.phone',
scheme: 'youku://'
}
]
更多实用例子
除了简单的打开App,我们更多的时候想要直达。这里汇总了很多有用的直达案例:
- 使用应用商店打开指定App,可用于引导评分
- 强制使用应用宝打开指定App
- 打开淘宝搜索页面。需要你要做淘宝客,需要向淘宝申请自己的scheme参数并传入。
- 打开地图并指定地点
- 打开qq并到指定聊天界面,可用于客服
具体代码见下:
<template>
<view>
<page-head title="通过scheme打开三方app示例"></page-head>
<button class="button" @click="openBrowser('https://uniapp.dcloud.io/h5')">使用浏览器打开指定URL</button>
<button class="button" @click="openMarket()">使用应用商店打开指定App</button>
<button class="button" @click="openMarket('com.tencent.android.qqdownloader')">强制使用应用宝打开指定App</button>
<button class="button" @click="openTaobao('taobao://s.taobao.com/search?q=uni-app')">打开淘宝搜索页面</button>
<button class="button" @click="openMap()">打开地图并指定地点</button>
<view class="uni-divider">
<view class="uni-divider__content">打开QQ</view>
<view class="uni-divider__line"></view>
</view>
<view class="uni-padding-wrap">
<form @submit="openQQ">
<view>
<view class="uni-title">请输入聊天对象QQ号:</view>
<view class="uni-list">
<view class="uni-list-cell">
<input class="uni-input" name="qqNum" type="number"/>
</view>
</view>
</view>
<view>
<view class="uni-title">请选择QQ号类型:</view>
<radio-group class="uni-flex" name="qqNumType">
<label>
<radio value="wpa" checked=""/>普通QQ号</label>
<label>
<radio value="crm" />营销QQ号(无需加好友直接聊天)</label>
</radio-group>
</view>
<view class="uni-btn-v uni-common-mt">
<button class="button" formType="submit">打开qq并到指定聊天界面</button>
</view>
</form>
</view>
</view>
</template>
<script>
export default {
data() {
return {
};
},
methods: {
openBrowser(url){
plus.runtime.openURL(url)
},
openMarket(marketPackageName) {
var appurl;
if (plus.os.name=="Android") {
appurl = "market://details?id=io.dcloud.HelloH5"; //由于hello uni-app没有上Android应用商店,所以此处打开了另一个示例应用
}
else{
appurl = "itms-apps://itunes.apple.com/cn/app/hello-uni-app/id1417078253?mt=8";
}
if (typeof(marketPackageName)=="undefined") {
plus.runtime.openURL(appurl, function(res) {
console.log(res);
});
} else{//强制指定某个Android应用市场的包名,通过这个包名启动指定app
if (plus.os.name=="Android") {
plus.runtime.openURL(appurl, function(res) {
plus.nativeUI.alert("本机没有安装应用宝");
},marketPackageName);
} else{
plus.nativeUI.alert("仅Android手机才支持应用宝");
}
}
},
openTaobao(url){
plus.runtime.openURL(url, function(res) {
uni.showModal({
content:"本机未检测到淘宝客户端,是否打开浏览器访问淘宝?",
success:function(res){
if (res.confirm) {
plus.runtime.openURL("https://s.taobao.com/search?q=uni-app")
}
}
})
});
},
openMap(){
var url = "";
if (plus.os.name=="Android") {
var hasBaiduMap = plus.runtime.isApplicationExist({pname:'com.baidu.BaiduMap',action:'baidumap://'});
var hasAmap = plus.runtime.isApplicationExist({pname:'com.autonavi.minimap',action:'androidamap://'});
var urlBaiduMap = "baidumap://map/marker?location=39.968789,116.347247&title=DCloud&src=Hello%20uni-app";
var urlAmap = "androidamap://viewMap?sourceApplication=Hello%20uni-app&poiname=DCloud&lat=39.9631018208&lon=116.3406135236&dev=0"
if (hasAmap && hasBaiduMap) {
plus.nativeUI.actionSheet({title:"选择地图应用",cancel:"取消",buttons:[{title:"百度地图"},{title:"高德地图"}]}, function(e){
switch (e.index){
case 1:
plus.runtime.openURL(urlBaiduMap);
break;
case 2:
plus.runtime.openURL(urlAmap);
break;
}
})
}
else if (hasAmap) {
plus.runtime.openURL(urlAmap);
}
else if (hasBaiduMap) {
plus.runtime.openURL(urlBaiduMap);
}
else{
url = "geo:39.96310,116.340698?q=%e6%95%b0%e5%ad%97%e5%a4%a9%e5%a0%82";
plus.runtime.openURL(url); //如果是国外应用,应该优先使用这个,会启动google地图。这个接口不能统一坐标系,进入百度地图时会有偏差
}
} else{
// iOS上获取本机是否安装了百度高德地图,需要在manifest里配置,在manifest.json文件app-plus->distribute->apple->urlschemewhitelist节点下添加(如urlschemewhitelist:["iosamap","baidumap"])
plus.nativeUI.actionSheet({title:"选择地图应用",cancel:"取消",buttons:[{title:"Apple地图"},{title:"百度地图"},{title:"高德地图"}]}, function(e){
console.log("e.index: " + e.index);
switch (e.index){
case 1:
url = "http://maps.apple.com/?q=%e6%95%b0%e5%ad%97%e5%a4%a9%e5%a0%82&ll=39.96310,116.340698&spn=0.008766,0.019441";
break;
case 2:
url = "baidumap://map/marker?location=39.968789,116.347247&title=DCloud&src=Hello%20uni-app";
break;
case 3:
url = "iosamap://viewMap?sourceApplication=Hello%20uni-app&poiname=DCloud&lat=39.9631018208&lon=116.3406135236&dev=0";
break;
default:
break;
}
if (url!="") {
plus.runtime.openURL( url, function( e ) {
plus.nativeUI.alert("本机未安装指定的地图应用");
});
}
})
}
},
openQQ: function (e) {
// console.log("e.detail.value: " + JSON.stringify(e.detail.value));
// 没有校验qq号是否为空或合法数字,如果不是可用的qq号,启动qq后会停留在qq主界面
plus.runtime.openURL('mqqwpa://im/chat?chat_type=' + e.detail.value.qqNumType + '&uin=' + e.detail.value.qqNum,function (res) {
plus.nativeUI.alert("本机没有安装QQ,无法启动");
});
}
}
};
</script>
<style>
.button {
margin: 30upx;
color: #007AFF;
}
</style>
给自己的App设置scheme
可在manifest中可配置。
Android配置方法
iOS配置方法
我们在开发 App 应用中,经常会遇到打开第三方程序的场景,比如打开手机淘宝、通过第三方浏览器打开一个 url 等等。
App不像网页可以使用http超链接互相跳转,但手机os设计了scheme机制,可以通过特殊的链接互相调起。
比如手机淘宝,其安装后会在手机os中会注册一个scheme协议,taobao://
。
这种协议还支持参数,比如taobao://s.taobao.com/search?q=uni-app
启动淘宝并打开搜索页面搜索uni-app。
在uni-app/5+App中,可以通过scheme呼起其他App,也支持给自己的App设置scheme参数。
这个功能小程序并不支持,属于App端的扩展API。
打开外部scheme的API是plus.runtime.openURL()
。查看文档:http://www.html5plus.org/doc/zh_cn/runtime.html
打开第三方程序
打开第三方程序,我们需要使用 runtime 模块,下面我罗列两个相关的方法。其他操作请详读文档。
-
调用外部浏览器打开指定的URL
plus.runtime.openURL( url, errorCB, identity );
- url: ( String ) 必选 要打开的URL地址
字符串类型,各平台支持的地址类型存在差异,参考平台URL支持表。 - errorCB: ( OpenErrorCallback ) 可选 打开URL地址失败的回调
打开指定URL地址失败时回调,并返回失败信息。 - identity: ( String ) 可选 指定打开URL地址的程序名称
在iOS平台此参数被忽略,在Android平台为程序包名,如果指定的包名不存在,则打开URL地址失败。
<template> <view> <button class="button" type="primary" @click="open(0)">使用第三方程序打开指定URL</button> </view> </template>
<script> export default { data() { return { url: 'https://uniapp.dcloud.io/' }; }, onLoad(op) {}, methods: { open(types) { plus.runtime.openURL(this.url, function(res) { console.log(res); }); } } }; </script>
- url: ( String ) 必选 要打开的URL地址
-
调用第三方程序
plus.runtime.launchApplication( appInf, errorCB );
- appInf: ( ApplicationInf ) 必选 要启动第三方程序的描述信息
- errorCB: ( LaunchErrorCallback ) 必选 启动第三方程序操作失败的回调函数
启动第三方程序失败时回调,并返回失败信息。
<template> <view> <button class="button" type="primary" @click="launchApp">打开淘宝</button> </view> </template>
<script> export default { data() { return { url: 'https://uniapp.dcloud.io/' }; }, onLoad(op) {}, methods: { launchApp() { let _this = this; // 判断平台 if (plus.os.name == 'Android') { plus.runtime.launchApplication( { pname: 'com.taobao.taobao' }, function(e) { console.log('Open system default browser failed: ' + e.message); } ); } else if (plus.os.name == 'iOS') { plus.runtime.launchApplication({ action: 'taobao://' }, function(e) { console.log('Open system default browser failed: ' + e.message); }); } } } }; </script>
常用URLscheme
[
// 只在 ios 中生效
{
name: 'App Store',
scheme: 'itms-apps://'
},
{
name: '支付宝',
pname: 'com.eg.android.AlipayGphone',
scheme: 'alipay://'
},
{
name: '淘宝',
pname: 'com.taobao.taobao',
scheme: 'taobao://'
},
{
name: 'QQ',
pname: 'com.tencent.mobileqq',
scheme: 'mqq://'
},
{
name: '微信',
pname: 'com.tencent.mm',
scheme: 'weixin://'
},
{
name: '京东',
pname: 'com.jingdong.app.mall',
scheme: 'openApp.jdMobile://'
},
{
name: '新浪微博',
pname: 'com.sina.weibo',
scheme: 'sinaweibo://'
},
{
name: '优酷',
pname: 'com.youku.phone',
scheme: 'youku://'
}
]
更多实用例子
除了简单的打开App,我们更多的时候想要直达。这里汇总了很多有用的直达案例:
- 使用应用商店打开指定App,可用于引导评分
- 强制使用应用宝打开指定App
- 打开淘宝搜索页面。需要你要做淘宝客,需要向淘宝申请自己的scheme参数并传入。
- 打开地图并指定地点
- 打开qq并到指定聊天界面,可用于客服
具体代码见下:
<template>
<view>
<page-head title="通过scheme打开三方app示例"></page-head>
<button class="button" @click="openBrowser('https://uniapp.dcloud.io/h5')">使用浏览器打开指定URL</button>
<button class="button" @click="openMarket()">使用应用商店打开指定App</button>
<button class="button" @click="openMarket('com.tencent.android.qqdownloader')">强制使用应用宝打开指定App</button>
<button class="button" @click="openTaobao('taobao://s.taobao.com/search?q=uni-app')">打开淘宝搜索页面</button>
<button class="button" @click="openMap()">打开地图并指定地点</button>
<view class="uni-divider">
<view class="uni-divider__content">打开QQ</view>
<view class="uni-divider__line"></view>
</view>
<view class="uni-padding-wrap">
<form @submit="openQQ">
<view>
<view class="uni-title">请输入聊天对象QQ号:</view>
<view class="uni-list">
<view class="uni-list-cell">
<input class="uni-input" name="qqNum" type="number"/>
</view>
</view>
</view>
<view>
<view class="uni-title">请选择QQ号类型:</view>
<radio-group class="uni-flex" name="qqNumType">
<label>
<radio value="wpa" checked=""/>普通QQ号</label>
<label>
<radio value="crm" />营销QQ号(无需加好友直接聊天)</label>
</radio-group>
</view>
<view class="uni-btn-v uni-common-mt">
<button class="button" formType="submit">打开qq并到指定聊天界面</button>
</view>
</form>
</view>
</view>
</template>
<script>
export default {
data() {
return {
};
},
methods: {
openBrowser(url){
plus.runtime.openURL(url)
},
openMarket(marketPackageName) {
var appurl;
if (plus.os.name=="Android") {
appurl = "market://details?id=io.dcloud.HelloH5"; //由于hello uni-app没有上Android应用商店,所以此处打开了另一个示例应用
}
else{
appurl = "itms-apps://itunes.apple.com/cn/app/hello-uni-app/id1417078253?mt=8";
}
if (typeof(marketPackageName)=="undefined") {
plus.runtime.openURL(appurl, function(res) {
console.log(res);
});
} else{//强制指定某个Android应用市场的包名,通过这个包名启动指定app
if (plus.os.name=="Android") {
plus.runtime.openURL(appurl, function(res) {
plus.nativeUI.alert("本机没有安装应用宝");
},marketPackageName);
} else{
plus.nativeUI.alert("仅Android手机才支持应用宝");
}
}
},
openTaobao(url){
plus.runtime.openURL(url, function(res) {
uni.showModal({
content:"本机未检测到淘宝客户端,是否打开浏览器访问淘宝?",
success:function(res){
if (res.confirm) {
plus.runtime.openURL("https://s.taobao.com/search?q=uni-app")
}
}
})
});
},
openMap(){
var url = "";
if (plus.os.name=="Android") {
var hasBaiduMap = plus.runtime.isApplicationExist({pname:'com.baidu.BaiduMap',action:'baidumap://'});
var hasAmap = plus.runtime.isApplicationExist({pname:'com.autonavi.minimap',action:'androidamap://'});
var urlBaiduMap = "baidumap://map/marker?location=39.968789,116.347247&title=DCloud&src=Hello%20uni-app";
var urlAmap = "androidamap://viewMap?sourceApplication=Hello%20uni-app&poiname=DCloud&lat=39.9631018208&lon=116.3406135236&dev=0"
if (hasAmap && hasBaiduMap) {
plus.nativeUI.actionSheet({title:"选择地图应用",cancel:"取消",buttons:[{title:"百度地图"},{title:"高德地图"}]}, function(e){
switch (e.index){
case 1:
plus.runtime.openURL(urlBaiduMap);
break;
case 2:
plus.runtime.openURL(urlAmap);
break;
}
})
}
else if (hasAmap) {
plus.runtime.openURL(urlAmap);
}
else if (hasBaiduMap) {
plus.runtime.openURL(urlBaiduMap);
}
else{
url = "geo:39.96310,116.340698?q=%e6%95%b0%e5%ad%97%e5%a4%a9%e5%a0%82";
plus.runtime.openURL(url); //如果是国外应用,应该优先使用这个,会启动google地图。这个接口不能统一坐标系,进入百度地图时会有偏差
}
} else{
// iOS上获取本机是否安装了百度高德地图,需要在manifest里配置,在manifest.json文件app-plus->distribute->apple->urlschemewhitelist节点下添加(如urlschemewhitelist:["iosamap","baidumap"])
plus.nativeUI.actionSheet({title:"选择地图应用",cancel:"取消",buttons:[{title:"Apple地图"},{title:"百度地图"},{title:"高德地图"}]}, function(e){
console.log("e.index: " + e.index);
switch (e.index){
case 1:
url = "http://maps.apple.com/?q=%e6%95%b0%e5%ad%97%e5%a4%a9%e5%a0%82&ll=39.96310,116.340698&spn=0.008766,0.019441";
break;
case 2:
url = "baidumap://map/marker?location=39.968789,116.347247&title=DCloud&src=Hello%20uni-app";
break;
case 3:
url = "iosamap://viewMap?sourceApplication=Hello%20uni-app&poiname=DCloud&lat=39.9631018208&lon=116.3406135236&dev=0";
break;
default:
break;
}
if (url!="") {
plus.runtime.openURL( url, function( e ) {
plus.nativeUI.alert("本机未安装指定的地图应用");
});
}
})
}
},
openQQ: function (e) {
// console.log("e.detail.value: " + JSON.stringify(e.detail.value));
// 没有校验qq号是否为空或合法数字,如果不是可用的qq号,启动qq后会停留在qq主界面
plus.runtime.openURL('mqqwpa://im/chat?chat_type=' + e.detail.value.qqNumType + '&uin=' + e.detail.value.qqNum,function (res) {
plus.nativeUI.alert("本机没有安装QQ,无法启动");
});
}
}
};
</script>
<style>
.button {
margin: 30upx;
color: #007AFF;
}
</style>
给自己的App设置scheme
可在manifest中可配置。
Android配置方法
iOS配置方法

个推基于Consul的配置管理
作者:个推应用平台基础架构高级研发工程师 阿飞
在微服务架构体系中,由于微服务众多,服务之间又有互相调用关系,因此,一个通用的分布式配置管理是必不可少的。一般来说,配置管理需要解决配置集中管理、在系统运行期间可实现动态配置、配置修改后支持自动刷新等问题。
在大多数微服务体系中,都会有一个名为配置文件的功能模块来提供统一的分布式配置管理。构建配置中心,统一对应用中各个微服务进行管理,对微服务体系的意义重大。
Consul为什么适合做配置管理
Consul作为轻量级的分布式K/V存储系统,搭建方便,可用性高,并且支持多数据中心,提供Web UI进行K/V管理。此外Consul还可以结合Consul-Template或者在代码中引入Consul Client的相关依赖创建Watcher来实时Watch K/V的变化,是配置管理的不二之选。

下图为个推微服务体系基于Consul配置管理的整体设计。其中,CCenter就是在Consul的基础上进行二次开发的配置中心。
微服务体系下配置的分类和组织形式
在实践中,不同产品线的配置会放置在Consul的不同路径下,实现不同产品线配置之间的隔离。
按照配置的用途,可将同一产品线下的配置分为三类:
1.API网关相关配置;
2.服务注册与发现相关配置;
3.应用相关配置。
其中,每类配置会对应Consul上的不同目录。
按照配置的变化特性,可将配置分为两类:
1.环境相关的全局配置
如MySQL等外部依赖相关的配置和其他与环境相关的配置,这类配置在开发测试生产环境中存在差异,需要为不同环境配置不同的值。
2.应用本身的配置
一般为不经常性发生变化、可动态调整、开关的配置。这类配置比较稳定,在初始化后,只有在需要时才会改动,通常会设置默认值。这两类配置在Consul上会放在不同的子目录下。这样QA、运维只需要关注环境差异部分即可。
基于以上对配置的分类,最终Consul上的Key的格式如下:
/ProductLine_Prefix/Usage_Prefix/Environmental_Correlation_Prefix/Config_Item_Path
其中,
ProductLine_Prefix:用来隔离不同产品线的配置;
Usage_Prefix:用来区分配置的用途;
Environmental_Correlation_Prefix:用来分隔与环境相关的配置;
Config_Item_Path:具体的配置项。
配置在Consul上的组织形式有以下两种:
1.以配置文件的形式组织,Consul上的一个K/V,对应一个配置文件,如nginx的配置文件。
2.以配置项的形式组织,将配置文件模板化,拆成一个个的配置项,每个配置项对应Consul上的一个K/V,多个配置项对应一个配置文件。大部分配置文件本身都是以K/V的形式组织的,均适合模板化,模板化后即可以按照配置项的特性,在Consul上分成不同的类别进行管理。
如何实现配置更新
Consul上的K/V,要如何生成可加载的应用,或可使用的配置呢?
1.用Node和Lua实现的微服务的配置更新,使用Consul-Template来实现;
2.用Java实现的微服务的配置更新,通过Consul-Template工具(需要重启应用)和在代码中引入Consul Client的依赖创建Watcher(热更新)这两种方式来实现。
Consul-Template如何使用?
Consul-Template是一个后台进程,它可以根据Watch Consul上K/V的变化,更新任意数量的模板,同时生成对应的文件,之后还可以运行任意的命令。要使用Consul-Template一般需要定义两个文件:
1.模板文件
模板文件一般按照Go Template的格式进行编写,示例如下:
config-tree.ctmpl:
{{ tree /consul/path/to/configFiles | explode | toJSONPretty }}
该模板在/consul/path/to/configFiles路径下的配置发生变化时,会渲染出一个Json格式的字符串,其中包含了/consul/path/to/configFiles下所有的K/V.
config-kv.ctmpl:
return {
host='{{ printf "%s/mysql/host" (env "CONSUL_CONFIG_PREFIX") | key }}',
port={{ keyOrDefault (printf "%s/mysql/port" (env "CON-SUL_CONFIG_PREFIX")) "3306" }},
user='{{ printf "%s/mysql/user" (env "CONSUL_CONFIG_PREFIX") | key }}',
password='{{ printf "%s/mysql/password" (env "CON-SUL_CONFIG_PREFIX") | key }}'
}
该模板是按照配置项来渲染的,在该模板中使用了Consul-Template定义两个方法key和keyOrDefault。其中,key会在Consul上对应的K/V创建后,再进行渲染模板;keyOrDefault则会在Consul上没有对应的K/V时,使用默认值代替。
模板中还使用了 " CONSUL_CONFIG_PREFIX " 这个环境变量,这样,不同的产品线便可以使用同一个模板文件,只需要修改" CONSUL_CONFIG_PREFIX "这个环境变量的值即可。
2.配置文件
配置文件是按照HashiCorp Configuration Language (HCL)编写的,示例如下:
template {
source = "config-tree.ctmpl",
destination = "config-tree.json",
command = "sh updateAndReload.sh config-tree.json”
}
template {
source = "config-kv.ctmpl",
destination = "config-kv.lua",
command = "sh updateAndReload.sh config-kv.lua”
}
该配置文件的作用是使用" source"指定的两个模板文件进行渲染,将渲染的结果分别保存在" destination"指定的文件中,保存成功后,分别运行" command"指定的命令来更新并加载配置文件。
配置的更新方式
在个推的微服务体系中,配置的更新方式有两种:
1.替换配置文件,reload服务
2.调用服务接口直接更新内存中的配置
而在Java实现的微服务中,热更新配置通常是在代码中引入Consul Client的依赖,在应用启动时,会初始化一个Watcher来监听Consul上对应目录下K/V的变化,相关的K/V发生变化时,Watcher会负责将其拉取下来,然后调用相关的代码进行配置的更新。
基于Consul的二次开发-CCenter
配置中心CCenter在Consul上提供了更友好的WEB UI,并且增加版本控制,每次配置的更新都会生成一个版本,在应用版本后,配置才真正生效,可以更加方便地进行配置版本间的差异比较,应用任意版本的配置。
总结
以上就是个推在微服务实践中,基于Consul实现的一套配置管理的方案,作为轻量级的分布式K/V存储系统, Consul非常适合用于配置管理,可以帮助开发者们方便、快速地搭建配置中心,结合Consul-Template则可以方便地实现配置的实时更新,在Consul的基础上进行二次开发,实现了配置版本的有效控制,对微服务的配置管理起到了良好的辅助作用。
作者:个推应用平台基础架构高级研发工程师 阿飞
在微服务架构体系中,由于微服务众多,服务之间又有互相调用关系,因此,一个通用的分布式配置管理是必不可少的。一般来说,配置管理需要解决配置集中管理、在系统运行期间可实现动态配置、配置修改后支持自动刷新等问题。
在大多数微服务体系中,都会有一个名为配置文件的功能模块来提供统一的分布式配置管理。构建配置中心,统一对应用中各个微服务进行管理,对微服务体系的意义重大。
Consul为什么适合做配置管理
Consul作为轻量级的分布式K/V存储系统,搭建方便,可用性高,并且支持多数据中心,提供Web UI进行K/V管理。此外Consul还可以结合Consul-Template或者在代码中引入Consul Client的相关依赖创建Watcher来实时Watch K/V的变化,是配置管理的不二之选。
下图为个推微服务体系基于Consul配置管理的整体设计。其中,CCenter就是在Consul的基础上进行二次开发的配置中心。
微服务体系下配置的分类和组织形式
在实践中,不同产品线的配置会放置在Consul的不同路径下,实现不同产品线配置之间的隔离。
按照配置的用途,可将同一产品线下的配置分为三类:
1.API网关相关配置;
2.服务注册与发现相关配置;
3.应用相关配置。
其中,每类配置会对应Consul上的不同目录。
按照配置的变化特性,可将配置分为两类:
1.环境相关的全局配置
如MySQL等外部依赖相关的配置和其他与环境相关的配置,这类配置在开发测试生产环境中存在差异,需要为不同环境配置不同的值。
2.应用本身的配置
一般为不经常性发生变化、可动态调整、开关的配置。这类配置比较稳定,在初始化后,只有在需要时才会改动,通常会设置默认值。这两类配置在Consul上会放在不同的子目录下。这样QA、运维只需要关注环境差异部分即可。
基于以上对配置的分类,最终Consul上的Key的格式如下:
/ProductLine_Prefix/Usage_Prefix/Environmental_Correlation_Prefix/Config_Item_Path
其中,
ProductLine_Prefix:用来隔离不同产品线的配置;
Usage_Prefix:用来区分配置的用途;
Environmental_Correlation_Prefix:用来分隔与环境相关的配置;
Config_Item_Path:具体的配置项。
配置在Consul上的组织形式有以下两种:
1.以配置文件的形式组织,Consul上的一个K/V,对应一个配置文件,如nginx的配置文件。
2.以配置项的形式组织,将配置文件模板化,拆成一个个的配置项,每个配置项对应Consul上的一个K/V,多个配置项对应一个配置文件。大部分配置文件本身都是以K/V的形式组织的,均适合模板化,模板化后即可以按照配置项的特性,在Consul上分成不同的类别进行管理。
如何实现配置更新
Consul上的K/V,要如何生成可加载的应用,或可使用的配置呢?
1.用Node和Lua实现的微服务的配置更新,使用Consul-Template来实现;
2.用Java实现的微服务的配置更新,通过Consul-Template工具(需要重启应用)和在代码中引入Consul Client的依赖创建Watcher(热更新)这两种方式来实现。
Consul-Template如何使用?
Consul-Template是一个后台进程,它可以根据Watch Consul上K/V的变化,更新任意数量的模板,同时生成对应的文件,之后还可以运行任意的命令。要使用Consul-Template一般需要定义两个文件:
1.模板文件
模板文件一般按照Go Template的格式进行编写,示例如下:
config-tree.ctmpl:
{{ tree /consul/path/to/configFiles | explode | toJSONPretty }}
该模板在/consul/path/to/configFiles路径下的配置发生变化时,会渲染出一个Json格式的字符串,其中包含了/consul/path/to/configFiles下所有的K/V.
config-kv.ctmpl:
return {
host='{{ printf "%s/mysql/host" (env "CONSUL_CONFIG_PREFIX") | key }}',
port={{ keyOrDefault (printf "%s/mysql/port" (env "CON-SUL_CONFIG_PREFIX")) "3306" }},
user='{{ printf "%s/mysql/user" (env "CONSUL_CONFIG_PREFIX") | key }}',
password='{{ printf "%s/mysql/password" (env "CON-SUL_CONFIG_PREFIX") | key }}'
}
该模板是按照配置项来渲染的,在该模板中使用了Consul-Template定义两个方法key和keyOrDefault。其中,key会在Consul上对应的K/V创建后,再进行渲染模板;keyOrDefault则会在Consul上没有对应的K/V时,使用默认值代替。
模板中还使用了 " CONSUL_CONFIG_PREFIX " 这个环境变量,这样,不同的产品线便可以使用同一个模板文件,只需要修改" CONSUL_CONFIG_PREFIX "这个环境变量的值即可。
2.配置文件
配置文件是按照HashiCorp Configuration Language (HCL)编写的,示例如下:
template {
source = "config-tree.ctmpl",
destination = "config-tree.json",
command = "sh updateAndReload.sh config-tree.json”
}
template {
source = "config-kv.ctmpl",
destination = "config-kv.lua",
command = "sh updateAndReload.sh config-kv.lua”
}
该配置文件的作用是使用" source"指定的两个模板文件进行渲染,将渲染的结果分别保存在" destination"指定的文件中,保存成功后,分别运行" command"指定的命令来更新并加载配置文件。
配置的更新方式
在个推的微服务体系中,配置的更新方式有两种:
1.替换配置文件,reload服务
2.调用服务接口直接更新内存中的配置
而在Java实现的微服务中,热更新配置通常是在代码中引入Consul Client的依赖,在应用启动时,会初始化一个Watcher来监听Consul上对应目录下K/V的变化,相关的K/V发生变化时,Watcher会负责将其拉取下来,然后调用相关的代码进行配置的更新。
基于Consul的二次开发-CCenter
配置中心CCenter在Consul上提供了更友好的WEB UI,并且增加版本控制,每次配置的更新都会生成一个版本,在应用版本后,配置才真正生效,可以更加方便地进行配置版本间的差异比较,应用任意版本的配置。
总结
以上就是个推在微服务实践中,基于Consul实现的一套配置管理的方案,作为轻量级的分布式K/V存储系统, Consul非常适合用于配置管理,可以帮助开发者们方便、快速地搭建配置中心,结合Consul-Template则可以方便地实现配置的实时更新,在Consul的基础上进行二次开发,实现了配置版本的有效控制,对微服务的配置管理起到了良好的辅助作用。
收起阅读 »
hello uniapp 原生选项卡和非原生选项卡差别真是大啊(速度和性能)
我加载远程数据,原生顶端选项卡,基本上秒加载,同样的数据源,非原生选项卡,要耗费三倍以上时间,才能加载渲染完成。
性能和加载速度不是一个量级的。
左右滑动非原生选项卡,多划几次就卡死。官方的也这样。性能堪忧!
weex的性能确实好。但是不能横屏。好郁闷!
我加载远程数据,原生顶端选项卡,基本上秒加载,同样的数据源,非原生选项卡,要耗费三倍以上时间,才能加载渲染完成。
性能和加载速度不是一个量级的。
左右滑动非原生选项卡,多划几次就卡死。官方的也这样。性能堪忧!
weex的性能确实好。但是不能横屏。好郁闷!

app调用摄像头拍照+相册选择并且转base64上传到服务器(含上传ajax)
引用的CSS:
<link rel="stylesheet" type="text/css" href="../css/mui.min.css" />
引用的JS:
<script src="../js/mui.min.js"></script>
html部分如下:
<ul class="mui-table-view mui-table-view-chevron">
<li class="mui-table-view-cell" id="headImage">
<a class="mui-navigate-right" style="padding-right: 38px;">
<img class="mui-media-object mui-pull-right" style="width: 42px;height:42px;" id="mainImage">
<div style="line-height: 42px;color:#8f8f94 ;">上传单据图片</div>
</a>
</li>
</ul>
JS部分如下----首先定义两个数组:
var imagereturn=[];
var endBaseimg =[];
document.getElementById('headImage').addEventListener('click', function() {
if (mui.os.plus) {
var a = [{
title: "拍照"
}, {
title: "从手机相册选择"
}];
plus.nativeUI.actionSheet({
title: "上传单据图片",
cancel: "取消",
buttons: a
}, function(b) { /actionSheet 按钮点击事件/
switch (b.index) {
case 0:
break;
case 1:
getImage(); /拍照/
break;
case 2:
galleryImg();/打开相册/
break;
default:
break;
}
})
}
}, false);
// }
//拍照
function getImage() {
var c = plus.camera.getCamera();
c.captureImage(function(e) {
plus.io.resolveLocalFileSystemURL(e, function(entry) {
var s = entry.toLocalURL() + "?version=" + new Date().getTime();
uploadHead(s); /上传图片/
}, function(e) {
console.log("读取拍照文件错误:" + e.message);
});
}, function(s) {
console.log("error" + s);
}, {
filename: "_doc/head.png"
});
}
//本地相册选择
function galleryImg() {
plus.gallery.pick(function(a) {
plus.io.resolveLocalFileSystemURL(a, function(entry) {
plus.io.resolveLocalFileSystemURL("_doc/", function(root) {
root.getFile("head.png", {}, function(file) {
//文件已存在
file.remove(function() {
entry.copyTo(root, 'head.png', function(e) {
var e = e.fullPath + "?version=" + new Date().getTime();
uploadHead(e); /上传图片/
//变更大图预览的src
//目前仅有一张图片,暂时如此处理,后续需要通过标准组件实现
},
function(e) {
console.log('copy image fail:' + e.message);
});
}, function() {
console.log("delete image fail:" + e.message);
});
}, function() {
//文件不存在
entry.copyTo(root, 'head.png', function(e) {
var path = e.fullPath + "?version=" + new Date().getTime();
uploadHead(path); /上传图片/
},
function(e) {
console.log('copy image fail:' + e.message);
});
});
}, function(e) {
console.log("get _www folder fail");
})
}, function(e) {
console.log("读取拍照文件错误:" + e.message);
});
}, function(a) {}, {
filter: "image"
})
}
function uploadHead(imgPath) {
endBaseimg=[]
mainImage.src = imgPath;
var image = new Image();
image.src = imgPath;
image.onload = function() {
var imgData = getBase64Image(image);
endBaseimg.push(imgData);
// console.log(imgData)
/在这里调用上传接口/
var url = serverurl+'index/shangchuan';
mui.ajax(url, {
data:{
token:storaToken,
tu_cont:endBaseimg,
tu_kuozhan:'png'
},
type: 'post',
success: function(res) {
// console.log(JSON.stringify(res))
if(res.code == 1){
mui.alert('上传图片到服务器成功', '系统提示', function() { });
imagereturn = res.data.img_path
}
},
error: function(res) {
// alert(JSON.stringify(res))
mui.toast("请求服务器失败", {
duration: 'long',
type: 'div'
});
}
});
}
}
//将图片压缩转成base64
function getBase64Image(img) {
var canvas = document.createElement("canvas");
var width = img.width;
var height = img.height;
// calculate the width and height, constraining the proportions
if (width > height) {
if (width > 800) {
height = Math.round(height = 800 / width);
width = 800;
}
} else {
if (height > 800) {
width = Math.round(width = 800 / height);
height = 800;
}
}
canvas.width = width; /设置新的图片的宽度/
canvas.height = height; /设置新的图片的长度/
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height); /绘图/
var dataURL = canvas.toDataURL("image/png", 0.8);
// return dataURL.replace("data:image/png;base64,", "");
return dataURL;
}
引用的CSS:
<link rel="stylesheet" type="text/css" href="../css/mui.min.css" />
引用的JS:
<script src="../js/mui.min.js"></script>
html部分如下:
<ul class="mui-table-view mui-table-view-chevron">
<li class="mui-table-view-cell" id="headImage">
<a class="mui-navigate-right" style="padding-right: 38px;">
<img class="mui-media-object mui-pull-right" style="width: 42px;height:42px;" id="mainImage">
<div style="line-height: 42px;color:#8f8f94 ;">上传单据图片</div>
</a>
</li>
</ul>
JS部分如下----首先定义两个数组:
var imagereturn=[];
var endBaseimg =[];
document.getElementById('headImage').addEventListener('click', function() {
if (mui.os.plus) {
var a = [{
title: "拍照"
}, {
title: "从手机相册选择"
}];
plus.nativeUI.actionSheet({
title: "上传单据图片",
cancel: "取消",
buttons: a
}, function(b) { /actionSheet 按钮点击事件/
switch (b.index) {
case 0:
break;
case 1:
getImage(); /拍照/
break;
case 2:
galleryImg();/打开相册/
break;
default:
break;
}
})
}
}, false);
// }
//拍照
function getImage() {
var c = plus.camera.getCamera();
c.captureImage(function(e) {
plus.io.resolveLocalFileSystemURL(e, function(entry) {
var s = entry.toLocalURL() + "?version=" + new Date().getTime();
uploadHead(s); /上传图片/
}, function(e) {
console.log("读取拍照文件错误:" + e.message);
});
}, function(s) {
console.log("error" + s);
}, {
filename: "_doc/head.png"
});
}
//本地相册选择
function galleryImg() {
plus.gallery.pick(function(a) {
plus.io.resolveLocalFileSystemURL(a, function(entry) {
plus.io.resolveLocalFileSystemURL("_doc/", function(root) {
root.getFile("head.png", {}, function(file) {
//文件已存在
file.remove(function() {
entry.copyTo(root, 'head.png', function(e) {
var e = e.fullPath + "?version=" + new Date().getTime();
uploadHead(e); /上传图片/
//变更大图预览的src
//目前仅有一张图片,暂时如此处理,后续需要通过标准组件实现
},
function(e) {
console.log('copy image fail:' + e.message);
});
}, function() {
console.log("delete image fail:" + e.message);
});
}, function() {
//文件不存在
entry.copyTo(root, 'head.png', function(e) {
var path = e.fullPath + "?version=" + new Date().getTime();
uploadHead(path); /上传图片/
},
function(e) {
console.log('copy image fail:' + e.message);
});
});
}, function(e) {
console.log("get _www folder fail");
})
}, function(e) {
console.log("读取拍照文件错误:" + e.message);
});
}, function(a) {}, {
filter: "image"
})
}
function uploadHead(imgPath) {
endBaseimg=[]
mainImage.src = imgPath;
var image = new Image();
image.src = imgPath;
image.onload = function() {
var imgData = getBase64Image(image);
endBaseimg.push(imgData);
// console.log(imgData)
/在这里调用上传接口/
var url = serverurl+'index/shangchuan';
mui.ajax(url, {
data:{
token:storaToken,
tu_cont:endBaseimg,
tu_kuozhan:'png'
},
type: 'post',
success: function(res) {
// console.log(JSON.stringify(res))
if(res.code == 1){
mui.alert('上传图片到服务器成功', '系统提示', function() { });
imagereturn = res.data.img_path
}
},
error: function(res) {
// alert(JSON.stringify(res))
mui.toast("请求服务器失败", {
duration: 'long',
type: 'div'
});
}
});
}
}
//将图片压缩转成base64
function getBase64Image(img) {
var canvas = document.createElement("canvas");
var width = img.width;
var height = img.height;
// calculate the width and height, constraining the proportions
if (width > height) {
if (width > 800) {
height = Math.round(height = 800 / width);
width = 800;
}
} else {
if (height > 800) {
width = Math.round(width = 800 / height);
height = 800;
}
}
canvas.width = width; /设置新的图片的宽度/
canvas.height = height; /设置新的图片的长度/
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height); /绘图/
var dataURL = canvas.toDataURL("image/png", 0.8);
// return dataURL.replace("data:image/png;base64,", "");
return dataURL;
}

传智播客:年薪60万招聘uni-app培训讲师!
招聘岗位:前端与移动开发课程研究员,uni-app培训讲师
薪资范围:40k-60k
公司介绍:
传智播客是致力于高素质软件开发人才培养的新三板挂牌公司(代码:839976)。公司网址:http://www.itcast.cn
福利待遇:
五险一金、补充医疗险、意外险
交通补助、餐补
带薪年假
员工体检
其他福利:生日福利、节日福利、员工旅游、传智父母节等。
岗位职责:
针对前端流行技术进行相关预研工作
基于主流技术方案进行项目研发
负责设计前端项目课程
关注前端技术变革,能够快速进行课程转化
任职要求:
本科以上学历,5年以上前端领域开发经验,具备良好的表达能力
具备扎实的计算机理论基础,较强的学习能力和解决问题能力(重要)
熟悉前端页面局部,具备扎实的原生JavaScript基本功,熟悉Less/Sass等CSS预处理器,理解CSS模块化
熟悉Node.js
深入理解前端工程化思想,熟练使用webpack、gulp等工具
在实际项目中使用过Angular、React、Vue其中之一并有实践经验
熟悉前端echarts、d3、three.js等可视化库
有过微信小程序、服务号或Hybrid开发经验。
能够针对不同的业务场景进行合理的技术选型和项目架构
具备Java或者其他后台开发经验优先
熟悉uni-app开发
加分项:
有自己开源的前端项目
有课程设计或者授课经历
有自己的技术博客
工作地点:
北京
地址1:北京市昌平区建材城西路金燕龙办公楼一层(总部)
地址2:北京市昌平区北七家镇七北路42号TBD云集中心2号楼3单元3层
地址3:北京市顺义区京顺路99号黑马程序员(教学楼A栋)
上海
地址:上海市浦东新区航头镇航都路18号万香创新港
深圳
地址1:深圳市宝安区留仙二路中粮商务公园3栋17层
广州
地址:广州市天河区珠吉路58号津安创意园
武汉
地址1:湖北省武汉市东湖高新区高新二路22号中国光谷云计算海外高新企业孵化中心1号楼3层5层
地址2:武汉市东湖新技术开发区汤逊湖北路8号 湖北国知专利创业孵化园(华师一附中南门正对面)6号楼(知乐楼)
郑州
地址:郑州市高新区长椿路11号国家大学科技园8号楼三层
西安
地址:西安经开区草滩六路1369号绘锦园A栋3-4层
联系人:
丁老师:15321987531(微信与电话同步 )
招聘岗位:前端与移动开发课程研究员,uni-app培训讲师
薪资范围:40k-60k
公司介绍:
传智播客是致力于高素质软件开发人才培养的新三板挂牌公司(代码:839976)。公司网址:http://www.itcast.cn
福利待遇:
五险一金、补充医疗险、意外险
交通补助、餐补
带薪年假
员工体检
其他福利:生日福利、节日福利、员工旅游、传智父母节等。
岗位职责:
针对前端流行技术进行相关预研工作
基于主流技术方案进行项目研发
负责设计前端项目课程
关注前端技术变革,能够快速进行课程转化
任职要求:
本科以上学历,5年以上前端领域开发经验,具备良好的表达能力
具备扎实的计算机理论基础,较强的学习能力和解决问题能力(重要)
熟悉前端页面局部,具备扎实的原生JavaScript基本功,熟悉Less/Sass等CSS预处理器,理解CSS模块化
熟悉Node.js
深入理解前端工程化思想,熟练使用webpack、gulp等工具
在实际项目中使用过Angular、React、Vue其中之一并有实践经验
熟悉前端echarts、d3、three.js等可视化库
有过微信小程序、服务号或Hybrid开发经验。
能够针对不同的业务场景进行合理的技术选型和项目架构
具备Java或者其他后台开发经验优先
熟悉uni-app开发
加分项:
有自己开源的前端项目
有课程设计或者授课经历
有自己的技术博客
工作地点:
北京
地址1:北京市昌平区建材城西路金燕龙办公楼一层(总部)
地址2:北京市昌平区北七家镇七北路42号TBD云集中心2号楼3单元3层
地址3:北京市顺义区京顺路99号黑马程序员(教学楼A栋)
上海
地址:上海市浦东新区航头镇航都路18号万香创新港
深圳
地址1:深圳市宝安区留仙二路中粮商务公园3栋17层
广州
地址:广州市天河区珠吉路58号津安创意园
武汉
地址1:湖北省武汉市东湖高新区高新二路22号中国光谷云计算海外高新企业孵化中心1号楼3层5层
地址2:武汉市东湖新技术开发区汤逊湖北路8号 湖北国知专利创业孵化园(华师一附中南门正对面)6号楼(知乐楼)
郑州
地址:郑州市高新区长椿路11号国家大学科技园8号楼三层
西安
地址:西安经开区草滩六路1369号绘锦园A栋3-4层
联系人:
丁老师:15321987531(微信与电话同步 )
收起阅读 »
验证码登录
<template>
<view class="content">
<view class="login-info">
<view class="login">
<text class="login-title">输入验证码</text>
<text class="login-phone">已发到:+86 {{phone}}</text>
</view>
<form @submit="formSubmit">
<view class="uni-common-mt">
<view class="uni-flex uni-row" style="justify-content: center">
<view class="validate" @tap="tapStop" v-for="(item,index) in Length" :key="index">
<input class="uni-input v-code" :value="Value.length>=index+1?Value[index]:''" disabled maxlength="1"/>
</view>
</view>
<input name="password" class='input-code' type="number" :maxlength="Length" :focus="isFocus" @input="monitorInput" @blur="blurFocus"/>
<view class="">
<input class="uni-input" hidden type="text" name="phone" :value="phone" />
<button type="primary" formType="submit" id="go-login" class="go-login" :disabled="disabled" :class="[!prohibitSubmit ? 'prohibit-submit' : '']">{{reset_time}}</button>
</view>
</view>
</form>
</view>
</view>
</template>
<script>
export default {
data() {
return {
Length:4,
Value:"",
isFocus:true,
prohibitSubmit: false,
disabled: true,
phone:'',
reset_time:'重新获取',
setTime: null,
}
},
onLoad(e){
if(e.phone){
this.phone = e.phone;
}else{
uni.navigateBack({
delta: 1
});
}
},
created: function(e) {
this.setInterValFunc(this);
},
methods: {
blurFocus:function(e){
console.log('失去焦点');
this.isFocus=false;
},
monitorInput:function(event){
console.log(event.target.value);
var inputValue = event.target.value;
this.Value=inputValue;
if(inputValue.length == 4){
this.isFocus=false;
uni.request({
url: 'https://www.',
method:'POST',
data: {validate_code:event.target.value,phone:this.phone},
success: function(res) {
uni.hideLoading();
var data=res.data;
if(data.code>0){
uni.setStorage({
key: 'utoken',
data: data.data,
fail: () => {
uni.showModal({
title: '登录失败-写入数据',
showCancel:false
})
return false;
}
});
uni.switchTab({
url: '/pages/index/index'
});
}else{
uni.showModal({
title: "系统提示",
content: data.msg,
showCancel: false,
confirmText: "确定"
})
}
}
});
}
},
tapStop:function(event){
console.log(event);
this.isFocus=true;
},
setInterValFunc: function(obj) {
obj.prohibitSubmit = false;
obj.disabled = true;
obj.isFocus = true;
var reset_time = 60;
obj.setTime = setInterval(function() {
obj.reset_time= "重新获取 ("+ --reset_time +")";
if(reset_time <=0 ){
clearInterval(obj.setTime);
obj.reset_time= "重新获取";
obj.prohibitSubmit = true;
obj.disabled = false;
}
}, 1000);
},
formSubmit: function(e) {
if (e.detail.value.phone.length != 11) {
uni.showModal({
title: "系统提示",
content: "请输入正确的手机号",
showCancel: false,
confirmText: "确定"
})
return false;
};
uni.showLoading({
title: '加载中'
});
var obj=this;
uni.request({
url: 'https://www.',
method:'POST',
data: JSON.stringify(e.detail.value),
success: function(res) {
uni.hideLoading();
var data=res.data;
if(data.code>0){
obj.setInterValFunc(obj);
}else{
uni.showModal({
title: "系统提示",
content: data.msg,
showCancel: false,
confirmText: "确定"
})
}
}
});
}
}
}
</script>
<style>
page {
display: flex;
}
.content{
width: 750upx;
}
.login-info{
margin: 0 5%;
}
.login{
margin-top: 20upx;
}
.login-title{
margin-left: 20upx;
font-size:36upx;
font-weight: bold;
}
.login-phone{
margin-left: 20upx;
margin-top: 8upx;
display: block;
font-size:24upx;
color: #353535;
}
.uni-row{
margin-top: 60upx;
}
.validate{
width: 90upx;
height: 90upx;
margin: 0 20upx;
}
.v-code{
font-size: 45upx;
text-align: center;
border:1rpx solid #ddd;
border-radius: 20rpx;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.go-login{
height: 100upx;
line-height: 100upx;
border-radius: 50upx;
background-color: #f85314!important;
border-color: #f85314!important;
font-size: 30upx;
color: #FFFFFF;
margin-top: 10upx;
}
.input-code{
width: 0;
height: 0;
}
.uni-icon-clear{
color: #8f8f94;
}
.prohibit-submit{
background-color: #cec6c6!important;
border-color: #cec6c6!important;
}
.user-login{
font-size: 22upx;
color: #8f8f94;
margin-left: 30upx;
}
</style>
<template>
<view class="content">
<view class="login-info">
<view class="login">
<text class="login-title">输入验证码</text>
<text class="login-phone">已发到:+86 {{phone}}</text>
</view>
<form @submit="formSubmit">
<view class="uni-common-mt">
<view class="uni-flex uni-row" style="justify-content: center">
<view class="validate" @tap="tapStop" v-for="(item,index) in Length" :key="index">
<input class="uni-input v-code" :value="Value.length>=index+1?Value[index]:''" disabled maxlength="1"/>
</view>
</view>
<input name="password" class='input-code' type="number" :maxlength="Length" :focus="isFocus" @input="monitorInput" @blur="blurFocus"/>
<view class="">
<input class="uni-input" hidden type="text" name="phone" :value="phone" />
<button type="primary" formType="submit" id="go-login" class="go-login" :disabled="disabled" :class="[!prohibitSubmit ? 'prohibit-submit' : '']">{{reset_time}}</button>
</view>
</view>
</form>
</view>
</view>
</template>
<script>
export default {
data() {
return {
Length:4,
Value:"",
isFocus:true,
prohibitSubmit: false,
disabled: true,
phone:'',
reset_time:'重新获取',
setTime: null,
}
},
onLoad(e){
if(e.phone){
this.phone = e.phone;
}else{
uni.navigateBack({
delta: 1
});
}
},
created: function(e) {
this.setInterValFunc(this);
},
methods: {
blurFocus:function(e){
console.log('失去焦点');
this.isFocus=false;
},
monitorInput:function(event){
console.log(event.target.value);
var inputValue = event.target.value;
this.Value=inputValue;
if(inputValue.length == 4){
this.isFocus=false;
uni.request({
url: 'https://www.',
method:'POST',
data: {validate_code:event.target.value,phone:this.phone},
success: function(res) {
uni.hideLoading();
var data=res.data;
if(data.code>0){
uni.setStorage({
key: 'utoken',
data: data.data,
fail: () => {
uni.showModal({
title: '登录失败-写入数据',
showCancel:false
})
return false;
}
});
uni.switchTab({
url: '/pages/index/index'
});
}else{
uni.showModal({
title: "系统提示",
content: data.msg,
showCancel: false,
confirmText: "确定"
})
}
}
});
}
},
tapStop:function(event){
console.log(event);
this.isFocus=true;
},
setInterValFunc: function(obj) {
obj.prohibitSubmit = false;
obj.disabled = true;
obj.isFocus = true;
var reset_time = 60;
obj.setTime = setInterval(function() {
obj.reset_time= "重新获取 ("+ --reset_time +")";
if(reset_time <=0 ){
clearInterval(obj.setTime);
obj.reset_time= "重新获取";
obj.prohibitSubmit = true;
obj.disabled = false;
}
}, 1000);
},
formSubmit: function(e) {
if (e.detail.value.phone.length != 11) {
uni.showModal({
title: "系统提示",
content: "请输入正确的手机号",
showCancel: false,
confirmText: "确定"
})
return false;
};
uni.showLoading({
title: '加载中'
});
var obj=this;
uni.request({
url: 'https://www.',
method:'POST',
data: JSON.stringify(e.detail.value),
success: function(res) {
uni.hideLoading();
var data=res.data;
if(data.code>0){
obj.setInterValFunc(obj);
}else{
uni.showModal({
title: "系统提示",
content: data.msg,
showCancel: false,
confirmText: "确定"
})
}
}
});
}
}
}
</script>
<style>
page {
display: flex;
}
.content{
width: 750upx;
}
.login-info{
margin: 0 5%;
}
.login{
margin-top: 20upx;
}
.login-title{
margin-left: 20upx;
font-size:36upx;
font-weight: bold;
}
.login-phone{
margin-left: 20upx;
margin-top: 8upx;
display: block;
font-size:24upx;
color: #353535;
}
.uni-row{
margin-top: 60upx;
}
.validate{
width: 90upx;
height: 90upx;
margin: 0 20upx;
}
.v-code{
font-size: 45upx;
text-align: center;
border:1rpx solid #ddd;
border-radius: 20rpx;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.go-login{
height: 100upx;
line-height: 100upx;
border-radius: 50upx;
background-color: #f85314!important;
border-color: #f85314!important;
font-size: 30upx;
color: #FFFFFF;
margin-top: 10upx;
}
.input-code{
width: 0;
height: 0;
}
.uni-icon-clear{
color: #8f8f94;
}
.prohibit-submit{
background-color: #cec6c6!important;
border-color: #cec6c6!important;
}
.user-login{
font-size: 22upx;
color: #8f8f94;
margin-left: 30upx;
}
</style>