HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

多多客微信百度支付宝三端合一小程序平台正式上线

百度小程序 支付宝小程序 微信小程序 小程序

多多客DOODOOKE微信、百度、支付宝三端合一小程序SaaS平台今日正式上线!

开年集齐BAT,多多客DOODOOKE与你一起开启新篇章!

一次制作 三端发布 同时管理

商家只需要在多多客管理后台制作一次小程序,即可在微信、百度、支付宝三大平台同时发布和管理。

多多客三端合一小程序平台帮助商家快速布局小程序,跨越小程序开发的高门槛、高成本,一次性获取微信、支付宝、百度全域千亿级流量,同时节省小程序的制作时间和制作成本。

商家可以在同一个后台统一管理微信、百度、支付宝三端用户和订单等数据,大大优化和完善了商家对小程序的管理效率和使用体验,制定实时营销策略,更加高效运营,降低成本。

随着微信、百度、支付宝、今日头条等越来越多的流量巨头入局小程序,未来小程序将成为商家运营的标配,一款能够同时运行在不同“超级App”中的小程序就显得格外重要。

商家只需要在多多客(doodooke.com)后台通过在线制作,扫码授权,点击发布简单3步,即可轻松拥有微信、百度、支付宝三大平台的小程序。再加上多多客原有的完全可视化拖拽,N+营销工具引流,海量优质行业模板等能力,带给商家更高质量的小程序产品和更完善的小程序服务体系。

继续阅读 »

多多客DOODOOKE微信、百度、支付宝三端合一小程序SaaS平台今日正式上线!

开年集齐BAT,多多客DOODOOKE与你一起开启新篇章!

一次制作 三端发布 同时管理

商家只需要在多多客管理后台制作一次小程序,即可在微信、百度、支付宝三大平台同时发布和管理。

多多客三端合一小程序平台帮助商家快速布局小程序,跨越小程序开发的高门槛、高成本,一次性获取微信、支付宝、百度全域千亿级流量,同时节省小程序的制作时间和制作成本。

商家可以在同一个后台统一管理微信、百度、支付宝三端用户和订单等数据,大大优化和完善了商家对小程序的管理效率和使用体验,制定实时营销策略,更加高效运营,降低成本。

随着微信、百度、支付宝、今日头条等越来越多的流量巨头入局小程序,未来小程序将成为商家运营的标配,一款能够同时运行在不同“超级App”中的小程序就显得格外重要。

商家只需要在多多客(doodooke.com)后台通过在线制作,扫码授权,点击发布简单3步,即可轻松拥有微信、百度、支付宝三大平台的小程序。再加上多多客原有的完全可视化拖拽,N+营销工具引流,海量优质行业模板等能力,带给商家更高质量的小程序产品和更完善的小程序服务体系。

收起阅读 »

uni-app简单网站震撼来袭:无需服务器的SDK来了,100块钱就可以开始创业

uni_app

很简单,我们的思路是这样的:
uni-app提供客户端
ysv8提供服务器端(100块钱终身可用)
下面上效果:


最后是源码:

提示:pc端调试,请按F12点下

继续阅读 »

很简单,我们的思路是这样的:
uni-app提供客户端
ysv8提供服务器端(100块钱终身可用)
下面上效果:


最后是源码:

提示:pc端调试,请按F12点下

收起阅读 »

多个页面引入同一个组件,这个组件会被重复打包

小程序 uniapp
 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 使用指南

Push unipush

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

继续阅读 »

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

收起阅读 »

uni-app 中如何打开外部应用,如:浏览器、淘宝、AppStore、QQ等

打开外部应用 Runtime plus uniapp scheme schema

我们在开发 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 模块,下面我罗列两个相关的方法。其他操作请详读文档。

  1. 调用外部浏览器打开指定的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>  
    
  2. 调用第三方程序

    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 模块,下面我罗列两个相关的方法。其他操作请详读文档。

  1. 调用外部浏览器打开指定的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>  
    
  2. 调用第三方程序

    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配置方法

收起阅读 »

fdsafdsa

fdsafdsa

fdsafdsa

个推基于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>

收起阅读 »