HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

实现扫描二维码和相册识别二维码 html5plus

扫码 HTML5+

废话不多说直接上源码,如有不足,请留言

<template>  
  <div class="scan">  
    <header>  
      <p @click="closeScan">返回</p>  
      <span>请扫码二维码</span>  
      <p @click="scanImg">相册</p>  
    </header>  
    <div id="bcid">  
      <div style="height:40%"></div>  
      <p class="tip">...载入中...</p>  
    </div>  
  </div>  
</template>

下面是js部分

<script type='text/ecmascript-6'>  
let scan = null;  
export default {  
  data() {  
    return {  
      codeUrl: ""  
    };  
  },  
  mounted() {  
    //跳转时自动开启  
    this.startRecognize();  
  },  
  methods: {  
    // 创建扫描控件  
    startRecognize() {  
      let that = this;  
      if (!window.plus) return;  
      scan = new plus.barcode.Barcode(  
        "bcid",  
        [plus.barcode.QR, plus.barcode.EAN8, plus.barcode.EAN13],  
        {  
          frameColor: "#009DE2",  
          scanbarColor: "#009DE2"  
        }  
      );  
      //scan.onmarked = onmarked;  

      // 开始扫描  
      //scan.start();  
      function onmarked(type, result, file) {  
        switch (type) {  
          case plus.barcode.QR:  
            type = "QR";  
            break;  
          case plus.barcode.EAN13:  
            type = "EAN13";  
            break;  
          case plus.barcode.EAN8:  
            type = "EAN8";  
            break;  
          default:  
            type = "其它" + type;  
            break;  
        }  
        result = result.replace(/\n/g, "");  
        that.codeUrl = result;  
        window.localStorage.codeUrl = result;  
       // alert(result);  
        //that.closeScan();  
      }  
    },  
    // 关闭返回  
    closeScan() {  
      if (!window.plus) return;  
      scan.close();  
      this.$router.push({ path: "/home" });  
    },  
    scanImg() {  
      // 从系统相册选择文件  
      if (!window.plus) return;  
      plus.gallery.pick(  
        function(path) {  
         // alert(path);  
          plus.barcode.scan(  
            path,  
            function(type, result) {  
             // alert("Scan success:(" + type + ")" + result);  
              window.localStorage.codeUrl2 = result;  
            },  
            function(e) {  
              console.log(e);  
              window.localStorage.codeUrl2 = e;  
              plus.nativeUI.alert("如果图片无法识别,请用扫码上传");  
            }  
          );  
        },  
        function(e) {  
          alert("取消选择图片");  
        },  
        { filter: "image" }  
      );  
    }  
  }  
};  
</script>

下面是样式可以自行写

<style lang="scss">  
.scan {  
  height: 100%;  
  #bcid {  
    width: 100%;  
    position: absolute;  
    left: 0;  
    right: 0;  
    top: 1rem;  
    bottom: 0;  
    text-align: center;  
    color: #fff;  
    background: #ccc;  
  }  
  header {  
    position: absolute;  
    display: flex;  
    justify-content: space-between;  
    font-size: 16px;  
    color:#009DE2;  
    left: 0.3rem;  
    top: 0;  
    right: 0.3rem;  
    height: 1rem;  
    line-height: 1rem;  
    z-index: 2;  
    span{  
      color: #000;  
    }  
  }  
}  
</style>

觉得有用就关注点个赞吧,么么哒

继续阅读 »

废话不多说直接上源码,如有不足,请留言

<template>  
  <div class="scan">  
    <header>  
      <p @click="closeScan">返回</p>  
      <span>请扫码二维码</span>  
      <p @click="scanImg">相册</p>  
    </header>  
    <div id="bcid">  
      <div style="height:40%"></div>  
      <p class="tip">...载入中...</p>  
    </div>  
  </div>  
</template>

下面是js部分

<script type='text/ecmascript-6'>  
let scan = null;  
export default {  
  data() {  
    return {  
      codeUrl: ""  
    };  
  },  
  mounted() {  
    //跳转时自动开启  
    this.startRecognize();  
  },  
  methods: {  
    // 创建扫描控件  
    startRecognize() {  
      let that = this;  
      if (!window.plus) return;  
      scan = new plus.barcode.Barcode(  
        "bcid",  
        [plus.barcode.QR, plus.barcode.EAN8, plus.barcode.EAN13],  
        {  
          frameColor: "#009DE2",  
          scanbarColor: "#009DE2"  
        }  
      );  
      //scan.onmarked = onmarked;  

      // 开始扫描  
      //scan.start();  
      function onmarked(type, result, file) {  
        switch (type) {  
          case plus.barcode.QR:  
            type = "QR";  
            break;  
          case plus.barcode.EAN13:  
            type = "EAN13";  
            break;  
          case plus.barcode.EAN8:  
            type = "EAN8";  
            break;  
          default:  
            type = "其它" + type;  
            break;  
        }  
        result = result.replace(/\n/g, "");  
        that.codeUrl = result;  
        window.localStorage.codeUrl = result;  
       // alert(result);  
        //that.closeScan();  
      }  
    },  
    // 关闭返回  
    closeScan() {  
      if (!window.plus) return;  
      scan.close();  
      this.$router.push({ path: "/home" });  
    },  
    scanImg() {  
      // 从系统相册选择文件  
      if (!window.plus) return;  
      plus.gallery.pick(  
        function(path) {  
         // alert(path);  
          plus.barcode.scan(  
            path,  
            function(type, result) {  
             // alert("Scan success:(" + type + ")" + result);  
              window.localStorage.codeUrl2 = result;  
            },  
            function(e) {  
              console.log(e);  
              window.localStorage.codeUrl2 = e;  
              plus.nativeUI.alert("如果图片无法识别,请用扫码上传");  
            }  
          );  
        },  
        function(e) {  
          alert("取消选择图片");  
        },  
        { filter: "image" }  
      );  
    }  
  }  
};  
</script>

下面是样式可以自行写

<style lang="scss">  
.scan {  
  height: 100%;  
  #bcid {  
    width: 100%;  
    position: absolute;  
    left: 0;  
    right: 0;  
    top: 1rem;  
    bottom: 0;  
    text-align: center;  
    color: #fff;  
    background: #ccc;  
  }  
  header {  
    position: absolute;  
    display: flex;  
    justify-content: space-between;  
    font-size: 16px;  
    color:#009DE2;  
    left: 0.3rem;  
    top: 0;  
    right: 0.3rem;  
    height: 1rem;  
    line-height: 1rem;  
    z-index: 2;  
    span{  
      color: #000;  
    }  
  }  
}  
</style>

觉得有用就关注点个赞吧,么么哒

收起阅读 »

uni框架中,有关H5页面设置ico,页面标题栏log小图标

第一步,在项目根目录创建index.html.

如图

然后再index.html中复制一下代码

这段代码,在官方文档中有 地址:https://uniapp.dcloud.io/collocation/manifest?id=%e5%ae%8c%e6%95%b4-manifestjson 有关自定义模板的

第二步,将ico图标放入根目录的/static/img 中,如图:

第三步,在创建的index.html文件中加入代码

第四步,在manifest.json中H5配置中配置自定义模板,如图:

最后,配置好之后,编译h5文件,放在本地服务器中预览,是否达到效果

继续阅读 »

第一步,在项目根目录创建index.html.

如图

然后再index.html中复制一下代码

这段代码,在官方文档中有 地址:https://uniapp.dcloud.io/collocation/manifest?id=%e5%ae%8c%e6%95%b4-manifestjson 有关自定义模板的

第二步,将ico图标放入根目录的/static/img 中,如图:

第三步,在创建的index.html文件中加入代码

第四步,在manifest.json中H5配置中配置自定义模板,如图:

最后,配置好之后,编译h5文件,放在本地服务器中预览,是否达到效果

收起阅读 »

HBuilderX 检测不到XCode上的模拟器

模拟器 ios模拟器 HBuilderX

该问题已经整理入笔记,欢迎大家收藏:HBuilderX 检测不到XCode上的模拟器

HBuilder 检测不到XCode上的模拟器

在终端中尝试命令:

xcrun simctl list

返回:xcrun: error: unable to find utility "simctl", not a developer tool or in PATH

搜索发现是多个XCode 版本导致,想想由于昨天刚安装了homebrew,可能是它导致的

解决方法:

选择一个code版本:

sudo xcode-select -s /Applications/Xcode.app/Contents/Developer/

再次运行:xcrun simctl list

问题解决。

继续阅读 »

该问题已经整理入笔记,欢迎大家收藏:HBuilderX 检测不到XCode上的模拟器

HBuilder 检测不到XCode上的模拟器

在终端中尝试命令:

xcrun simctl list

返回:xcrun: error: unable to find utility "simctl", not a developer tool or in PATH

搜索发现是多个XCode 版本导致,想想由于昨天刚安装了homebrew,可能是它导致的

解决方法:

选择一个code版本:

sudo xcode-select -s /Applications/Xcode.app/Contents/Developer/

再次运行:xcrun simctl list

问题解决。

收起阅读 »

uniapp H5端在异步回调中无法调用chooseImage

ui组件 h5 uniapp
  1. uni.chooseImage 在手机浏览器中无法在异步回调中拉起;
  2. 可以在异步完成后调用uni.showModal 然后在showModal的success回调中再去调用uni.chooseImage可以拉起成功。
chooseImage: async function() {  
    let that = this;  
    if (this.imageList.length === 3) {  
        let isContinue = await this.isFullImg();  
        if (!isContinue) {  
            return;  
        }  
    }  

    uni.chooseImage({  
        sourceType: sourceType[that.sourceTypeIndex],  
        sizeType: sizeType[that.sizeTypeIndex],  
        count: that.imageList.length + that.count[that.countIndex] > 3 ? 3 - that.imageList.length : that.count[that.countIndex],  
        success: (res) => {  
            that.imageList = that.imageList.concat(res.tempFilePaths);  
        },  
        fail: (err) => {  
        }  
    })  
},  
isFullImg: function() {  
    let that = this;  
    return new Promise((res) => {  
        setTimeout(function() {  
            //如果我把uni.showModal这段代码注释掉替换成 res(true); ,uni.chooseImage 就不会在手机端的浏览器中调起来  
            uni.showModal({  
                content: "已经有3张图片了,是否清空现有图片?",  
                success: (e) => {  
                    if (e.confirm) {  
                        that.imageList = [];  
                        res(true);  
                    } else {  
                        res(false)  
                    }  
                },  
                fail: () => {  
                    res(false)  
                }  
            })  
        },2000)  
    })  
}  
继续阅读 »
  1. uni.chooseImage 在手机浏览器中无法在异步回调中拉起;
  2. 可以在异步完成后调用uni.showModal 然后在showModal的success回调中再去调用uni.chooseImage可以拉起成功。
chooseImage: async function() {  
    let that = this;  
    if (this.imageList.length === 3) {  
        let isContinue = await this.isFullImg();  
        if (!isContinue) {  
            return;  
        }  
    }  

    uni.chooseImage({  
        sourceType: sourceType[that.sourceTypeIndex],  
        sizeType: sizeType[that.sizeTypeIndex],  
        count: that.imageList.length + that.count[that.countIndex] > 3 ? 3 - that.imageList.length : that.count[that.countIndex],  
        success: (res) => {  
            that.imageList = that.imageList.concat(res.tempFilePaths);  
        },  
        fail: (err) => {  
        }  
    })  
},  
isFullImg: function() {  
    let that = this;  
    return new Promise((res) => {  
        setTimeout(function() {  
            //如果我把uni.showModal这段代码注释掉替换成 res(true); ,uni.chooseImage 就不会在手机端的浏览器中调起来  
            uni.showModal({  
                content: "已经有3张图片了,是否清空现有图片?",  
                success: (e) => {  
                    if (e.confirm) {  
                        that.imageList = [];  
                        res(true);  
                    } else {  
                        res(false)  
                    }  
                },  
                fail: () => {  
                    res(false)  
                }  
            })  
        },2000)  
    })  
}  
收起阅读 »

第一次接触uniapp 制作app 总结1

历时三个月 ,基本完成了公司的app项目!下面我我在使用uniapp时遇到的问题做个总结【可能并非全部】(其实只用了两个多月,后面app部分页面,及流程重做了)  

1、项目开始时
其实项目开始时,页面已经用vue做了一半了,但是后来老大说可能要做成小程序,然后告诉了我这个框架《uniapp》花了近一个星期,边学边做又将vue上的项目转移到uniapp ,做开始遇到了几个小问题都是一些标签使用上的问题,基本多看几遍文档就能够解决!
2、修改BUG
在整个项目编写过程中,我将几个遇到的问题列举下:
1、注册(上传多张图片)
这个问题一共用了差不多一个多星期。
需求:用户注册需要填写信息,上传图片 1、身份证正反2、生活照(用来做人脸识别)3、权限证书(权限证书又分了三种对应三种权限)
这个需求,这么理解,三个权限可以组合,也就是权限1
单独的权限需要传1、身份证正 2、身份证反 3、生活照 4、权限证书
两个权限需要传1、身份证正 2、身份证反 3、生活照 4、权限证书1 5、权限证书2
三个权限都有的 1、身份证正 2、身份证反 3、生活照 4、权限证书1 5、权限证书2 6、权限证书3
在这里遇到的问题就是关于上传的问题,刚开始我没有使用uniapp内置的api 我直接调用的接口,后来发现传不了,需要用表单,但是页面结构都已经做好了,所以就放弃了这一种,然后就是百度,发现又uploadfile 这个api 然后就开始了 钻坑之旅
1.多张图片传不了?(files)
用了差不多一天多的时间发现多张图片传不了???一头雾水不是写的5+app吗?
因为花了太多的时间果断放弃!

  1. 将图片转未base64
    又去百度搜索图片转base64的方法,最后发现转完图片太大了这个方法肯定不行,转完后的大小几十M到一两百M,好吧又果断放弃
    3.然后有回到在页面添加标签form表单的方法
    这个方法用了半天去改页面弄东西,后来发现,需要操作dom通过js去创建表单。。嫌弃太麻烦又放弃了!
    4.最后还是用回了uploadfile
    选来选去最后还是用回了这个内置的api,经过自己不断的学习(问人),发现自己少了个东西 {name:name,uri:图片地址}在一个不起眼的角落里还有一个files 的说明uri 和name 的问题如图


然后果断的加上,通过遍历一个一个的去加,加完以后发现可以了然后调用接口就完事儿了!!oh!mygod!(其实这当中,还有其它的问题,但是都是无关痛痒的,也都是自身的问题就不详细描述了)
2、导航标题
刚学的时候就知道有自定义导航,但是没当回事儿,只是看了一遍没咋注意!觉得就用官方给的就好了呀!后来才知道,还是自己太年轻!
在刚开始用官方给的导航没点问题,感觉也还不错!这个框架真好用!后来一个需求 ,我基本把所有页面的导航都换成了自定义导航!
需求:根据订单不同的状态在导航是否显示二维码跳转页! 在导航上让一个button消失??后来发现可以在上面进行操作(点击执行某个事件onNavigationBarButtonTap(e){})但是无法隐藏,好吧全部改成自定义
3、状态栏
在将导航改成自定义后发现状态栏不见了。果断百度后来知道了height: var(--status-bar-height);去设置状态栏等等。
历史三个月踩了很多坑,还收获了很多,在这里做已分享,可能还有很多的不足之处,希望大家提出宝贵意见!非常感激!又不懂的欢迎来问,直接加我qq就行。虽然我会的不是很多,但是还是希望大家共同进步!

继续阅读 »
历时三个月 ,基本完成了公司的app项目!下面我我在使用uniapp时遇到的问题做个总结【可能并非全部】(其实只用了两个多月,后面app部分页面,及流程重做了)  

1、项目开始时
其实项目开始时,页面已经用vue做了一半了,但是后来老大说可能要做成小程序,然后告诉了我这个框架《uniapp》花了近一个星期,边学边做又将vue上的项目转移到uniapp ,做开始遇到了几个小问题都是一些标签使用上的问题,基本多看几遍文档就能够解决!
2、修改BUG
在整个项目编写过程中,我将几个遇到的问题列举下:
1、注册(上传多张图片)
这个问题一共用了差不多一个多星期。
需求:用户注册需要填写信息,上传图片 1、身份证正反2、生活照(用来做人脸识别)3、权限证书(权限证书又分了三种对应三种权限)
这个需求,这么理解,三个权限可以组合,也就是权限1
单独的权限需要传1、身份证正 2、身份证反 3、生活照 4、权限证书
两个权限需要传1、身份证正 2、身份证反 3、生活照 4、权限证书1 5、权限证书2
三个权限都有的 1、身份证正 2、身份证反 3、生活照 4、权限证书1 5、权限证书2 6、权限证书3
在这里遇到的问题就是关于上传的问题,刚开始我没有使用uniapp内置的api 我直接调用的接口,后来发现传不了,需要用表单,但是页面结构都已经做好了,所以就放弃了这一种,然后就是百度,发现又uploadfile 这个api 然后就开始了 钻坑之旅
1.多张图片传不了?(files)
用了差不多一天多的时间发现多张图片传不了???一头雾水不是写的5+app吗?
因为花了太多的时间果断放弃!

  1. 将图片转未base64
    又去百度搜索图片转base64的方法,最后发现转完图片太大了这个方法肯定不行,转完后的大小几十M到一两百M,好吧又果断放弃
    3.然后有回到在页面添加标签form表单的方法
    这个方法用了半天去改页面弄东西,后来发现,需要操作dom通过js去创建表单。。嫌弃太麻烦又放弃了!
    4.最后还是用回了uploadfile
    选来选去最后还是用回了这个内置的api,经过自己不断的学习(问人),发现自己少了个东西 {name:name,uri:图片地址}在一个不起眼的角落里还有一个files 的说明uri 和name 的问题如图


然后果断的加上,通过遍历一个一个的去加,加完以后发现可以了然后调用接口就完事儿了!!oh!mygod!(其实这当中,还有其它的问题,但是都是无关痛痒的,也都是自身的问题就不详细描述了)
2、导航标题
刚学的时候就知道有自定义导航,但是没当回事儿,只是看了一遍没咋注意!觉得就用官方给的就好了呀!后来才知道,还是自己太年轻!
在刚开始用官方给的导航没点问题,感觉也还不错!这个框架真好用!后来一个需求 ,我基本把所有页面的导航都换成了自定义导航!
需求:根据订单不同的状态在导航是否显示二维码跳转页! 在导航上让一个button消失??后来发现可以在上面进行操作(点击执行某个事件onNavigationBarButtonTap(e){})但是无法隐藏,好吧全部改成自定义
3、状态栏
在将导航改成自定义后发现状态栏不见了。果断百度后来知道了height: var(--status-bar-height);去设置状态栏等等。
历史三个月踩了很多坑,还收获了很多,在这里做已分享,可能还有很多的不足之处,希望大家提出宝贵意见!非常感激!又不懂的欢迎来问,直接加我qq就行。虽然我会的不是很多,但是还是希望大家共同进步!

收起阅读 »

windows下生成p12证书的方法,用于ios开发

其实很简单,使用这个工具就可以生成了

https://www.yunedit.com/createcert

使用方法非常简单,也就是登录进去这个工具,创建证书,就可以像使用苹果电脑钥匙串访问那样创建一个csr文件了,还能在线生成p12证书

而且是免费的,非常好用

继续阅读 »

其实很简单,使用这个工具就可以生成了

https://www.yunedit.com/createcert

使用方法非常简单,也就是登录进去这个工具,创建证书,就可以像使用苹果电脑钥匙串访问那样创建一个csr文件了,还能在线生成p12证书

而且是免费的,非常好用

收起阅读 »

阿里小程序IDE官方内嵌uni-app,为开发者提供多端开发服务

支付宝小程序

随着微信、阿里、百度、头条、QQ纷纷推出小程序,开发者的开发维护成本持续上升,负担过重。这点已经成为共识,现在连小程序平台厂商也充分意识到了。

阿里小程序团队,为了减轻开发者的负担,在官方的小程序开发者工具中整合了多端框架。

经过阿里团队仔细评估,uni-app 在产品完成度、跨平台支持度、开发者社区、可持续发展等多方面优势明显,最终选定 uni-app 内置于阿里小程序开发工具中,为开发者提供多端开发解决方案。

经过之前1个月的公测,10月10日,阿里小程序正式发布0.70版开发者工具,通过 uni-app 实现多端开发,成为本次版本更新的亮点功能!

如下图,在阿里小程序工具左侧主导航选择 uni-app,创建项目,即可开发。


阿里小程序开发工具更新说明详见:https://docs.alipay.com/mini/ide/0.70-stable

集成 uni-app,这对于阿里团队而言,并不是一个容易做出的决定。毕竟 uni-app 是一个三方产品,要经过复杂的评审流程。

这一方面突显出阿里团队以开发者需求为本的优秀价值观,另一方面也证明 uni-app 的产品确实过硬。

很多开发者都有多端需求,但又没有足够精力去了解、评估 uni-app,而处于观望态度。现在大家可以更放心的使用 uni-app 了,它没有让阿里失望,也不会让你失望。

自从 uni-app 推出以来,DCloud也取得了高速的发展,目前拥有370万开发者,框架运行在4.6亿手机用户设备上,月活达到1.35亿(仅包括部分接入DCloud统计平台的数据)。并且数据仍在高速增长中,在市场占有率上处于遥遥领先的位置。

本次阿里小程序工具集成 uni-app,会让 uni-app 继续快速爆发,取得更大的成功。

后续DCloud还将深化与阿里的合作,在serverless等领域给开发者提供更多优质服务。

使用多端框架开发各端应用,是多赢的模式。开发者减轻了负担,获得了更多新流量。而小程序平台厂商,也能保证自己平台上的各种应用可以被及时的更新。

DCloud欢迎更多小程序平台厂商,与我们一起合作,为开发者、平台、用户的多赢而努力。

进一步了解uni-app,详见:https://uniapp.dcloud.io

欢迎扫码关注DCloud公众号,转发消息到朋友圈。

继续阅读 »

随着微信、阿里、百度、头条、QQ纷纷推出小程序,开发者的开发维护成本持续上升,负担过重。这点已经成为共识,现在连小程序平台厂商也充分意识到了。

阿里小程序团队,为了减轻开发者的负担,在官方的小程序开发者工具中整合了多端框架。

经过阿里团队仔细评估,uni-app 在产品完成度、跨平台支持度、开发者社区、可持续发展等多方面优势明显,最终选定 uni-app 内置于阿里小程序开发工具中,为开发者提供多端开发解决方案。

经过之前1个月的公测,10月10日,阿里小程序正式发布0.70版开发者工具,通过 uni-app 实现多端开发,成为本次版本更新的亮点功能!

如下图,在阿里小程序工具左侧主导航选择 uni-app,创建项目,即可开发。


阿里小程序开发工具更新说明详见:https://docs.alipay.com/mini/ide/0.70-stable

集成 uni-app,这对于阿里团队而言,并不是一个容易做出的决定。毕竟 uni-app 是一个三方产品,要经过复杂的评审流程。

这一方面突显出阿里团队以开发者需求为本的优秀价值观,另一方面也证明 uni-app 的产品确实过硬。

很多开发者都有多端需求,但又没有足够精力去了解、评估 uni-app,而处于观望态度。现在大家可以更放心的使用 uni-app 了,它没有让阿里失望,也不会让你失望。

自从 uni-app 推出以来,DCloud也取得了高速的发展,目前拥有370万开发者,框架运行在4.6亿手机用户设备上,月活达到1.35亿(仅包括部分接入DCloud统计平台的数据)。并且数据仍在高速增长中,在市场占有率上处于遥遥领先的位置。

本次阿里小程序工具集成 uni-app,会让 uni-app 继续快速爆发,取得更大的成功。

后续DCloud还将深化与阿里的合作,在serverless等领域给开发者提供更多优质服务。

使用多端框架开发各端应用,是多赢的模式。开发者减轻了负担,获得了更多新流量。而小程序平台厂商,也能保证自己平台上的各种应用可以被及时的更新。

DCloud欢迎更多小程序平台厂商,与我们一起合作,为开发者、平台、用户的多赢而努力。

进一步了解uni-app,详见:https://uniapp.dcloud.io

欢迎扫码关注DCloud公众号,转发消息到朋友圈。

收起阅读 »

使用uni-app开发小程序,比直接原生开发小程序好在哪里?

对比 原生 微信

小程序原生开发有不少槽点:

  1. 原生wxml开发对Node、预编译器、webpack支持不好,影响开发效率和工程构建流程。所以大公司都会用框架开发
  2. 微信定义的这套语法,wxml、wxs,以及wx:if等语法,私有化太强。不如正经学vue,学会了全端通用,而不是只为微信小程序
  3. vue生态里有太多周边工具,可以提高开发效率,比如ide、校验器、三方库。。。而微信的开发者工具和专业编辑器相比实在不好用,个性化设置也非常少

作为前端工程师,除了微信小程序,还要开发web、其他小程序甚至App,人们不喜欢来回切换开发工具和变更语法思考方式。

uni-app自然可以解决这些问题,但开发者又经常有些顾虑:

  1. 怕使用uni-app后,微信小程序里有的功能无法实现,受制于uni-app的更新
  2. 怕性能不如原生WXML
  3. 怕框架不成熟,跳到坑里
  4. 担心社区生态不完善

本文从开发者关心的功能、性能、学习门槛、开发体验、生态、可扩展性等维度,逐个分析对比,给予说明。

1.功能实现

开发者最常问的问题:如果小程序迭代升级,新增了一批API,但uni-app框架未及时更新,该怎么办?

其实这是误解,uni-app不限制底层API 调用;在小程序端,uni-app支持直接编写微信原生代码。

类比传统web开发,如果vue、react等框架的使用,造成开发者无法操作浏览器提供的所有api,那这样的框架肯定是不成熟的。小程序开发也一样,uni-app框架中,同样可调用微信提供的所有原生API。

故如果存在某些API(平台特有或新增API),uni-app尚未封装,开发者可直接在uni-app中编写微信原生API,即wx.开头的各种API。

举个例子,目前uni-app虽然尚未封装跨平台的广告(ad)组件,但开发者在小程序端依然可以使用微信<ad>组件来展现广告,代码示例如下:

 <view>  
    <view>微信公众号关注组件</view>  
    <view>  
        <!-- uni-app未封装,但可直接使用微信原生的official-account组件-->  
        <official-account></official-account>  
    </view>  
</view>

包括微信小程序自定义组件、WXS、云开发这些复杂用法,在uni-app里一样全面支持。尤其是wxs,目前在各种小程序开发框架里,也只有uni-app支持。

所以,结论是:使用uni-app框架开发,在功能上和原生小程序开发没有区别,不会有任何限制。

2. 性能体验

开发者常问的第二个问题:三方框架,内部大多做了层层封装,这些封装是否会增加运行负载,导致性能下降?

同样是多虑了,uni-app不会导致性能下载,甚至对很多环节做了自动优化,很多场景下性能体验比微信原生开发更好。

类似使用vue.js开发web,不但不会造成性能比原生js差,反而由于虚拟dom和差量更新技术的运用,在大多数场景下,比开发者手动写代码操作dom的性能还好。

小程序中需要频繁的写setData代码来更新数据,这里很重要的就是差量数据更新。如果不做差量,代码性能不好,如果每处逻辑都判断差量数据更新,那代码写起来太麻烦了。

使用uni-app,底层自动差量数据更新,简单而高性能。

我们从优化理论、实测数据两个维度来仔细说明。

2.1 理论:框架优化方案

为提高性能体验,小程序从架构设计层面做了很多工作:

  • 逻辑层、视图层分离,避免JS运算阻塞视图渲染
  • 单独定义组件标签(wxml),减少DOM复杂度
  • 精简样式(wxss),提升渲染性能
  • 复杂组件原生化(video/map等),解决web组件的功能/体验缺失

通过这些规范约束,大幅提升了小程序的整体性能体验,但依然存在不少性能坑点,其中以setData最为频繁普遍。

这里引用微信官方的描述,简单介绍一下setData背后的工作原理:

小程序的视图层目前使用 WebView 作为渲染载体,而逻辑层是由独立的 JavascriptCore 作为运行环境。在架构上,WebView 和 JavascriptCore 都是独立的模块,并不具备数据直接共享的通道。当前,视图层和逻辑层的数据传输,实际上通过两边提供的 evaluateJavascript 所实现。

为简化开发,微信将evaluateJavascript调用封装成了setData JS方法,实现视图层和逻辑层的数据传输,数据流示意图如下:

setData的执行会受到很多因素的影响,setData每次传递数据量过大或频繁被调用(见微信官方介绍),都可能引发性能体验问题。

幸运的是,uni-app在这两个方面都有优化。

2.1.1 减少 setData 传递数据量

假设当前页面有一个列表(初始值为a,b,c,d),现在要向列表后追加4个新列表项(e,f,g,h),我们分别以微信原生、uni-app 两种模式编写代码。

小程序原生代码:

page({  
    data:{  
        list:['a','b','c','d']  
    },  
    change:function(){  
        let newData = ['e','f','g','h'];  
        this.data.list.push(...newData);  
        this.setData({  
            list:this.data.list  
        })  
    }  
})

如上微信原生代码,change方法执行时,会将list中的a,b,c,d,e,f,g,h8个列表项通过setData全部传输过去。

uni-app 代码:

export default{  
    data(){  
        return {  
            list:['a','b','c','d']  
        }  
    },  
    methods:{  
        change:function(){  
            let newData = ['e','f','g','h'];  
            this.list.push(...newData)  
        }  
    }  
}

如上uni-app代码,change方法执行时,仅会将list中的e,f,g,h4个新增列表项传输过去,实现了setData传输量的极简化。

uni-app借鉴了 westore JSON Diff库,在调用setData之前,会先比对历史数据,精确、高效计算出有变化的差量数据,然后再调用setData,仅传输变化的数据,这样就实现 setData 传递数据量的最小化,大幅提高通讯性能。

Tips:也许有些同学对传递数据从a,b,c,d,e,f,g,h8个列表项优化为e,f,g,h4个列表项,不以为然,但我们提醒,不要小看这个机制,上述只是demo示例。

  • 在实际列表场景中,每个列表项可能包含缩略图、标题、摘要、时间等各种信息,每个列表项数据都会更大(假设为1k);
  • 假设当前页面有20个列表项,连续上拉4次后,页面变成100条记录;如果再次上拉,页面变成120条记录时,情况会有不同
  • 上述微信原生的方式,将120条记录数据(120k)全部传输过去
  • 上述 uni-app 模式,仅会将新增的20条(101 ~ 120)记录数据(20k)传输过去,数据量是原生方式的1/6!
  • 当页面列表项数据越多,这个差别就越大,页面有200条记录时,uni-app传递数据量会变成微信原生数据传递量的1/10!

2.1.2 减少 setData 调用频次

假设我们有更改多个变量值的需求,我们分别以微信原生、uni-app 两种模式编写代码。

小程序原生代码:

change:function(){  
    this.setData({a:1});  
    this.setData({b:2});  
    this.setData({c:3});  
    this.setData({d:4});  
}

如上四次调用setData,就会引发4次逻辑层、视图层数据通讯

uni-app 代码:

change:function(){  
    this.a = 1;  
    this.b = 2;  
    this.c = 3;  
    this.d = 4;  
}

如上uni-app的代码,最后会被合并成{"a":1,"b":2,"c":3,"d":4}一条数据,然后仅调用一次setData完成所有数据传递,大幅降低了setData的调用频次。

uni-app之所以有这样的优势,是因为 uni-app 基于 Vue Runtime 深度定制实现,并借助了 Vue 的 nextTick 机制。

2.2 实测:性能对比数据

有了如上的理论分析,我们接着进行真机实测,用数据来对比。

测试模型如下:

  • 开发内容:开发一个仿微博小程序首页的复杂长列表,支持下拉刷新、上拉翻页、点赞。

仿微博的列表是一个包含很多组件的列表,这种复杂列表对性能的压力更大,很适合做性能测试。

  • 界面如下:

  • 开发版本:使用微信原生、uni-app分别开发两套代码,uni-app使用cli方式默认安装。

  • 测试代码开源(Github仓库地址:https://github.com/dcloudio/test-framework),
    Tips:若有同学觉得测试代码写法欠妥,欢迎提交 PR 或 Issus,本项目下还有其它框架的测试代码,开发者可忽略

  • 测试机型:红米 Redmi 6 Pro、MIUI 10.2.2.0 稳定版(最新版)、微信版本 7.0.3(最新版)

  • 测试环境:每个框架开始测试前,杀掉各App进程、清空内存,保证测试机环境基本一致;每次从本地读取静态数据,屏蔽网络差异。

从触发上拉加载到数据更新、页面渲染完成,需要准确计时。人眼视觉计时肯定不行,我们采用程序埋点的方式,制定了如下计时时机:

  • 计时开始时机:交互事件触发,框架赋值之前,如:上拉加载(onReachBottom)函数开头
  • 计时结束时机:页面渲染完毕(微信setData回调函数开头)

Tips:setData回调函数开头可认为是页面渲染完成的时间,是因为微信setData定义如下(微信规范):

字段 类型 必填 描述
data Object 这次要改变的数据
callback Function setData引起的界面更新渲染完毕后的回调函数

测试方式:从页面空列表开始,通过程序自动触发上拉加载,每次新增20条列表,记录单次耗时;固定间隔连续触发 N 次上拉加载,使得页面达到 20*N 条列表,计算这 N 次触发上拉到渲染完成的平均耗时。

测试结果如下:

列表条数 微信原生 uni-app
200 770 641
400 876 741
600 1111 910
800 1406 1113
1000 1690 1321

说明:以400条微博列表为例,从页面空列表开始,每隔1秒触发一次上拉加载(新增20条微博),记录单次耗时,触发20次后停止(页面达到400条微博),计算这20次的平均耗时,结果微信原生在这20次 触发上拉 -> 渲染完成 的平均耗时为876毫秒,uni-app是741毫秒。

这个数据,可能违反了很多人的直觉,uni-app 的性能竟然比微信原生还好!

当然,使用微信原生开发,也可以自己单独写代码优化setData。但每处业务都编写太多判断是不现实的,自然是用框架更舒心。

这个结果,和web开发类似,web开发也有原生js开发、vue、react框架等情况。如果不做特殊优化,原生js写的网页,性能经常还不如vue、react框架的性能。

也恰恰是因为Vuereact框架的优秀,性能好,开发体验好,所以原生js开发已经逐渐减少使用了。

3.社区生态

3.1 周边轮子

小程序是脱离web自造生态,很多web生态中轮子无法使用。

微信小程序还是有周边生态的,而其他几家小程序平台的生态基本没建起来。

uni-app的周边生态非常丰富,在插件市场有近数千个插件,详见 ext.dcloud.net.cn

首先uni-app兼容小程序的生态,各种自定义组件均可直接引入使用。在此基础上,uni-app的插件市场,有更多vue组件,同时可跨多端使用,并且性能优秀。

这使得uni-app的生态成为最丰富的小程序开发生态。

比如富文本解析、图表、自定义下拉刷新等组件,uni-app的插件性能均超过了wxparse、wx-echart等微信小程序组件。包括 uni ui等ui库的性能也超过了vant、iview等ui库的小程序版。

如果开发者需要丰富和高性能的组件,更应该使用uni-app,而不是原生小程序开发。

3.2 活跃的QQ/微信群和论坛

uni-app官方有 70 个开发者QQ/微信交流群(大多2千人群,近10万开发者),三方群更多。

问答社区,每天有数百篇帖子。活跃度与微信小程序官方论坛相同,远超过其他小程序官方论坛。

uni-app三方培训活跃,腾讯课堂官方都为uni-app制作了课程,各种培训网站到处可见免费或收费的uni-app培训视频教程。

4.学习门槛、开发体验

首先微信原生的开发语法,既像React ,又像Vue,有点不伦不类,对于开发者来说,等于又要学习一套新的语法,大幅提升了学习成本,这一直被大家所诟病。

uni-app则对开发者更为友好,简单来说是 vue的语法 + 小程序的js api。

它遵循Vue.js语法规范,组件和API遵循微信小程序命名,这些都属于通用技术栈,学习它们是前端必备技能,uni-app没有太多额外学习成本。

有一定 Vue.js 和微信小程序开发经验的开发者可快速上手 uni-app

没学过vue的同学,也不用掌握vue的全部,只需了解vue基础语法、数据绑定、列表渲染、组件等,其他如路由、loader、cli、node.js、webpack并不需要学。

因为HBuilderX工具搭配uni-app可以免终端开发,可视化创建项目、可视化安装组件和扩展编译器,也就是uni-app的学习门槛,比web开发的vue.js还低。

开发体验层面,微信原生开发相比uni-app有较大差距,主要体现在:

  • 更为强大的组件化开发能力:vue的组件开发比小程序自定义组件开发的体验要好很多
  • 应用状态管理:uni-app支持vuex
  • 使用 Sass 等 CSS 预处理器
  • 完整的 ES Next 语法支持
  • 自定义构建策略

开发工具维度,差距更大:

  • 微信开发者工具被吐槽无数
  • uni-app的出品公司,同时也是HBuilder的出品公司,DCloud.io。HBuilder/HBuilderX系列是四大主流前端开发工具(可对比百度指数),其为uni-app做了很多优化,故uni-app的开发效率、易用性非微信原生开发可及。

这里可以输出一个结论:如果你需要工程化能力,那就直接忘了微信原生开发吧。

5.未来扩展性

虽然当前产品仅要求发布到微信小程序,但阿里、百度、字节跳动、QQ、快应用等众多平台的流量越来越多,覆盖这些平台是迟早要考虑的事情。

此时,uni-ap的跨端功能将成为程序员的自救神器,基于uni-app开发的小程序,无需修改,即可同时发布到多家小程序,甚至App、H5平台。这不是梦想,而是现实。大家可依次扫描如下8个二维码,亲自体验最全面的跨平台效果!。

6.结语

uni-app 微信
功能 相同 相同
性能 常规场景更优 需要自己编写复杂代码才能提高性能
社区生态 丰富,更多高性能组件 丰富
开发体验 纯vue体验,高效、统一;工程化能力强 语法私有化;工程化能力弱
多端能力 同时支持H5、多家小程序、跨平台App 只能用于微信小程序

结论:只开发微信小程序,也应该使用uni-app

继续阅读 »

小程序原生开发有不少槽点:

  1. 原生wxml开发对Node、预编译器、webpack支持不好,影响开发效率和工程构建流程。所以大公司都会用框架开发
  2. 微信定义的这套语法,wxml、wxs,以及wx:if等语法,私有化太强。不如正经学vue,学会了全端通用,而不是只为微信小程序
  3. vue生态里有太多周边工具,可以提高开发效率,比如ide、校验器、三方库。。。而微信的开发者工具和专业编辑器相比实在不好用,个性化设置也非常少

作为前端工程师,除了微信小程序,还要开发web、其他小程序甚至App,人们不喜欢来回切换开发工具和变更语法思考方式。

uni-app自然可以解决这些问题,但开发者又经常有些顾虑:

  1. 怕使用uni-app后,微信小程序里有的功能无法实现,受制于uni-app的更新
  2. 怕性能不如原生WXML
  3. 怕框架不成熟,跳到坑里
  4. 担心社区生态不完善

本文从开发者关心的功能、性能、学习门槛、开发体验、生态、可扩展性等维度,逐个分析对比,给予说明。

1.功能实现

开发者最常问的问题:如果小程序迭代升级,新增了一批API,但uni-app框架未及时更新,该怎么办?

其实这是误解,uni-app不限制底层API 调用;在小程序端,uni-app支持直接编写微信原生代码。

类比传统web开发,如果vue、react等框架的使用,造成开发者无法操作浏览器提供的所有api,那这样的框架肯定是不成熟的。小程序开发也一样,uni-app框架中,同样可调用微信提供的所有原生API。

故如果存在某些API(平台特有或新增API),uni-app尚未封装,开发者可直接在uni-app中编写微信原生API,即wx.开头的各种API。

举个例子,目前uni-app虽然尚未封装跨平台的广告(ad)组件,但开发者在小程序端依然可以使用微信<ad>组件来展现广告,代码示例如下:

 <view>  
    <view>微信公众号关注组件</view>  
    <view>  
        <!-- uni-app未封装,但可直接使用微信原生的official-account组件-->  
        <official-account></official-account>  
    </view>  
</view>

包括微信小程序自定义组件、WXS、云开发这些复杂用法,在uni-app里一样全面支持。尤其是wxs,目前在各种小程序开发框架里,也只有uni-app支持。

所以,结论是:使用uni-app框架开发,在功能上和原生小程序开发没有区别,不会有任何限制。

2. 性能体验

开发者常问的第二个问题:三方框架,内部大多做了层层封装,这些封装是否会增加运行负载,导致性能下降?

同样是多虑了,uni-app不会导致性能下载,甚至对很多环节做了自动优化,很多场景下性能体验比微信原生开发更好。

类似使用vue.js开发web,不但不会造成性能比原生js差,反而由于虚拟dom和差量更新技术的运用,在大多数场景下,比开发者手动写代码操作dom的性能还好。

小程序中需要频繁的写setData代码来更新数据,这里很重要的就是差量数据更新。如果不做差量,代码性能不好,如果每处逻辑都判断差量数据更新,那代码写起来太麻烦了。

使用uni-app,底层自动差量数据更新,简单而高性能。

我们从优化理论、实测数据两个维度来仔细说明。

2.1 理论:框架优化方案

为提高性能体验,小程序从架构设计层面做了很多工作:

  • 逻辑层、视图层分离,避免JS运算阻塞视图渲染
  • 单独定义组件标签(wxml),减少DOM复杂度
  • 精简样式(wxss),提升渲染性能
  • 复杂组件原生化(video/map等),解决web组件的功能/体验缺失

通过这些规范约束,大幅提升了小程序的整体性能体验,但依然存在不少性能坑点,其中以setData最为频繁普遍。

这里引用微信官方的描述,简单介绍一下setData背后的工作原理:

小程序的视图层目前使用 WebView 作为渲染载体,而逻辑层是由独立的 JavascriptCore 作为运行环境。在架构上,WebView 和 JavascriptCore 都是独立的模块,并不具备数据直接共享的通道。当前,视图层和逻辑层的数据传输,实际上通过两边提供的 evaluateJavascript 所实现。

为简化开发,微信将evaluateJavascript调用封装成了setData JS方法,实现视图层和逻辑层的数据传输,数据流示意图如下:

setData的执行会受到很多因素的影响,setData每次传递数据量过大或频繁被调用(见微信官方介绍),都可能引发性能体验问题。

幸运的是,uni-app在这两个方面都有优化。

2.1.1 减少 setData 传递数据量

假设当前页面有一个列表(初始值为a,b,c,d),现在要向列表后追加4个新列表项(e,f,g,h),我们分别以微信原生、uni-app 两种模式编写代码。

小程序原生代码:

page({  
    data:{  
        list:['a','b','c','d']  
    },  
    change:function(){  
        let newData = ['e','f','g','h'];  
        this.data.list.push(...newData);  
        this.setData({  
            list:this.data.list  
        })  
    }  
})

如上微信原生代码,change方法执行时,会将list中的a,b,c,d,e,f,g,h8个列表项通过setData全部传输过去。

uni-app 代码:

export default{  
    data(){  
        return {  
            list:['a','b','c','d']  
        }  
    },  
    methods:{  
        change:function(){  
            let newData = ['e','f','g','h'];  
            this.list.push(...newData)  
        }  
    }  
}

如上uni-app代码,change方法执行时,仅会将list中的e,f,g,h4个新增列表项传输过去,实现了setData传输量的极简化。

uni-app借鉴了 westore JSON Diff库,在调用setData之前,会先比对历史数据,精确、高效计算出有变化的差量数据,然后再调用setData,仅传输变化的数据,这样就实现 setData 传递数据量的最小化,大幅提高通讯性能。

Tips:也许有些同学对传递数据从a,b,c,d,e,f,g,h8个列表项优化为e,f,g,h4个列表项,不以为然,但我们提醒,不要小看这个机制,上述只是demo示例。

  • 在实际列表场景中,每个列表项可能包含缩略图、标题、摘要、时间等各种信息,每个列表项数据都会更大(假设为1k);
  • 假设当前页面有20个列表项,连续上拉4次后,页面变成100条记录;如果再次上拉,页面变成120条记录时,情况会有不同
  • 上述微信原生的方式,将120条记录数据(120k)全部传输过去
  • 上述 uni-app 模式,仅会将新增的20条(101 ~ 120)记录数据(20k)传输过去,数据量是原生方式的1/6!
  • 当页面列表项数据越多,这个差别就越大,页面有200条记录时,uni-app传递数据量会变成微信原生数据传递量的1/10!

2.1.2 减少 setData 调用频次

假设我们有更改多个变量值的需求,我们分别以微信原生、uni-app 两种模式编写代码。

小程序原生代码:

change:function(){  
    this.setData({a:1});  
    this.setData({b:2});  
    this.setData({c:3});  
    this.setData({d:4});  
}

如上四次调用setData,就会引发4次逻辑层、视图层数据通讯

uni-app 代码:

change:function(){  
    this.a = 1;  
    this.b = 2;  
    this.c = 3;  
    this.d = 4;  
}

如上uni-app的代码,最后会被合并成{"a":1,"b":2,"c":3,"d":4}一条数据,然后仅调用一次setData完成所有数据传递,大幅降低了setData的调用频次。

uni-app之所以有这样的优势,是因为 uni-app 基于 Vue Runtime 深度定制实现,并借助了 Vue 的 nextTick 机制。

2.2 实测:性能对比数据

有了如上的理论分析,我们接着进行真机实测,用数据来对比。

测试模型如下:

  • 开发内容:开发一个仿微博小程序首页的复杂长列表,支持下拉刷新、上拉翻页、点赞。

仿微博的列表是一个包含很多组件的列表,这种复杂列表对性能的压力更大,很适合做性能测试。

  • 界面如下:

  • 开发版本:使用微信原生、uni-app分别开发两套代码,uni-app使用cli方式默认安装。

  • 测试代码开源(Github仓库地址:https://github.com/dcloudio/test-framework),
    Tips:若有同学觉得测试代码写法欠妥,欢迎提交 PR 或 Issus,本项目下还有其它框架的测试代码,开发者可忽略

  • 测试机型:红米 Redmi 6 Pro、MIUI 10.2.2.0 稳定版(最新版)、微信版本 7.0.3(最新版)

  • 测试环境:每个框架开始测试前,杀掉各App进程、清空内存,保证测试机环境基本一致;每次从本地读取静态数据,屏蔽网络差异。

从触发上拉加载到数据更新、页面渲染完成,需要准确计时。人眼视觉计时肯定不行,我们采用程序埋点的方式,制定了如下计时时机:

  • 计时开始时机:交互事件触发,框架赋值之前,如:上拉加载(onReachBottom)函数开头
  • 计时结束时机:页面渲染完毕(微信setData回调函数开头)

Tips:setData回调函数开头可认为是页面渲染完成的时间,是因为微信setData定义如下(微信规范):

字段 类型 必填 描述
data Object 这次要改变的数据
callback Function setData引起的界面更新渲染完毕后的回调函数

测试方式:从页面空列表开始,通过程序自动触发上拉加载,每次新增20条列表,记录单次耗时;固定间隔连续触发 N 次上拉加载,使得页面达到 20*N 条列表,计算这 N 次触发上拉到渲染完成的平均耗时。

测试结果如下:

列表条数 微信原生 uni-app
200 770 641
400 876 741
600 1111 910
800 1406 1113
1000 1690 1321

说明:以400条微博列表为例,从页面空列表开始,每隔1秒触发一次上拉加载(新增20条微博),记录单次耗时,触发20次后停止(页面达到400条微博),计算这20次的平均耗时,结果微信原生在这20次 触发上拉 -> 渲染完成 的平均耗时为876毫秒,uni-app是741毫秒。

这个数据,可能违反了很多人的直觉,uni-app 的性能竟然比微信原生还好!

当然,使用微信原生开发,也可以自己单独写代码优化setData。但每处业务都编写太多判断是不现实的,自然是用框架更舒心。

这个结果,和web开发类似,web开发也有原生js开发、vue、react框架等情况。如果不做特殊优化,原生js写的网页,性能经常还不如vue、react框架的性能。

也恰恰是因为Vuereact框架的优秀,性能好,开发体验好,所以原生js开发已经逐渐减少使用了。

3.社区生态

3.1 周边轮子

小程序是脱离web自造生态,很多web生态中轮子无法使用。

微信小程序还是有周边生态的,而其他几家小程序平台的生态基本没建起来。

uni-app的周边生态非常丰富,在插件市场有近数千个插件,详见 ext.dcloud.net.cn

首先uni-app兼容小程序的生态,各种自定义组件均可直接引入使用。在此基础上,uni-app的插件市场,有更多vue组件,同时可跨多端使用,并且性能优秀。

这使得uni-app的生态成为最丰富的小程序开发生态。

比如富文本解析、图表、自定义下拉刷新等组件,uni-app的插件性能均超过了wxparse、wx-echart等微信小程序组件。包括 uni ui等ui库的性能也超过了vant、iview等ui库的小程序版。

如果开发者需要丰富和高性能的组件,更应该使用uni-app,而不是原生小程序开发。

3.2 活跃的QQ/微信群和论坛

uni-app官方有 70 个开发者QQ/微信交流群(大多2千人群,近10万开发者),三方群更多。

问答社区,每天有数百篇帖子。活跃度与微信小程序官方论坛相同,远超过其他小程序官方论坛。

uni-app三方培训活跃,腾讯课堂官方都为uni-app制作了课程,各种培训网站到处可见免费或收费的uni-app培训视频教程。

4.学习门槛、开发体验

首先微信原生的开发语法,既像React ,又像Vue,有点不伦不类,对于开发者来说,等于又要学习一套新的语法,大幅提升了学习成本,这一直被大家所诟病。

uni-app则对开发者更为友好,简单来说是 vue的语法 + 小程序的js api。

它遵循Vue.js语法规范,组件和API遵循微信小程序命名,这些都属于通用技术栈,学习它们是前端必备技能,uni-app没有太多额外学习成本。

有一定 Vue.js 和微信小程序开发经验的开发者可快速上手 uni-app

没学过vue的同学,也不用掌握vue的全部,只需了解vue基础语法、数据绑定、列表渲染、组件等,其他如路由、loader、cli、node.js、webpack并不需要学。

因为HBuilderX工具搭配uni-app可以免终端开发,可视化创建项目、可视化安装组件和扩展编译器,也就是uni-app的学习门槛,比web开发的vue.js还低。

开发体验层面,微信原生开发相比uni-app有较大差距,主要体现在:

  • 更为强大的组件化开发能力:vue的组件开发比小程序自定义组件开发的体验要好很多
  • 应用状态管理:uni-app支持vuex
  • 使用 Sass 等 CSS 预处理器
  • 完整的 ES Next 语法支持
  • 自定义构建策略

开发工具维度,差距更大:

  • 微信开发者工具被吐槽无数
  • uni-app的出品公司,同时也是HBuilder的出品公司,DCloud.io。HBuilder/HBuilderX系列是四大主流前端开发工具(可对比百度指数),其为uni-app做了很多优化,故uni-app的开发效率、易用性非微信原生开发可及。

这里可以输出一个结论:如果你需要工程化能力,那就直接忘了微信原生开发吧。

5.未来扩展性

虽然当前产品仅要求发布到微信小程序,但阿里、百度、字节跳动、QQ、快应用等众多平台的流量越来越多,覆盖这些平台是迟早要考虑的事情。

此时,uni-ap的跨端功能将成为程序员的自救神器,基于uni-app开发的小程序,无需修改,即可同时发布到多家小程序,甚至App、H5平台。这不是梦想,而是现实。大家可依次扫描如下8个二维码,亲自体验最全面的跨平台效果!。

6.结语

uni-app 微信
功能 相同 相同
性能 常规场景更优 需要自己编写复杂代码才能提高性能
社区生态 丰富,更多高性能组件 丰富
开发体验 纯vue体验,高效、统一;工程化能力强 语法私有化;工程化能力弱
多端能力 同时支持H5、多家小程序、跨平台App 只能用于微信小程序

结论:只开发微信小程序,也应该使用uni-app

收起阅读 »

分享 iOS 离线打包精简版 demo

离线打包

demo https://gitee.com/hw2016/hbuilderx_simplify

具体请看原贴:

帖子 https://www.jianshu.com/p/35d6111bd215

我使用的资源库如图(精简版):

继续阅读 »

demo https://gitee.com/hw2016/hbuilderx_simplify

具体请看原贴:

帖子 https://www.jianshu.com/p/35d6111bd215

我使用的资源库如图(精简版):

收起阅读 »

HQChart使用教程37 - 如何在uni-app创建k线图(app)

@[TOC](HQChart使用教程37 - 如何在uni-app创建k线图 app)

插件目录

在这里插入图片描述

创建步骤

1. 拷贝插件到工程中

创建一个空的uni-app 工程, 把wechathqchart 目录拷贝到工程中。
例子里 我建了一个hqchart.uniapp的目录, 把插件的文件拷贝到这个目录里
在这里插入图片描述

2. 创建一个page页 在page页中

import umychart.wechat.3.0.js
创建一个画布元素
绑定手势事件

代码如下:

<template>  
    <view>  
        <view>   
            <canvas id="kline" canvas-id='kline' class='kline' style="width: 400px; height: 600px"   
              @touchstart="KLineTouchStart" @touchmove='KLineTouchMove' @touchend='KLineTouchEnd' ></canvas>    
        </view>  

        <view class="button-sp-area">  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(PERIOD_ID.KLINE_DAY_ID)">日线</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(PERIOD_ID.KLINE_WEEK_ID)">周线</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(PERIOD_ID.KLINE_MINUTE_ID)">1分钟</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(PERIOD_ID.KLINE_15MINUTE_ID)">15分钟</button>  
        </view>  

        <view class="button-sp-area">  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLineIndex(0,'BOLL')">BOLL</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLineIndex(1,'RSI')">RSI</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLineIndex(2,'WR')">WR</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLineIndex(0,'MA')">MA</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLineIndex(1,'VOL')">VOL</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLineIndex(1,'MACD')">MACD</button>  
        </view>  

        <view class="button-sp-area">  
            <button class="mini-btn" type="default" size="mini" @click="ChangeSymbol('000001.sz')">000001.sz</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeSymbol('600000.sh')">600000.sh</button>  
        </view>  
    </view>  

</template>  

<script>  
import {JSCommon} from '../../umychart.uniapp/umychart.wechat.3.0.js'  

function DefaultData() { }  

DefaultData.GetKLineOption = function ()   
{  
    let data =   
    {  
        Type: '历史K线图',   

        Windows: //窗口指标  
        [  
            {Index:"MA",Modify: false, Change: false},   
            {Index:"VOL",Modify: false, Change: false},  
            {Index:"MACD",Modify: false, Change: false},  
        ],   

        CorssCursorTouchEnd:true,  
        IsShowRightMenu:false,       //是否显示右键菜单  
        CorssCursorInfo:{ Left:2,Right:2 },  

        Border: //边框  
        {  
            Left:   1,  
            Right:  1, //右边间距  
            Top:    1,  
            Bottom: 25,  
        },  

        KLine:  
        {  
            Right:1,                            //复权 0 不复权 1 前复权 2 后复权  
            Period:0,                           //周期: 0 日线 1 周线 2 月线 3 年线   
            PageSize:12,  
            IsShowTooltip:false,  
        },  

        Frame:  //子框架设置 (Height 窗口高度比例值)  
        [  
            {   SplitCount:3,  
                //Height:4,  
                IsShowLeftText:true,   
                IsShowRightText:false  
            },  
            {  
                SplitCount:2,  
                //Height:2,  
                IsShowLeftText:true,   
                IsShowRightText:false  
            },  
            {  
                SplitCount:2,  
                //Height:2,  
                IsShowLeftText:true,   
                IsShowRightText:false  
            }  
        ],  

        ExtendChart:  
        [  
            {Name:'KLineTooltip' },  
        ],  

    };  

    return data;  
}  

//周期枚举  
var PERIOD_ID=  
{  
    KLINE_DAY_ID:0,  
    KLINE_WEEK_ID:1,  
    KLINE_MONTH_ID:2,  
    KLINE_YEAR_ID:3,  

    KLINE_MINUTE_ID:4,  
    KLINE_5MINUTE_ID:5,  
    KLINE_15MINUTE_ID:6,  
    KLINE_30MINUTE_ID:7,  
    KLINE_60MINUTE_ID:8  
}  

var g_KLine=  
{  
    JSChart:null  
};  

export default   
{  
    name:'HQChart',  

    data()   
    {  
        let data=  
        {  
            Symbol:'600000.sh',  

            KLine:  
            {  
                Option:DefaultData.GetKLineOption(),  
                IsShow:false,  
                Display:'none',  
                Width:400,  
                Height:600,  
            },  

            PERIOD_ID:PERIOD_ID,  
        };  

        return data;  
    },  

    onLoad()   
    {  

    },  

    onReady()  
    {  
        this.ChangeKLinePeriod(PERIOD_ID.KLINE_DAY_ID);  
    },  

    methods:   
    {  
        //////////////////////////////////////////////////////////////////////////////////////  
        CreateKLineChart:function()  
        {  
            if (this.KLine.JSChart) return;  

            let element = new JSCommon.JSCanvasElement();  
            // #ifdef APP-PLUS  
            element.IsUniApp=true;  //canvas需要指定下 是uniapp的app  
            // #endif  
            element.ID = 'kline';  
            element.Height = this.KLine.Height;  //高度宽度需要手动绑定!!  
            element.Width = this.KLine.Width;  

            g_KLine.JSChart = JSCommon.JSChart.Init(element);  
            this.KLine.Option.NetworkFilter=this.NetworkFilter;  
            this.KLine.Option.Symbol=this.Symbol;  
            g_KLine.JSChart.SetOption(this.KLine.Option);  
        },  

        //K线周期切换  
        ChangeKLinePeriod:function(period)  
        {  
            if (!g_KLine.JSChart)    //不存在创建  
            {  
                this.KLine.Option.Period=period;  
                this.CreateKLineChart();  
            }  
            else  
            {  
                g_KLine.JSChart.ChangePeriod(period);  
            }  
        },  

        //切换指标 windowIndex=窗口索引 0开始, name=指标名字/ID  
        ChangeKLineIndex:function(windowIndex, name)  
        {  
            if (!g_KLine.JSChart) return;  

            g_KLine.JSChart.ChangeIndex(windowIndex,name);  
        },  

        //切换股票  
        ChangeSymbol:function(symbol)  
        {  
            if (!g_KLine.JSChart) return;  

            g_KLine.JSChart.ChangeSymbol(symbol);  
        },  

        NetworkFilter:function(data, callback)  
        {  
            console.log('[HQChart:NetworkFilter] data', data.Name);  
        },  

        //KLine事件  
        KLineTouchStart: function (event)   
        {  
          if (g_KLine.JSChart) g_KLine.JSChart.OnTouchStart(event);  
        },  

        KLineTouchMove: function (event)   
        {  
          if (g_KLine.JSChart) g_KLine.JSChart.OnTouchMove(event);  
        },  

        KLineTouchEnd: function (event)   
        {  
          if (g_KLine.JSChart) g_KLine.JSChart.OnTouchEnd(event);  
        },  
    }  
}  
</script>  

<style>  

    .content {  
        display: flex;  
        flex-direction: column;  
        align-items: center;  
        justify-content: center;  
    }  

    .logo {  
        height: 200upx;  
        width: 200upx;  
        margin-top: 200upx;  
        margin-left: auto;  
        margin-right: auto;  
        margin-bottom: 50upx;  
    }  

    .text-area {  
        display: flex;  
        justify-content: center;  
    }  

    .title {  
        font-size: 36upx;  
        color: #8f8f94;  
    }  
</style>  

注意

 element.IsUniApp=true 

如果是uniapp-app平台的需要设置为true,其他平台的不需要设置

3.运行到模拟器

在这里插入图片描述

特别感谢 秋云

帮我解决了在uniapp-app 环境中measureText 无法计算的问题。
官方bugi地址: https://ask.dcloud.net.cn/question/70374

如果还有问题可以加交流QQ群: 950092318

HQChart代码地址
地址:github.com/jones2000/HQChart

继续阅读 »

@[TOC](HQChart使用教程37 - 如何在uni-app创建k线图 app)

插件目录

在这里插入图片描述

创建步骤

1. 拷贝插件到工程中

创建一个空的uni-app 工程, 把wechathqchart 目录拷贝到工程中。
例子里 我建了一个hqchart.uniapp的目录, 把插件的文件拷贝到这个目录里
在这里插入图片描述

2. 创建一个page页 在page页中

import umychart.wechat.3.0.js
创建一个画布元素
绑定手势事件

代码如下:

<template>  
    <view>  
        <view>   
            <canvas id="kline" canvas-id='kline' class='kline' style="width: 400px; height: 600px"   
              @touchstart="KLineTouchStart" @touchmove='KLineTouchMove' @touchend='KLineTouchEnd' ></canvas>    
        </view>  

        <view class="button-sp-area">  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(PERIOD_ID.KLINE_DAY_ID)">日线</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(PERIOD_ID.KLINE_WEEK_ID)">周线</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(PERIOD_ID.KLINE_MINUTE_ID)">1分钟</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(PERIOD_ID.KLINE_15MINUTE_ID)">15分钟</button>  
        </view>  

        <view class="button-sp-area">  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLineIndex(0,'BOLL')">BOLL</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLineIndex(1,'RSI')">RSI</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLineIndex(2,'WR')">WR</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLineIndex(0,'MA')">MA</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLineIndex(1,'VOL')">VOL</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLineIndex(1,'MACD')">MACD</button>  
        </view>  

        <view class="button-sp-area">  
            <button class="mini-btn" type="default" size="mini" @click="ChangeSymbol('000001.sz')">000001.sz</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeSymbol('600000.sh')">600000.sh</button>  
        </view>  
    </view>  

</template>  

<script>  
import {JSCommon} from '../../umychart.uniapp/umychart.wechat.3.0.js'  

function DefaultData() { }  

DefaultData.GetKLineOption = function ()   
{  
    let data =   
    {  
        Type: '历史K线图',   

        Windows: //窗口指标  
        [  
            {Index:"MA",Modify: false, Change: false},   
            {Index:"VOL",Modify: false, Change: false},  
            {Index:"MACD",Modify: false, Change: false},  
        ],   

        CorssCursorTouchEnd:true,  
        IsShowRightMenu:false,       //是否显示右键菜单  
        CorssCursorInfo:{ Left:2,Right:2 },  

        Border: //边框  
        {  
            Left:   1,  
            Right:  1, //右边间距  
            Top:    1,  
            Bottom: 25,  
        },  

        KLine:  
        {  
            Right:1,                            //复权 0 不复权 1 前复权 2 后复权  
            Period:0,                           //周期: 0 日线 1 周线 2 月线 3 年线   
            PageSize:12,  
            IsShowTooltip:false,  
        },  

        Frame:  //子框架设置 (Height 窗口高度比例值)  
        [  
            {   SplitCount:3,  
                //Height:4,  
                IsShowLeftText:true,   
                IsShowRightText:false  
            },  
            {  
                SplitCount:2,  
                //Height:2,  
                IsShowLeftText:true,   
                IsShowRightText:false  
            },  
            {  
                SplitCount:2,  
                //Height:2,  
                IsShowLeftText:true,   
                IsShowRightText:false  
            }  
        ],  

        ExtendChart:  
        [  
            {Name:'KLineTooltip' },  
        ],  

    };  

    return data;  
}  

//周期枚举  
var PERIOD_ID=  
{  
    KLINE_DAY_ID:0,  
    KLINE_WEEK_ID:1,  
    KLINE_MONTH_ID:2,  
    KLINE_YEAR_ID:3,  

    KLINE_MINUTE_ID:4,  
    KLINE_5MINUTE_ID:5,  
    KLINE_15MINUTE_ID:6,  
    KLINE_30MINUTE_ID:7,  
    KLINE_60MINUTE_ID:8  
}  

var g_KLine=  
{  
    JSChart:null  
};  

export default   
{  
    name:'HQChart',  

    data()   
    {  
        let data=  
        {  
            Symbol:'600000.sh',  

            KLine:  
            {  
                Option:DefaultData.GetKLineOption(),  
                IsShow:false,  
                Display:'none',  
                Width:400,  
                Height:600,  
            },  

            PERIOD_ID:PERIOD_ID,  
        };  

        return data;  
    },  

    onLoad()   
    {  

    },  

    onReady()  
    {  
        this.ChangeKLinePeriod(PERIOD_ID.KLINE_DAY_ID);  
    },  

    methods:   
    {  
        //////////////////////////////////////////////////////////////////////////////////////  
        CreateKLineChart:function()  
        {  
            if (this.KLine.JSChart) return;  

            let element = new JSCommon.JSCanvasElement();  
            // #ifdef APP-PLUS  
            element.IsUniApp=true;  //canvas需要指定下 是uniapp的app  
            // #endif  
            element.ID = 'kline';  
            element.Height = this.KLine.Height;  //高度宽度需要手动绑定!!  
            element.Width = this.KLine.Width;  

            g_KLine.JSChart = JSCommon.JSChart.Init(element);  
            this.KLine.Option.NetworkFilter=this.NetworkFilter;  
            this.KLine.Option.Symbol=this.Symbol;  
            g_KLine.JSChart.SetOption(this.KLine.Option);  
        },  

        //K线周期切换  
        ChangeKLinePeriod:function(period)  
        {  
            if (!g_KLine.JSChart)    //不存在创建  
            {  
                this.KLine.Option.Period=period;  
                this.CreateKLineChart();  
            }  
            else  
            {  
                g_KLine.JSChart.ChangePeriod(period);  
            }  
        },  

        //切换指标 windowIndex=窗口索引 0开始, name=指标名字/ID  
        ChangeKLineIndex:function(windowIndex, name)  
        {  
            if (!g_KLine.JSChart) return;  

            g_KLine.JSChart.ChangeIndex(windowIndex,name);  
        },  

        //切换股票  
        ChangeSymbol:function(symbol)  
        {  
            if (!g_KLine.JSChart) return;  

            g_KLine.JSChart.ChangeSymbol(symbol);  
        },  

        NetworkFilter:function(data, callback)  
        {  
            console.log('[HQChart:NetworkFilter] data', data.Name);  
        },  

        //KLine事件  
        KLineTouchStart: function (event)   
        {  
          if (g_KLine.JSChart) g_KLine.JSChart.OnTouchStart(event);  
        },  

        KLineTouchMove: function (event)   
        {  
          if (g_KLine.JSChart) g_KLine.JSChart.OnTouchMove(event);  
        },  

        KLineTouchEnd: function (event)   
        {  
          if (g_KLine.JSChart) g_KLine.JSChart.OnTouchEnd(event);  
        },  
    }  
}  
</script>  

<style>  

    .content {  
        display: flex;  
        flex-direction: column;  
        align-items: center;  
        justify-content: center;  
    }  

    .logo {  
        height: 200upx;  
        width: 200upx;  
        margin-top: 200upx;  
        margin-left: auto;  
        margin-right: auto;  
        margin-bottom: 50upx;  
    }  

    .text-area {  
        display: flex;  
        justify-content: center;  
    }  

    .title {  
        font-size: 36upx;  
        color: #8f8f94;  
    }  
</style>  

注意

 element.IsUniApp=true 

如果是uniapp-app平台的需要设置为true,其他平台的不需要设置

3.运行到模拟器

在这里插入图片描述

特别感谢 秋云

帮我解决了在uniapp-app 环境中measureText 无法计算的问题。
官方bugi地址: https://ask.dcloud.net.cn/question/70374

如果还有问题可以加交流QQ群: 950092318

HQChart代码地址
地址:github.com/jones2000/HQChart

收起阅读 »

HQChart使用教程35 - 如何在uni-app创建K线图(h5)

插件目录

在这里插入图片描述

创建步骤

1. 创建一个空的uni-app 工程, 把umychart_uniapp_h5 目录拷贝到工程中。

在这里插入图片描述

2. 创建一个page页 在page页中 import umychart.uniapp.h5.js

代码如下:

<template>  
    <div class='divchart' >  
        <div class='kline' id="kline" ref='kline'  v-show="KLine.IsShow"></div>  
    </div>  
</template>  

<script>  
import HQChart from '../../umychart_uniapp_h5/umychart.uniapp.h5.js'  

function DefaultData() { }  

DefaultData.GetKLineOption = function ()   
{  
    let data =   
    {  
        Type: '历史K线图',   

        Windows: //窗口指标  
        [  
            {Index:"MA",Modify: false, Change: false},   
            {Index:"VOL",Modify: false, Change: false}  
        ],   

        IsCorssOnlyDrawKLine:true,  
        CorssCursorTouchEnd:true,  

        Border: //边框  
        {  
            Left:   1,  
            Right:  1, //右边间距  
            Top:    25,  
            Bottom: 25,  
        },  

        KLine:  
        {  
            Right:1,                            //复权 0 不复权 1 前复权 2 后复权  
            Period:0,                           //周期: 0 日线 1 周线 2 月线 3 年线   
            PageSize:70,  
            IsShowTooltip:false  
        },  

        ExtendChart:  
        [  
            {Name:'KLineTooltip' }, //开启手机端tooltip  
        ],   

    };  

    return data;  
}  

export default   
{  
    data()   
    {  
        let data=  
        {  
            Symbol:'600000.sh',  
            ChartWidth:300,  
            ChartHeight:600,  
            KLine:  
            {  
                JSChart:null,  
                Option:DefaultData.GetKLineOption(),   
                IsShow:true,  
            }  
        };  

        return data;  
    },  

    onLoad()   
    {  

    },  

    onReady()  
    {  
        this.OnSize();  
        this.CreateKLineChart();   
    },  

    methods:   
    {  
        OnSize()  
        {  
            var chartHeight = this.ChartHeight;  
            var chartWidth = this.ChartWidth;  

            var kline=this.$refs.kline;  
            kline.style.width=chartWidth+'px';  
            kline.style.height=chartHeight+'px';  
            if (this.KLine.JSChart) this.KLine.JSChart.OnSize();  
        },  

        CreateKLineChart()  //创建K线图  
        {  
            if (this.KLine.JSChart) return;  
            this.KLine.Option.Symbol=this.Symbol;  
            let chart=HQChart.JSChart.Init(this.$refs.kline);  
            chart.SetOption(this.KLine.Option);  
            this.KLine.JSChart=chart;  
        },  
    }  
}  
</script>  

<style>  

</style>  

在这里插入图片描述

3.在浏览器里运行

在这里插入图片描述

效果图

在这里插入图片描述

如果还有问题可以加交流QQ群: 950092318

HQChart代码地址
地址:github.com/jones2000/HQChart

继续阅读 »

插件目录

在这里插入图片描述

创建步骤

1. 创建一个空的uni-app 工程, 把umychart_uniapp_h5 目录拷贝到工程中。

在这里插入图片描述

2. 创建一个page页 在page页中 import umychart.uniapp.h5.js

代码如下:

<template>  
    <div class='divchart' >  
        <div class='kline' id="kline" ref='kline'  v-show="KLine.IsShow"></div>  
    </div>  
</template>  

<script>  
import HQChart from '../../umychart_uniapp_h5/umychart.uniapp.h5.js'  

function DefaultData() { }  

DefaultData.GetKLineOption = function ()   
{  
    let data =   
    {  
        Type: '历史K线图',   

        Windows: //窗口指标  
        [  
            {Index:"MA",Modify: false, Change: false},   
            {Index:"VOL",Modify: false, Change: false}  
        ],   

        IsCorssOnlyDrawKLine:true,  
        CorssCursorTouchEnd:true,  

        Border: //边框  
        {  
            Left:   1,  
            Right:  1, //右边间距  
            Top:    25,  
            Bottom: 25,  
        },  

        KLine:  
        {  
            Right:1,                            //复权 0 不复权 1 前复权 2 后复权  
            Period:0,                           //周期: 0 日线 1 周线 2 月线 3 年线   
            PageSize:70,  
            IsShowTooltip:false  
        },  

        ExtendChart:  
        [  
            {Name:'KLineTooltip' }, //开启手机端tooltip  
        ],   

    };  

    return data;  
}  

export default   
{  
    data()   
    {  
        let data=  
        {  
            Symbol:'600000.sh',  
            ChartWidth:300,  
            ChartHeight:600,  
            KLine:  
            {  
                JSChart:null,  
                Option:DefaultData.GetKLineOption(),   
                IsShow:true,  
            }  
        };  

        return data;  
    },  

    onLoad()   
    {  

    },  

    onReady()  
    {  
        this.OnSize();  
        this.CreateKLineChart();   
    },  

    methods:   
    {  
        OnSize()  
        {  
            var chartHeight = this.ChartHeight;  
            var chartWidth = this.ChartWidth;  

            var kline=this.$refs.kline;  
            kline.style.width=chartWidth+'px';  
            kline.style.height=chartHeight+'px';  
            if (this.KLine.JSChart) this.KLine.JSChart.OnSize();  
        },  

        CreateKLineChart()  //创建K线图  
        {  
            if (this.KLine.JSChart) return;  
            this.KLine.Option.Symbol=this.Symbol;  
            let chart=HQChart.JSChart.Init(this.$refs.kline);  
            chart.SetOption(this.KLine.Option);  
            this.KLine.JSChart=chart;  
        },  
    }  
}  
</script>  

<style>  

</style>  

在这里插入图片描述

3.在浏览器里运行

在这里插入图片描述

效果图

在这里插入图片描述

如果还有问题可以加交流QQ群: 950092318

HQChart代码地址
地址:github.com/jones2000/HQChart

收起阅读 »

HQChart使用教程44-uniapp使用条件编译同时支持h5,app,小程序

今天在群里帮一位朋友排查HQChart同时在多端使用的问题。我整理了以下

背景

由于小程序/app很多局限性(无法创建DOM,canvas异步绘图等)导致HQChart开发的时候分成两个版本(小程序版本和H5页面版本)。
使用条件编译我们可以把这2个版本组件同时包含的工程中,并且通过平台判断动态加载对应版本的js.

安装插件

在工程里建2个目录,把HQChart的2个版本分别考入对应的目录里。
版本对应关系看以前的教程
HQChart使用教程35 - 如何在uni-app创建K线图(h5)
HQChart使用教程37 - 如何在uni-app创建k线图(app)
在这里插入图片描述

template 设置

由于小程序/app是无法动态创建dom,所有只能是先在模板里写死一个画布,在初始化的时候绑定到HQChart中。H5是可以直接内部创建dom,所以只需要传入一个div,HQChart自动会创建画布. 我们使用条件编译在不同的平台使用不同的模板
注意 id的名字尽量使用不一样的,如h5如果使用id='kline' 在app/小程序就使用id='kline2'

<!--  #ifdef  H5 -->  
<div>  
    <div class='kline' id="kline" ref='kline'  v-show="KLine.IsShow"></div>  
    <div class='minute' id="minute" ref='minute'  v-show="Minute.IsShow"></div>  
</div>  
<!--  #endif -->  

<!--  #ifndef  H5 -->  
<view>  
    <canvas id="kline2" canvas-id='kline2' class='kline2' v-bind:style="{width: ChartWidth+'px', height: ChartHeight+'px'}"  v-show="KLine.IsShow"  
      @touchstart="KLineTouchStart" @touchmove='KLineTouchMove' @touchend='KLineTouchEnd' ></canvas>    
      <canvas id="minute2" canvas-id='minute2' class='minute' v-bind:style="{width: ChartWidth+'px', height: ChartHeight+'px'}" v-show="Minute.IsShow"  
       @touchstart="MinuteTouchStart" @touchmove='MinuteTouchMove' @touchend='MinuteTouchEnd' ></canvas>  
</view>  
<!--  #endif -->

这样2个模板就同时存在一个页面中了

创建插件设置

为每个平台创建一个创建插件的函数,然后通过一个总的创建函数动态调用对应的创建方法
下面是也创建K线图为例子‘CreateKLineChart_h5()'是h5平台的创建插件方法, 'CreateKLineChart_app()'是app和小程序创建的方法,在"CreateKLineChart()'通过条件编译就可以动态选择使用对应的创建函数
为了代码的可读和可维护性我这边是拆分成2个创建函数,你也可以在CreateKLineChart里面把2个平台的创建都写里面,只过不这样可读性比较差。

CreateKLineChart()  
{  
    // #ifdef H5  
    this.CreateKLineChart_h5();  
    // #endif  

    // #ifndef H5  
    this.CreateKLineChart_app();  
    // #endif  
},

下面是2个平台对应的创建方法,走势图的创建也是一样

CreateKLineChart_h5()  //创建K线图  
{  
    if (g_KLine.JSChart) return;  
    this.KLine.Option.Symbol=this.Symbol;  
    let chart=HQChart.JSChart.Init(this.$refs.kline);  
this.KLine.Option.NetworkFilter=this.NetworkFilter;  
    chart.SetOption(this.KLine.Option);  
    g_KLine.JSChart=chart;  
},  

CreateKLineChart_app()  
{  
    if (this.KLine.JSChart) return;  

    let element = new JSCommon.JSCanvasElement();  
    // #ifdef APP-PLUS  
    element.IsUniApp=true;  //canvas需要指定下 是uniapp的app  
    // #endif  
    element.ID = 'kline2';  
    element.Height = this.ChartHeight;  //高度宽度需要手动绑定!!  
    element.Width = this.ChartWidth;  

    g_KLine.JSChart = JSCommon.JSChart.Init(element);  
    this.KLine.Option.NetworkFilter=this.NetworkFilter;  
    this.KLine.Option.Symbol=this.Symbol;  
    g_KLine.JSChart.SetOption(this.KLine.Option);  
},

HQChart大小调整

由于app/小程序无法获取dom,所以只能是在外部把画布的长宽设置到HQChart中(动态获取只能通过其他的查询元素函数获取,比较麻烦,关键还是异步的,非常搞不懂获取一个元素信息还使用异步,难道以目前的手机配置查询几千几万了dom信息不能在毫秒级处理完),
H5是可以动态获取dom,就不存在这个文件,改变了外层的div调用HQChart的OnSize()方法就可以动态把div的大小绑定画布上。

OnSize()  
{  
    // #ifdef H5  
    this.OnSize_h5();  
    // #endif  
},  

OnSize_h5()  
{  
    var chartHeight = this.ChartHeight;  
    var chartWidth = this.ChartWidth;  

    var kline=this.$refs.kline;  
    kline.style.width=chartWidth+'px';  
    kline.style.height=chartHeight+'px';  
    if (g_KLine.JSChart) g_KLine.JSChart.OnSize();  

    var minute=this.$refs.minute;  
    minute.style.width=chartWidth+'px';  
    minute.style.height=chartHeight+'px';  
    if (g_Minute.JSChart) g_Minute.JSChart.OnSize();  
},

这样多端支持就完成了。点运行,然后喝杯咖啡吧,编译调试真的很慢。

效果图

在这里插入图片描述
在这里插入图片描述

完整代码

<template>  
    <div class='divchart' >  
        <!--  #ifdef  H5 -->  
        <div>  
        <div class='kline' id="kline" ref='kline'  v-show="KLine.IsShow"></div>  
        <div class='minute' id="minute" ref='minute'  v-show="Minute.IsShow"></div>  
        </div>  
        <!--  #endif -->  

        <!--  #ifndef  H5 -->  
        <view>  
            <canvas id="kline2" canvas-id='kline2' class='kline2' v-bind:style="{width: ChartWidth+'px', height: ChartHeight+'px'}"  v-show="KLine.IsShow"  
              @touchstart="KLineTouchStart" @touchmove='KLineTouchMove' @touchend='KLineTouchEnd' ></canvas>    
              <canvas id="minute2" canvas-id='minute2' class='minute' v-bind:style="{width: ChartWidth+'px', height: ChartHeight+'px'}" v-show="Minute.IsShow"  
               @touchstart="MinuteTouchStart" @touchmove='MinuteTouchMove' @touchend='MinuteTouchEnd' ></canvas>  
        </view>  
        <!--  #endif -->  

        <div class="button-sp-area">  
            <button class="mini-btn" type="default" size="mini" @click="ChangeMinutePeriod(MINUTE_PERIOD_ID.MINUTE_ID)">分时</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeMinutePeriod(MINUTE_PERIOD_ID.MINUTE_5DAY_ID)">5日</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(KLINE_PERIOD_ID.KLINE_DAY_ID)">日线</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(KLINE_PERIOD_ID.KLINE_WEEK_ID)">周线</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(KLINE_PERIOD_ID.KLINE_MINUTE_ID)">1分钟</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(KLINE_PERIOD_ID.KLINE_15MINUTE_ID)">15分钟</button>  
        </div>  

    </div>  
</template>  

<script>  
// #ifdef H5      
import HQChart from '../../umychart_uniapp_h5/umychart.uniapp.h5.js'  
// #endif  

// #ifndef H5  
import {JSCommon} from '../../umychart.uniapp/umychart.wechat.3.0.js'  
// #endif  

function DefaultData() { }  

DefaultData.GetKLineOption = function ()   
{  
    let data =   
    {  
        Type: '历史K线图',   

        Windows: //窗口指标  
        [  
            {Index:"MA",Modify: false, Change: false},   
            {Index:"VOL",Modify: false, Change: false}  
        ],   

        IsCorssOnlyDrawKLine:true,  
        CorssCursorTouchEnd:true,  

        Border: //边框  
        {  
            Left:   1,  
            Right:  1, //右边间距  
            Top:    25,  
            Bottom: 25,  
        },  

        KLine:  
        {  
            Right:1,                            //复权 0 不复权 1 前复权 2 后复权  
            Period:0,                           //周期: 0 日线 1 周线 2 月线 3 年线   
            PageSize:30,  
            IsShowTooltip:false  
        },  

        ExtendChart:  
        [  
            {Name:'KLineTooltip' }, //开启手机端tooltip  
        ],   

        Frame:  //子框架设置  
        [  
            {SplitCount:3},  
            {SplitCount:2},  
            {SplitCount:3},  
        ],  

    };  

    return data;  
}  

DefaultData.GetMinuteOption=function()  
{  
    var option=   
    {  
        Type:'分钟走势图',   //创建图形类型  

        Windows: //窗口指标  
        [  

        ],   

        IsAutoUpdate:true,       //是自动更新数据  
        DayCount:1,                 //1 最新交易日数据 >1 多日走势图  
        IsShowRightMenu:false,       //是否显示右键菜单  
        CorssCursorTouchEnd:true,  

        MinuteLine:  
        {  
            //IsDrawAreaPrice:false,      //是否画价格面积图  
        },  

        Border: //边框  
        {  
            Left:1,    //左边间距  
            Right:1,   //右边间距  
            Top:20,  
            Bottom:20  
        },  

        Frame:  //子框架设置  
        [  
            {SplitCount:3},  
            {SplitCount:2},  
            {SplitCount:3},  
        ],  

        ExtendChart:    //扩展图形  
        [  
            {Name:'MinuteTooltip' }  //手机端tooltip  
        ],  
    };  

    return option;  
}  

//周期枚举  
var KLINE_PERIOD_ID=  
{  
    KLINE_DAY_ID:0,  
    KLINE_WEEK_ID:1,  
    KLINE_MONTH_ID:2,  
    KLINE_YEAR_ID:3,  

    KLINE_MINUTE_ID:4,  
    KLINE_5MINUTE_ID:5,  
    KLINE_15MINUTE_ID:6,  
    KLINE_30MINUTE_ID:7,  
    KLINE_60MINUTE_ID:8  
}  

//周期枚举  
var MINUTE_PERIOD_ID=  
{  
    MINUTE_ID:1,  
    MINUTE_2DAY_ID:2,  
    MINUTE_3DAY_ID:3,  
    MINUTE_4DAY_ID:4,  
    MINUTE_5DAY_ID:5,  
}  

var g_KLine={ JSChart:null };  
var g_Minute={ JSChart:null };  
export default   
{  
    data()   
    {  
        let data=  
        {  
            Symbol:'600000.sh',  
            ChartWidth:300,  
            ChartHeight:500,  
            KLine:  
            {  

                Option:DefaultData.GetKLineOption(),   
                IsShow:true,  
            },  
            Minute:  
            {  

                Option:DefaultData.GetMinuteOption(),  
                IsShow:false,  
            },  

            MINUTE_PERIOD_ID:MINUTE_PERIOD_ID,  
            KLINE_PERIOD_ID:KLINE_PERIOD_ID,  
        };  

        return data;  
    },  

    onLoad()   
    {  

    },  

    onReady()  
    {  
        this.OnSize();  
        this.CreateKLineChart();   
    },  

    methods:   
    {  
        OnSize()  
        {  
            // #ifdef H5  
            this.OnSize_h5();  
            // #endif  
        },  

        OnSize_h5()  
        {  
            var chartHeight = this.ChartHeight;  
            var chartWidth = this.ChartWidth;  

            var kline=this.$refs.kline;  
            kline.style.width=chartWidth+'px';  
            kline.style.height=chartHeight+'px';  
            if (g_KLine.JSChart) g_KLine.JSChart.OnSize();  

            var minute=this.$refs.minute;  
            minute.style.width=chartWidth+'px';  
            minute.style.height=chartHeight+'px';  
            if (g_Minute.JSChart) g_Minute.JSChart.OnSize();  
        },  

        CreateKLineChart_h5()  //创建K线图  
        {  
            if (g_KLine.JSChart) return;  
            this.KLine.Option.Symbol=this.Symbol;  
            let chart=HQChart.JSChart.Init(this.$refs.kline);  
            this.KLine.Option.NetworkFilter=this.NetworkFilter;  
            chart.SetOption(this.KLine.Option);  
            g_KLine.JSChart=chart;  
        },  

        CreateKLineChart_app()  
        {  
            if (this.KLine.JSChart) return;  

            let element = new JSCommon.JSCanvasElement();  
            // #ifdef APP-PLUS  
            element.IsUniApp=true;  //canvas需要指定下 是uniapp的app  
            // #endif  
            element.ID = 'kline2';  
            element.Height = this.ChartHeight;  //高度宽度需要手动绑定!!  
            element.Width = this.ChartWidth;  

            g_KLine.JSChart = JSCommon.JSChart.Init(element);  
            this.KLine.Option.NetworkFilter=this.NetworkFilter;  
            this.KLine.Option.Symbol=this.Symbol;  
            g_KLine.JSChart.SetOption(this.KLine.Option);  
        },  

        CreateKLineChart()  
        {  
            // #ifdef H5  
            this.CreateKLineChart_h5();  
            // #endif  

            // #ifndef H5  
            this.CreateKLineChart_app();  
            // #endif  
        },  

        //K线周期切换  
        ChangeKLinePeriod:function(period)  
        {  
            this.Minute.IsShow=false;  
            this.KLine.IsShow=true;  
            if (!g_KLine.JSChart)    //不存在创建  
            {  
                this.KLine.Option.Period=period;  
                this.CreateKLineChart_h5();  
            }  
            else  
            {  
                g_KLine.JSChart.ChangePeriod(period);  
            }  
        },  

        CreateMinuteChart_h5() //创建日线图  
        {  
            if (g_Minute.JSChart) return;  
            this.Minute.Option.Symbol=this.Symbol;  
            let chart=HQChart.JSChart.Init(this.$refs.minute);  
            this.Minute.Option.NetworkFilter=this.NetworkFilter;  
            chart.SetOption(this.Minute.Option);  
            g_Minute.JSChart=chart;  
        },  

        CreateMinuteChart_app()  
        {  
            if (g_Minute.JSChart) return;  

            var element = new JSCommon.JSCanvasElement();  
            // #ifdef APP-PLUS  
            element.IsUniApp=true;  //canvas需要指定下 是uniapp的app  
            // #endif  
            element.ID = 'minute2';  
            element.Height = this.ChartHeight;  //高度宽度需要手动绑定!!  
            element.Width = this.ChartWidth;  

            g_Minute.JSChart = JSCommon.JSChart.Init(element);  
            this.Minute.Option.NetworkFilter=this.NetworkFilter;  
            this.Minute.Option.Symbol=this.Symbol;  
            g_Minute.JSChart.SetOption(this.Minute.Option);  
        },  

        CreateMinuteChart()  
        {  
            // #ifdef H5  
            this.CreateMinuteChart_h5();  
            // #endif  

            // #ifndef H5  
            this.CreateMinuteChart_app();  
            // #endif  
        },  

        //走势图多日切换  
        ChangeMinutePeriod:function(period)  
        {  
            this.Minute.IsShow=true;  
            this.KLine.IsShow=false;  
            if (!g_Minute.JSChart)   //不存在创建  
            {  
                this.Minute.Option.DayCount=period;  
                this.CreateMinuteChart();  
            }  
            else  
            {  
                g_Minute.JSChart.ChangeDayCount(period);  
            }  
        },  

        NetworkFilter:function(data, callback)  
        {  
            console.log(`[HQChart:NetworkFilter] Name=${data.Name} Explain=${data.Explain}` );  
        },  

        ///////////////////////////////////////////////  
        //手势事件 app/小程序才有  
        //KLine事件  
        KLineTouchStart: function (event)   
        {  
          if (g_KLine.JSChart) g_KLine.JSChart.OnTouchStart(event);  
        },  

        KLineTouchMove: function (event)   
        {  
          if (g_KLine.JSChart) g_KLine.JSChart.OnTouchMove(event);  
        },  

        KLineTouchEnd: function (event)   
        {  
          if (g_KLine.JSChart) g_KLine.JSChart.OnTouchEnd(event);  
        },  

        //走势图事件  
        MinuteTouchStart: function (event)   
        {  
          if (g_Minute.JSChart) g_Minute.JSChart.OnTouchStart(event);  
        },  

        MinuteTouchMove: function (event)   
        {  
          if (g_Minute.JSChart) g_Minute.JSChart.OnTouchMove(event);  
        },  

        MinuteTouchEnd: function (event)   
        {  
          if (g_Minute.JSChart) g_Minute.JSChart.OnTouchEnd(event);  
        },  
    }  
}  

</script>  

<style>  

</style>  

如果还有问题可以加交流QQ群: 950092318

HQChart代码地址
地址:github.com/jones2000/HQChart

继续阅读 »

今天在群里帮一位朋友排查HQChart同时在多端使用的问题。我整理了以下

背景

由于小程序/app很多局限性(无法创建DOM,canvas异步绘图等)导致HQChart开发的时候分成两个版本(小程序版本和H5页面版本)。
使用条件编译我们可以把这2个版本组件同时包含的工程中,并且通过平台判断动态加载对应版本的js.

安装插件

在工程里建2个目录,把HQChart的2个版本分别考入对应的目录里。
版本对应关系看以前的教程
HQChart使用教程35 - 如何在uni-app创建K线图(h5)
HQChart使用教程37 - 如何在uni-app创建k线图(app)
在这里插入图片描述

template 设置

由于小程序/app是无法动态创建dom,所有只能是先在模板里写死一个画布,在初始化的时候绑定到HQChart中。H5是可以直接内部创建dom,所以只需要传入一个div,HQChart自动会创建画布. 我们使用条件编译在不同的平台使用不同的模板
注意 id的名字尽量使用不一样的,如h5如果使用id='kline' 在app/小程序就使用id='kline2'

<!--  #ifdef  H5 -->  
<div>  
    <div class='kline' id="kline" ref='kline'  v-show="KLine.IsShow"></div>  
    <div class='minute' id="minute" ref='minute'  v-show="Minute.IsShow"></div>  
</div>  
<!--  #endif -->  

<!--  #ifndef  H5 -->  
<view>  
    <canvas id="kline2" canvas-id='kline2' class='kline2' v-bind:style="{width: ChartWidth+'px', height: ChartHeight+'px'}"  v-show="KLine.IsShow"  
      @touchstart="KLineTouchStart" @touchmove='KLineTouchMove' @touchend='KLineTouchEnd' ></canvas>    
      <canvas id="minute2" canvas-id='minute2' class='minute' v-bind:style="{width: ChartWidth+'px', height: ChartHeight+'px'}" v-show="Minute.IsShow"  
       @touchstart="MinuteTouchStart" @touchmove='MinuteTouchMove' @touchend='MinuteTouchEnd' ></canvas>  
</view>  
<!--  #endif -->

这样2个模板就同时存在一个页面中了

创建插件设置

为每个平台创建一个创建插件的函数,然后通过一个总的创建函数动态调用对应的创建方法
下面是也创建K线图为例子‘CreateKLineChart_h5()'是h5平台的创建插件方法, 'CreateKLineChart_app()'是app和小程序创建的方法,在"CreateKLineChart()'通过条件编译就可以动态选择使用对应的创建函数
为了代码的可读和可维护性我这边是拆分成2个创建函数,你也可以在CreateKLineChart里面把2个平台的创建都写里面,只过不这样可读性比较差。

CreateKLineChart()  
{  
    // #ifdef H5  
    this.CreateKLineChart_h5();  
    // #endif  

    // #ifndef H5  
    this.CreateKLineChart_app();  
    // #endif  
},

下面是2个平台对应的创建方法,走势图的创建也是一样

CreateKLineChart_h5()  //创建K线图  
{  
    if (g_KLine.JSChart) return;  
    this.KLine.Option.Symbol=this.Symbol;  
    let chart=HQChart.JSChart.Init(this.$refs.kline);  
this.KLine.Option.NetworkFilter=this.NetworkFilter;  
    chart.SetOption(this.KLine.Option);  
    g_KLine.JSChart=chart;  
},  

CreateKLineChart_app()  
{  
    if (this.KLine.JSChart) return;  

    let element = new JSCommon.JSCanvasElement();  
    // #ifdef APP-PLUS  
    element.IsUniApp=true;  //canvas需要指定下 是uniapp的app  
    // #endif  
    element.ID = 'kline2';  
    element.Height = this.ChartHeight;  //高度宽度需要手动绑定!!  
    element.Width = this.ChartWidth;  

    g_KLine.JSChart = JSCommon.JSChart.Init(element);  
    this.KLine.Option.NetworkFilter=this.NetworkFilter;  
    this.KLine.Option.Symbol=this.Symbol;  
    g_KLine.JSChart.SetOption(this.KLine.Option);  
},

HQChart大小调整

由于app/小程序无法获取dom,所以只能是在外部把画布的长宽设置到HQChart中(动态获取只能通过其他的查询元素函数获取,比较麻烦,关键还是异步的,非常搞不懂获取一个元素信息还使用异步,难道以目前的手机配置查询几千几万了dom信息不能在毫秒级处理完),
H5是可以动态获取dom,就不存在这个文件,改变了外层的div调用HQChart的OnSize()方法就可以动态把div的大小绑定画布上。

OnSize()  
{  
    // #ifdef H5  
    this.OnSize_h5();  
    // #endif  
},  

OnSize_h5()  
{  
    var chartHeight = this.ChartHeight;  
    var chartWidth = this.ChartWidth;  

    var kline=this.$refs.kline;  
    kline.style.width=chartWidth+'px';  
    kline.style.height=chartHeight+'px';  
    if (g_KLine.JSChart) g_KLine.JSChart.OnSize();  

    var minute=this.$refs.minute;  
    minute.style.width=chartWidth+'px';  
    minute.style.height=chartHeight+'px';  
    if (g_Minute.JSChart) g_Minute.JSChart.OnSize();  
},

这样多端支持就完成了。点运行,然后喝杯咖啡吧,编译调试真的很慢。

效果图

在这里插入图片描述
在这里插入图片描述

完整代码

<template>  
    <div class='divchart' >  
        <!--  #ifdef  H5 -->  
        <div>  
        <div class='kline' id="kline" ref='kline'  v-show="KLine.IsShow"></div>  
        <div class='minute' id="minute" ref='minute'  v-show="Minute.IsShow"></div>  
        </div>  
        <!--  #endif -->  

        <!--  #ifndef  H5 -->  
        <view>  
            <canvas id="kline2" canvas-id='kline2' class='kline2' v-bind:style="{width: ChartWidth+'px', height: ChartHeight+'px'}"  v-show="KLine.IsShow"  
              @touchstart="KLineTouchStart" @touchmove='KLineTouchMove' @touchend='KLineTouchEnd' ></canvas>    
              <canvas id="minute2" canvas-id='minute2' class='minute' v-bind:style="{width: ChartWidth+'px', height: ChartHeight+'px'}" v-show="Minute.IsShow"  
               @touchstart="MinuteTouchStart" @touchmove='MinuteTouchMove' @touchend='MinuteTouchEnd' ></canvas>  
        </view>  
        <!--  #endif -->  

        <div class="button-sp-area">  
            <button class="mini-btn" type="default" size="mini" @click="ChangeMinutePeriod(MINUTE_PERIOD_ID.MINUTE_ID)">分时</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeMinutePeriod(MINUTE_PERIOD_ID.MINUTE_5DAY_ID)">5日</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(KLINE_PERIOD_ID.KLINE_DAY_ID)">日线</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(KLINE_PERIOD_ID.KLINE_WEEK_ID)">周线</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(KLINE_PERIOD_ID.KLINE_MINUTE_ID)">1分钟</button>  
            <button class="mini-btn" type="default" size="mini" @click="ChangeKLinePeriod(KLINE_PERIOD_ID.KLINE_15MINUTE_ID)">15分钟</button>  
        </div>  

    </div>  
</template>  

<script>  
// #ifdef H5      
import HQChart from '../../umychart_uniapp_h5/umychart.uniapp.h5.js'  
// #endif  

// #ifndef H5  
import {JSCommon} from '../../umychart.uniapp/umychart.wechat.3.0.js'  
// #endif  

function DefaultData() { }  

DefaultData.GetKLineOption = function ()   
{  
    let data =   
    {  
        Type: '历史K线图',   

        Windows: //窗口指标  
        [  
            {Index:"MA",Modify: false, Change: false},   
            {Index:"VOL",Modify: false, Change: false}  
        ],   

        IsCorssOnlyDrawKLine:true,  
        CorssCursorTouchEnd:true,  

        Border: //边框  
        {  
            Left:   1,  
            Right:  1, //右边间距  
            Top:    25,  
            Bottom: 25,  
        },  

        KLine:  
        {  
            Right:1,                            //复权 0 不复权 1 前复权 2 后复权  
            Period:0,                           //周期: 0 日线 1 周线 2 月线 3 年线   
            PageSize:30,  
            IsShowTooltip:false  
        },  

        ExtendChart:  
        [  
            {Name:'KLineTooltip' }, //开启手机端tooltip  
        ],   

        Frame:  //子框架设置  
        [  
            {SplitCount:3},  
            {SplitCount:2},  
            {SplitCount:3},  
        ],  

    };  

    return data;  
}  

DefaultData.GetMinuteOption=function()  
{  
    var option=   
    {  
        Type:'分钟走势图',   //创建图形类型  

        Windows: //窗口指标  
        [  

        ],   

        IsAutoUpdate:true,       //是自动更新数据  
        DayCount:1,                 //1 最新交易日数据 >1 多日走势图  
        IsShowRightMenu:false,       //是否显示右键菜单  
        CorssCursorTouchEnd:true,  

        MinuteLine:  
        {  
            //IsDrawAreaPrice:false,      //是否画价格面积图  
        },  

        Border: //边框  
        {  
            Left:1,    //左边间距  
            Right:1,   //右边间距  
            Top:20,  
            Bottom:20  
        },  

        Frame:  //子框架设置  
        [  
            {SplitCount:3},  
            {SplitCount:2},  
            {SplitCount:3},  
        ],  

        ExtendChart:    //扩展图形  
        [  
            {Name:'MinuteTooltip' }  //手机端tooltip  
        ],  
    };  

    return option;  
}  

//周期枚举  
var KLINE_PERIOD_ID=  
{  
    KLINE_DAY_ID:0,  
    KLINE_WEEK_ID:1,  
    KLINE_MONTH_ID:2,  
    KLINE_YEAR_ID:3,  

    KLINE_MINUTE_ID:4,  
    KLINE_5MINUTE_ID:5,  
    KLINE_15MINUTE_ID:6,  
    KLINE_30MINUTE_ID:7,  
    KLINE_60MINUTE_ID:8  
}  

//周期枚举  
var MINUTE_PERIOD_ID=  
{  
    MINUTE_ID:1,  
    MINUTE_2DAY_ID:2,  
    MINUTE_3DAY_ID:3,  
    MINUTE_4DAY_ID:4,  
    MINUTE_5DAY_ID:5,  
}  

var g_KLine={ JSChart:null };  
var g_Minute={ JSChart:null };  
export default   
{  
    data()   
    {  
        let data=  
        {  
            Symbol:'600000.sh',  
            ChartWidth:300,  
            ChartHeight:500,  
            KLine:  
            {  

                Option:DefaultData.GetKLineOption(),   
                IsShow:true,  
            },  
            Minute:  
            {  

                Option:DefaultData.GetMinuteOption(),  
                IsShow:false,  
            },  

            MINUTE_PERIOD_ID:MINUTE_PERIOD_ID,  
            KLINE_PERIOD_ID:KLINE_PERIOD_ID,  
        };  

        return data;  
    },  

    onLoad()   
    {  

    },  

    onReady()  
    {  
        this.OnSize();  
        this.CreateKLineChart();   
    },  

    methods:   
    {  
        OnSize()  
        {  
            // #ifdef H5  
            this.OnSize_h5();  
            // #endif  
        },  

        OnSize_h5()  
        {  
            var chartHeight = this.ChartHeight;  
            var chartWidth = this.ChartWidth;  

            var kline=this.$refs.kline;  
            kline.style.width=chartWidth+'px';  
            kline.style.height=chartHeight+'px';  
            if (g_KLine.JSChart) g_KLine.JSChart.OnSize();  

            var minute=this.$refs.minute;  
            minute.style.width=chartWidth+'px';  
            minute.style.height=chartHeight+'px';  
            if (g_Minute.JSChart) g_Minute.JSChart.OnSize();  
        },  

        CreateKLineChart_h5()  //创建K线图  
        {  
            if (g_KLine.JSChart) return;  
            this.KLine.Option.Symbol=this.Symbol;  
            let chart=HQChart.JSChart.Init(this.$refs.kline);  
            this.KLine.Option.NetworkFilter=this.NetworkFilter;  
            chart.SetOption(this.KLine.Option);  
            g_KLine.JSChart=chart;  
        },  

        CreateKLineChart_app()  
        {  
            if (this.KLine.JSChart) return;  

            let element = new JSCommon.JSCanvasElement();  
            // #ifdef APP-PLUS  
            element.IsUniApp=true;  //canvas需要指定下 是uniapp的app  
            // #endif  
            element.ID = 'kline2';  
            element.Height = this.ChartHeight;  //高度宽度需要手动绑定!!  
            element.Width = this.ChartWidth;  

            g_KLine.JSChart = JSCommon.JSChart.Init(element);  
            this.KLine.Option.NetworkFilter=this.NetworkFilter;  
            this.KLine.Option.Symbol=this.Symbol;  
            g_KLine.JSChart.SetOption(this.KLine.Option);  
        },  

        CreateKLineChart()  
        {  
            // #ifdef H5  
            this.CreateKLineChart_h5();  
            // #endif  

            // #ifndef H5  
            this.CreateKLineChart_app();  
            // #endif  
        },  

        //K线周期切换  
        ChangeKLinePeriod:function(period)  
        {  
            this.Minute.IsShow=false;  
            this.KLine.IsShow=true;  
            if (!g_KLine.JSChart)    //不存在创建  
            {  
                this.KLine.Option.Period=period;  
                this.CreateKLineChart_h5();  
            }  
            else  
            {  
                g_KLine.JSChart.ChangePeriod(period);  
            }  
        },  

        CreateMinuteChart_h5() //创建日线图  
        {  
            if (g_Minute.JSChart) return;  
            this.Minute.Option.Symbol=this.Symbol;  
            let chart=HQChart.JSChart.Init(this.$refs.minute);  
            this.Minute.Option.NetworkFilter=this.NetworkFilter;  
            chart.SetOption(this.Minute.Option);  
            g_Minute.JSChart=chart;  
        },  

        CreateMinuteChart_app()  
        {  
            if (g_Minute.JSChart) return;  

            var element = new JSCommon.JSCanvasElement();  
            // #ifdef APP-PLUS  
            element.IsUniApp=true;  //canvas需要指定下 是uniapp的app  
            // #endif  
            element.ID = 'minute2';  
            element.Height = this.ChartHeight;  //高度宽度需要手动绑定!!  
            element.Width = this.ChartWidth;  

            g_Minute.JSChart = JSCommon.JSChart.Init(element);  
            this.Minute.Option.NetworkFilter=this.NetworkFilter;  
            this.Minute.Option.Symbol=this.Symbol;  
            g_Minute.JSChart.SetOption(this.Minute.Option);  
        },  

        CreateMinuteChart()  
        {  
            // #ifdef H5  
            this.CreateMinuteChart_h5();  
            // #endif  

            // #ifndef H5  
            this.CreateMinuteChart_app();  
            // #endif  
        },  

        //走势图多日切换  
        ChangeMinutePeriod:function(period)  
        {  
            this.Minute.IsShow=true;  
            this.KLine.IsShow=false;  
            if (!g_Minute.JSChart)   //不存在创建  
            {  
                this.Minute.Option.DayCount=period;  
                this.CreateMinuteChart();  
            }  
            else  
            {  
                g_Minute.JSChart.ChangeDayCount(period);  
            }  
        },  

        NetworkFilter:function(data, callback)  
        {  
            console.log(`[HQChart:NetworkFilter] Name=${data.Name} Explain=${data.Explain}` );  
        },  

        ///////////////////////////////////////////////  
        //手势事件 app/小程序才有  
        //KLine事件  
        KLineTouchStart: function (event)   
        {  
          if (g_KLine.JSChart) g_KLine.JSChart.OnTouchStart(event);  
        },  

        KLineTouchMove: function (event)   
        {  
          if (g_KLine.JSChart) g_KLine.JSChart.OnTouchMove(event);  
        },  

        KLineTouchEnd: function (event)   
        {  
          if (g_KLine.JSChart) g_KLine.JSChart.OnTouchEnd(event);  
        },  

        //走势图事件  
        MinuteTouchStart: function (event)   
        {  
          if (g_Minute.JSChart) g_Minute.JSChart.OnTouchStart(event);  
        },  

        MinuteTouchMove: function (event)   
        {  
          if (g_Minute.JSChart) g_Minute.JSChart.OnTouchMove(event);  
        },  

        MinuteTouchEnd: function (event)   
        {  
          if (g_Minute.JSChart) g_Minute.JSChart.OnTouchEnd(event);  
        },  
    }  
}  

</script>  

<style>  

</style>  

如果还有问题可以加交流QQ群: 950092318

HQChart代码地址
地址:github.com/jones2000/HQChart

收起阅读 »