
uniapp 在H5APP内长按图片保存到系统相册
原文链接:https://www.hebaocun.com/blog/97.html
var bitmap = new plus.nativeObj.Bitmap();
// 加载海报图片
bitmap.loadBase64Data(_this.poster, function() {
//保存到系统相册
bitmap.save("doc/poster"+_this.coupon.item_id+".jpg", {
overwrite: true, //是否覆盖已有图片, true 是
quality: 100 //图片质量,1-100 默认50, 100质量最高
}, function(e) {
//重点就是这里, 需要将bitmap保存的临时路径再使用saveImageToPhotosAlbum进行保存
uni.saveImageToPhotosAlbum({
filePath: e.target,
success: function () {
uni.showToast({
title: "图片保存成功",
icon: "none"
});
}
});
}, function(e) {
uni.showToast({
title: "图片保存失败",
icon: "none"
});
});
}, function(e) {
uni.showToast({
title: "图片保存失败",
icon: "none"
});
});
原文链接:https://www.hebaocun.com/blog/97.html
var bitmap = new plus.nativeObj.Bitmap();
// 加载海报图片
bitmap.loadBase64Data(_this.poster, function() {
//保存到系统相册
bitmap.save("doc/poster"+_this.coupon.item_id+".jpg", {
overwrite: true, //是否覆盖已有图片, true 是
quality: 100 //图片质量,1-100 默认50, 100质量最高
}, function(e) {
//重点就是这里, 需要将bitmap保存的临时路径再使用saveImageToPhotosAlbum进行保存
uni.saveImageToPhotosAlbum({
filePath: e.target,
success: function () {
uni.showToast({
title: "图片保存成功",
icon: "none"
});
}
});
}, function(e) {
uni.showToast({
title: "图片保存失败",
icon: "none"
});
});
}, function(e) {
uni.showToast({
title: "图片保存失败",
icon: "none"
});
});

对uniapp的吐槽
举例:
一、原生样式的问题
就拿radio来说吧 内置的样式改不了 最后我用view模拟圆框 在里面套了个对勾来实现的
还有其他各种原生组件内置样式 有些能改 有些不能改 能改也麻烦 为什么不跟前端页面似的 让用户自己选择引不引用uniapp的样式?
二、原生DOM的问题
平时最烦的就是小程序 不允许用DOM有多不方便 知道吗(直接操作DOM的速度并不慢 说直接操作DOM慢的都是菜)
现在学小程序 不允许用DOM 还不如以前开发速度快
现在的时间都耽误在各种修改样式上
三、各种意外BUG
比如我封装了一个组件 给它一个方法当做props属性 然后在组件里调用这个方法 在H5端一切正常 在APP就不行 报错
吐完槽,说一下优点,就是文档比以前好了,这是唯一的优点。
希望贵司能相信用户,把控制权都放开,比如原生样式这个,能让用户自由选择用不用。
DOM就不指望了,唉 愁
举例:
一、原生样式的问题
就拿radio来说吧 内置的样式改不了 最后我用view模拟圆框 在里面套了个对勾来实现的
还有其他各种原生组件内置样式 有些能改 有些不能改 能改也麻烦 为什么不跟前端页面似的 让用户自己选择引不引用uniapp的样式?
二、原生DOM的问题
平时最烦的就是小程序 不允许用DOM有多不方便 知道吗(直接操作DOM的速度并不慢 说直接操作DOM慢的都是菜)
现在学小程序 不允许用DOM 还不如以前开发速度快
现在的时间都耽误在各种修改样式上
三、各种意外BUG
比如我封装了一个组件 给它一个方法当做props属性 然后在组件里调用这个方法 在H5端一切正常 在APP就不行 报错
吐完槽,说一下优点,就是文档比以前好了,这是唯一的优点。
希望贵司能相信用户,把控制权都放开,比如原生样式这个,能让用户自由选择用不用。
DOM就不指望了,唉 愁

关于微信登陆获取code的方式。抄代码就可以了。
//全局申请一个:var auths=null;
// #ifdef APP-PLUS
plus.oauth.getServices(function(servies){
auths = servies;
var s = auths[0];
if( !s.authResult ){
s.authorize(function(e){
console.log('获取code!' + JSON.stringify(e));
uni.showModal({ title: '用户信息',content: e.code,});
}, function(e){
console.log('登陆认证失败!');
uni.showModal({ title: '认证失败1',content: JSON.stringify(e),});
}, {scope:'snsapi_userinfo',state:'123'});
}else{
console.log('已经登陆认证');
}
}, function(e){console.log("获取服务列表失败:"+JSON.stringify(e));})
// #endif
如果会返回错误的话。建议以下:
第一,appid一定要对。是开放平台那里取,如果您自己是后台管理员就没有关系。如果您是从客户那里或是别的管理员,那就要非常注意了。我为了这个问题坑了几天。死活不成功,但是我自己亲自向微信公众平台申请了一个应用,一次成功。说明给的appid根本就是不正确的。
第二,签名一定要正确。应用在手机上安装后,用微信的工具去获取一般这步可能不会错。
第三,包名。一定不能出错。基本上这三步Ok。就能顺利进行授权。
//全局申请一个:var auths=null;
// #ifdef APP-PLUS
plus.oauth.getServices(function(servies){
auths = servies;
var s = auths[0];
if( !s.authResult ){
s.authorize(function(e){
console.log('获取code!' + JSON.stringify(e));
uni.showModal({ title: '用户信息',content: e.code,});
}, function(e){
console.log('登陆认证失败!');
uni.showModal({ title: '认证失败1',content: JSON.stringify(e),});
}, {scope:'snsapi_userinfo',state:'123'});
}else{
console.log('已经登陆认证');
}
}, function(e){console.log("获取服务列表失败:"+JSON.stringify(e));})
// #endif
如果会返回错误的话。建议以下:
第一,appid一定要对。是开放平台那里取,如果您自己是后台管理员就没有关系。如果您是从客户那里或是别的管理员,那就要非常注意了。我为了这个问题坑了几天。死活不成功,但是我自己亲自向微信公众平台申请了一个应用,一次成功。说明给的appid根本就是不正确的。
第二,签名一定要正确。应用在手机上安装后,用微信的工具去获取一般这步可能不会错。
第三,包名。一定不能出错。基本上这三步Ok。就能顺利进行授权。
收起阅读 »
uni-app自定义组件模式开发注意事项
uni-app 自 1.8版本开始,新增支持自定义组件模式
,该编译模式组件性能更高,支持更多的Vue语法。
请开发者尽快升级老版项目为自定义组件模式,老版的模板编译模式将不再维护。
Tips: uni-app 不同编译模式差异,参考:https://ask.dcloud.net.cn/article/35843
开发者启用自定义组件模式
后,在进行自定义组件开发(页面开发不影响)时,需注意如下约束
id
为保留属性名,不能作为 props 传递,微信小程序自定义组件限制props
中不能定义data
为属性名,百度小程序限制props
不支持date
类型数据传递,微信小程序自定义组件限制uni.createSelectorQuery()
和uni.createIntersectionObserver()
的调整
// 错误
uni.createSelectorQuery();
uni.createIntersectionObserver();
// 正确
uni.createSelectorQuery().in(this);
uni.createIntersectionObserver(this, options);
uni.createCanvasContext()
的调整
// 错误
uni.createCanvasContext();
// 正确
uni.createCanvasContext('#canvas',this);
Array.length
改为计算属性
// 错误
<view v-if="{Array.length >= 0}"></view>
// 正确
<view v-if="{count}" ></view>
computed: {
count() {
return (Array.length >= 0)
}
}
-
uParse
富文本解析组件的调整
优化了uParse 组件
的性能,如老项目有使用,请直接替换最新组件,使用方式不变:https://ext.dcloud.net.cn/plugin?id=183
其实插件市场有更多三方增强的uparser组件可用,可以搜一下。 -
ECharts
图表组件的调整
替换最新的ucharts
组件, 源码地址:https://ext.dcloud.net.cn/plugin?id=271
使用方式参考 :http://doc.ucharts.cn/1074673
其实插件市场有更多优秀的三方增强的图表组件可用,可以搜一下。 -
css
调整
在编译成微信小程序原生组件的时候,会在组件外增加一层父节点。有可能样式会受到影响,比较典型的就是 flex 布局,请在微信端完成一遍测试。
在字节跳动小程序组件内引入字体会失效,解决方式:在 App.vue 内的 style 节点引入字体。 -
组件内
css
选择器使用
在微信小程序真机运行时,组件内如果使用了 tagName, ID, attribute 三种选择器时,会导致控制台出现告警信息。 所以我们在编写组件时,需要尽量避免使用上述三种选择器。 -
组件生命周期
编译成原生组件的时候,组件的生命周期请严格参考 组件生命周期 中的说明。
需要注意的是,组件不支持 onLoad 等页面的生命周期。 -
仅支持解构插槽
Prop
(支持设置默认值,但不提供重命名)
<!—不支持—>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
<!—支持—>
<template v-slot:default="{user}">
{{ user.firstName }}
</template>
- 组件中引用图片等静态资源时,一定要使用绝对路径,即
/static/logo.png
这样。其实,无论是页面还是组件,引用静态资源时统一采用绝对路径的方式是最优方案。
App额外注意事项
- App使用自定义组件模式,Android会增加6M左右的包体积。原因是App端增加了一个独立的v8以减少js的阻塞。iOS不变化,因为iOS的jscore是iOS自带的。
- 离线打包的项目需要在原生工程里引入 :离线sdk包里的liblibWeex.a库 和 weex-main-jsfm.js 和 weex-polyfill.js文件。
- 在自定义组件编译模式下,HBuilderX 2.4.0+ 支持 crypto.getRandomValues 方法,一些区块链应用的框架会用到此api
- 在自定义组件编译模式下,uni.request 和 websocket 暂时不支持传输 ArrayBuffer 类型的数据,且 websocket 只能创建一个连接,有需求的用户可改用老的模板编译模式。
uni-app 自 1.8版本开始,新增支持自定义组件模式
,该编译模式组件性能更高,支持更多的Vue语法。
请开发者尽快升级老版项目为自定义组件模式,老版的模板编译模式将不再维护。
Tips: uni-app 不同编译模式差异,参考:https://ask.dcloud.net.cn/article/35843
开发者启用自定义组件模式
后,在进行自定义组件开发(页面开发不影响)时,需注意如下约束
id
为保留属性名,不能作为 props 传递,微信小程序自定义组件限制props
中不能定义data
为属性名,百度小程序限制props
不支持date
类型数据传递,微信小程序自定义组件限制uni.createSelectorQuery()
和uni.createIntersectionObserver()
的调整
// 错误
uni.createSelectorQuery();
uni.createIntersectionObserver();
// 正确
uni.createSelectorQuery().in(this);
uni.createIntersectionObserver(this, options);
uni.createCanvasContext()
的调整
// 错误
uni.createCanvasContext();
// 正确
uni.createCanvasContext('#canvas',this);
Array.length
改为计算属性
// 错误
<view v-if="{Array.length >= 0}"></view>
// 正确
<view v-if="{count}" ></view>
computed: {
count() {
return (Array.length >= 0)
}
}
-
uParse
富文本解析组件的调整
优化了uParse 组件
的性能,如老项目有使用,请直接替换最新组件,使用方式不变:https://ext.dcloud.net.cn/plugin?id=183
其实插件市场有更多三方增强的uparser组件可用,可以搜一下。 -
ECharts
图表组件的调整
替换最新的ucharts
组件, 源码地址:https://ext.dcloud.net.cn/plugin?id=271
使用方式参考 :http://doc.ucharts.cn/1074673
其实插件市场有更多优秀的三方增强的图表组件可用,可以搜一下。 -
css
调整
在编译成微信小程序原生组件的时候,会在组件外增加一层父节点。有可能样式会受到影响,比较典型的就是 flex 布局,请在微信端完成一遍测试。
在字节跳动小程序组件内引入字体会失效,解决方式:在 App.vue 内的 style 节点引入字体。 -
组件内
css
选择器使用
在微信小程序真机运行时,组件内如果使用了 tagName, ID, attribute 三种选择器时,会导致控制台出现告警信息。 所以我们在编写组件时,需要尽量避免使用上述三种选择器。 -
组件生命周期
编译成原生组件的时候,组件的生命周期请严格参考 组件生命周期 中的说明。
需要注意的是,组件不支持 onLoad 等页面的生命周期。 -
仅支持解构插槽
Prop
(支持设置默认值,但不提供重命名)
<!—不支持—>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
<!—支持—>
<template v-slot:default="{user}">
{{ user.firstName }}
</template>
- 组件中引用图片等静态资源时,一定要使用绝对路径,即
/static/logo.png
这样。其实,无论是页面还是组件,引用静态资源时统一采用绝对路径的方式是最优方案。
App额外注意事项
- App使用自定义组件模式,Android会增加6M左右的包体积。原因是App端增加了一个独立的v8以减少js的阻塞。iOS不变化,因为iOS的jscore是iOS自带的。
- 离线打包的项目需要在原生工程里引入 :离线sdk包里的liblibWeex.a库 和 weex-main-jsfm.js 和 weex-polyfill.js文件。
- 在自定义组件编译模式下,HBuilderX 2.4.0+ 支持 crypto.getRandomValues 方法,一些区块链应用的框架会用到此api
- 在自定义组件编译模式下,uni.request 和 websocket 暂时不支持传输 ArrayBuffer 类型的数据,且 websocket 只能创建一个连接,有需求的用户可改用老的模板编译模式。

React Native基础+进阶+高级+实战视频教程
分享一套React Native基础+进阶+高级+实战视频教程,React Native零基础到入门实战,IOS+安卓移动应用开发,贯穿全栈React Native开发App 实战教程,比较全的React Native教学课程
教程目录列表:
教程下载:https://www.sucaihuo.com/video/398.html
分享一套React Native基础+进阶+高级+实战视频教程,React Native零基础到入门实战,IOS+安卓移动应用开发,贯穿全栈React Native开发App 实战教程,比较全的React Native教学课程
教程目录列表:
教程下载:https://www.sucaihuo.com/video/398.html

数据可视化之下发图实践
作者:个推前端工程师 东风
随着互联网的快速发展,数据维度越来越广,呈现形式也越发丰富,具有多维度数据特点的相关业务实践都能通过可视化图表来展示,比如个推的下发图,从时间和区域两个维度,可以即时、直观地展现个推数据下发的过程。
一、下发图的由来
个推下发图主要用于呈现个推为APP提供推送服务时数据的下发过程,可以直观显示个推推送触达到的城市,有利于开发者对下发数据进行分析。
个推下发图运用了迁徙图的原理,再通过自主设计开发出的一套可视化展示图像。这一类型的可视化可以广泛应用于拥有地理位置信息和数据转移特征的数据展示。
二、下发图的构成
下发图主要由地图、地理位置信息,以及飞线组成。如下图所示:

三、下发图的技术要点
1.地图
地图可以利用第三方地图服务,也可以自主绘制地图,本文以后者为例。自主绘制的地图主要利用了墨卡托投影原理,将地球正轴圆柱投影,由经纬度信息转化到画布上对应的位置。
本文案例中用了 d3.js 中的 geoMercator 进行墨卡托投影转换。
然后我们可以在阿里云的 datav 中获取地图的 geojson 数据,具体地址可参见括号内链接,(https://datav.aliyun.com/tools/atlas )再通过 canvas 原生 Api,添加背景色、边框等,就可以画出想要的地图了。
注意:下图中的地图角度透视主要应用了 css 中的 transform,perspective、rotateX、rotateY、rotateZ 等。
遵循上述步骤,一个透视角度的静态地图就绘制完成了。
2.贝塞尔曲线
贝塞尔曲线是计算机图形学中相当重要的参数曲线,它通过一个方程来描述一条曲线,根据方程的最高阶数,又分为线性贝塞尔曲线、二次贝塞尔曲线、三次贝塞尔曲线和更高阶的贝塞尔曲线。
本案例中主要应用了二次贝塞尔曲线,二次贝塞尔曲线的函数如下:
B(t) = (1-t) ²P0 + 2t(1-t)P1 + t²P2, t ∈ [0,1]
上图为本文案例中飞线的贝塞尔曲线应用,其中 from 为起点,to 为终点,curveness 为曲线的曲率,取值-1 ~ 1,曲率的绝对值越大,曲线越弯曲,percent为飞线位置占比。
3.动画
在 canvas 中,动画效果的实现通常是由 window.requestAnimationFrame 循环执行,因此,飞线需要算出每一帧中飞线的状态,以及飞线的入场和离场形态。
4.发光效果
那么下发图的特效具体如何实现呢?首先我们来介绍一下头部发光效果的实现过程:
我们以工业中的HSL色彩模式为颜色标准,通过对色相(H)、饱和度(S)、明度(L)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色,HSL即代表色相、饱和度、明度三个通道的颜色,这一标准几乎包括了人类视力所能感知的所有颜色。以此为依据,可以发现光源的发光规律,即光源中心的明亮度最高,由内向外,明亮度依次递减。
所以根据配置的基础颜色,就能获取到顶点发光处颜色的明亮度,大致方法如下:
完成头部发光步骤后,接下来需要打造一个酷炫的形状。发光的头部是一个类似棉签棒的形状,该形状可以用一个半圆和一个三角形来绘制,再根据曲线的切线,获取三角形以及半圆的旋转角度。
完成下发图头部制作后,接下来需要进行尾部的操作,因为canvas自带线性渐变,所以具体代码如下:
canvas 的落地效果呈圆形渐变样式,当飞线到达终点后,完整的落地效果就开始展示,整个画面类似雨滴降落到地面。
5.透视
如果不调整透视角度,贝塞尔曲线的样式如下图所示:
当曲线与下发方向的角度呈90度时,曲率最大;角度为0度或者180度时,曲率最小,与余弦定律相似。
其中 from 是起始位置,to 是终止位置,curveness 是曲线的曲率,angel 是视线的角度。
最终效果如下:
四、技术选型
在进行下发图的技术选型时,个推技术团队对比了 svg 和 canvas 两种技术栈,最后选择了 canvas,然后配合 requestAnimationFrame 画出下发轨迹的帧动画。两款技术栈的具体性能对比如下:
五、总结
随着数据维度的扩展和丰富,数据可视化的形态日渐丰富。作为地理位置信息和数据转移特征的数据可视化图表,下发图可以更直观地展现个推为APP提供推送服务时的下发量、下发区域等数据,对APP的行业分析以及战略调整有着指导性意义。
作者:个推前端工程师 东风
随着互联网的快速发展,数据维度越来越广,呈现形式也越发丰富,具有多维度数据特点的相关业务实践都能通过可视化图表来展示,比如个推的下发图,从时间和区域两个维度,可以即时、直观地展现个推数据下发的过程。
一、下发图的由来
个推下发图主要用于呈现个推为APP提供推送服务时数据的下发过程,可以直观显示个推推送触达到的城市,有利于开发者对下发数据进行分析。
个推下发图运用了迁徙图的原理,再通过自主设计开发出的一套可视化展示图像。这一类型的可视化可以广泛应用于拥有地理位置信息和数据转移特征的数据展示。
二、下发图的构成
下发图主要由地图、地理位置信息,以及飞线组成。如下图所示:
三、下发图的技术要点
1.地图
地图可以利用第三方地图服务,也可以自主绘制地图,本文以后者为例。自主绘制的地图主要利用了墨卡托投影原理,将地球正轴圆柱投影,由经纬度信息转化到画布上对应的位置。
本文案例中用了 d3.js 中的 geoMercator 进行墨卡托投影转换。
然后我们可以在阿里云的 datav 中获取地图的 geojson 数据,具体地址可参见括号内链接,(https://datav.aliyun.com/tools/atlas )再通过 canvas 原生 Api,添加背景色、边框等,就可以画出想要的地图了。
注意:下图中的地图角度透视主要应用了 css 中的 transform,perspective、rotateX、rotateY、rotateZ 等。
遵循上述步骤,一个透视角度的静态地图就绘制完成了。
2.贝塞尔曲线
贝塞尔曲线是计算机图形学中相当重要的参数曲线,它通过一个方程来描述一条曲线,根据方程的最高阶数,又分为线性贝塞尔曲线、二次贝塞尔曲线、三次贝塞尔曲线和更高阶的贝塞尔曲线。
本案例中主要应用了二次贝塞尔曲线,二次贝塞尔曲线的函数如下:
B(t) = (1-t) ²P0 + 2t(1-t)P1 + t²P2, t ∈ [0,1]
上图为本文案例中飞线的贝塞尔曲线应用,其中 from 为起点,to 为终点,curveness 为曲线的曲率,取值-1 ~ 1,曲率的绝对值越大,曲线越弯曲,percent为飞线位置占比。
3.动画
在 canvas 中,动画效果的实现通常是由 window.requestAnimationFrame 循环执行,因此,飞线需要算出每一帧中飞线的状态,以及飞线的入场和离场形态。
4.发光效果
那么下发图的特效具体如何实现呢?首先我们来介绍一下头部发光效果的实现过程:
我们以工业中的HSL色彩模式为颜色标准,通过对色相(H)、饱和度(S)、明度(L)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色,HSL即代表色相、饱和度、明度三个通道的颜色,这一标准几乎包括了人类视力所能感知的所有颜色。以此为依据,可以发现光源的发光规律,即光源中心的明亮度最高,由内向外,明亮度依次递减。
所以根据配置的基础颜色,就能获取到顶点发光处颜色的明亮度,大致方法如下:
完成头部发光步骤后,接下来需要打造一个酷炫的形状。发光的头部是一个类似棉签棒的形状,该形状可以用一个半圆和一个三角形来绘制,再根据曲线的切线,获取三角形以及半圆的旋转角度。
完成下发图头部制作后,接下来需要进行尾部的操作,因为canvas自带线性渐变,所以具体代码如下:
canvas 的落地效果呈圆形渐变样式,当飞线到达终点后,完整的落地效果就开始展示,整个画面类似雨滴降落到地面。
5.透视
如果不调整透视角度,贝塞尔曲线的样式如下图所示:
当曲线与下发方向的角度呈90度时,曲率最大;角度为0度或者180度时,曲率最小,与余弦定律相似。
其中 from 是起始位置,to 是终止位置,curveness 是曲线的曲率,angel 是视线的角度。
最终效果如下:
四、技术选型
在进行下发图的技术选型时,个推技术团队对比了 svg 和 canvas 两种技术栈,最后选择了 canvas,然后配合 requestAnimationFrame 画出下发轨迹的帧动画。两款技术栈的具体性能对比如下:
五、总结
随着数据维度的扩展和丰富,数据可视化的形态日渐丰富。作为地理位置信息和数据转移特征的数据可视化图表,下发图可以更直观地展现个推为APP提供推送服务时的下发量、下发区域等数据,对APP的行业分析以及战略调整有着指导性意义。

最大资源网列表及剧集数据采集
【
zuidazy_list(page){
var pattern = new RegExp('-' + "(.?)" + '.html' +"."+ '_blank">' + "(.?)" + '</a' +"."+ '<span class="xing_vb5">' + "(.?)" + '</span>' +"."+ '<span class="xing_vb(6|7)">' + "(.?)" + '</span>',"g");
let data=[];
uni.request({
method:"GET",
url:'http://zuidazy.net/?m='+page+'.html',
success: (result) => {
if(result.statusCode==200){
// var data = result.data.match(/\/>(.)\$(.*)<\/li>/g)
while (pattern.exec(result.data) != null){
data.push({"id":RegExp.$1,
"title":RegExp.$2,
"type":RegExp.$3,
"times":RegExp.$5});
this.zuidazy_info(RegExp.$1)
// result.push(RegExp.$1);
}
}
},
fail: (e) => {
console.log(JSON.stringify(e))
}
});
console.log(data)
},
zuidazy_info(id){
let d1=[];
let d2=[];
let d3=[];
uni.request({
method:"GET",
url:'http://zuidazy.net/?m='+id+'.html',
success: (result) => {
if(result.statusCode==200){
var data = result.data.match(/\/>(.*)\$(.*)<\/li>/g)
for(var i=0;i<data.length;i++){
if(data[i].indexOf('.m3u8')>-1){
d1.push(this.getdata(data[i]))
}else if(data[i].indexOf('.mp4')>-1){
d2.push(this.getdata(data[i]))
}else{
d3.push(this.getdata(data[i]))
}
}
}
},
fail: (e) => {
console.log(JSON.stringify(e))
}
});
console.log([d1,d2,d3])
},
】
【
zuidazy_list(page){
var pattern = new RegExp('-' + "(.?)" + '.html' +"."+ '_blank">' + "(.?)" + '</a' +"."+ '<span class="xing_vb5">' + "(.?)" + '</span>' +"."+ '<span class="xing_vb(6|7)">' + "(.?)" + '</span>',"g");
let data=[];
uni.request({
method:"GET",
url:'http://zuidazy.net/?m='+page+'.html',
success: (result) => {
if(result.statusCode==200){
// var data = result.data.match(/\/>(.)\$(.*)<\/li>/g)
while (pattern.exec(result.data) != null){
data.push({"id":RegExp.$1,
"title":RegExp.$2,
"type":RegExp.$3,
"times":RegExp.$5});
this.zuidazy_info(RegExp.$1)
// result.push(RegExp.$1);
}
}
},
fail: (e) => {
console.log(JSON.stringify(e))
}
});
console.log(data)
},
zuidazy_info(id){
let d1=[];
let d2=[];
let d3=[];
uni.request({
method:"GET",
url:'http://zuidazy.net/?m='+id+'.html',
success: (result) => {
if(result.statusCode==200){
var data = result.data.match(/\/>(.*)\$(.*)<\/li>/g)
for(var i=0;i<data.length;i++){
if(data[i].indexOf('.m3u8')>-1){
d1.push(this.getdata(data[i]))
}else if(data[i].indexOf('.mp4')>-1){
d2.push(this.getdata(data[i]))
}else{
d3.push(this.getdata(data[i]))
}
}
}
},
fail: (e) => {
console.log(JSON.stringify(e))
}
});
console.log([d1,d2,d3])
},
】
收起阅读 »
蓝牙小票打印机 代码片段分享
var main = plus.android.runtimeMainActivity()
var BluetoothAdapter = plus.android.importClass(
'android.bluetooth.BluetoothAdapter'
)
var IntentFilter = plus.android.importClass('android.content.IntentFilter')
var BluetoothDevice = plus.android.importClass(
'android.bluetooth.BluetoothDevice'
)
var BAdapter = new BluetoothAdapter.getDefaultAdapter()
BAdapter.isEnabled()
BAdapter.enable()
plus.bluetooth.openBluetoothAdapter({
success: function(e) {
console.log('open success: ' + JSON.stringify(e))
plus.bluetooth.startBluetoothDevicesDiscovery({
success: function(e) {
console.log('start discovery success: ' + JSON.stringify(e))
},
fail: function(e) {
console.log('start discovery failed: ' + JSON.stringify(e))
}
})
},
fail: function(e) {
console.log('open failed: ' + JSON.stringify(e))
}
})
plus.bluetooth.getBluetoothDevices({
success: function(e) {
var devices = e.devices
console.log('get devices success: ' + e.length)
for (var i in devices) {
console.log(i + ': ' + JSON.stringify(devices[i]))
}
},
fail: function(e) {
console.log('get devices failed: ' + JSON.stringify(e))
}
})
plus.bluetooth.stopBluetoothDevicesDiscovery({
success: function(e) {
console.log('stop discovery success: ' + JSON.stringify(e))
plus.bluetooth.closeBluetoothAdapter({
success: function(e) {
console.log('close success: ' + JSON.stringify(e))
},
fail: function(e) {
console.log('close failed: ' + JSON.stringify(e))
}
})
},
fail: function(e) {
console.log('stop discovery failed: ' + JSON.stringify(e))
}
})
UUID = plus.android.importClass('java.util.UUID')
uuid = UUID.fromString('00001101-0000-1000-8000-00805F9B34FB') //不需要更改
device = BAdapter.getRemoteDevice('DC:1D:30:34:62:A6') //这里是蓝牙打印机的蓝牙地址
plus.android.importClass(device)
bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(uuid)
plus.android.importClass(bluetoothSocket)
bluetoothSocket.connect() //连接
bluetoothSocket.isConnected()
var outputStream = bluetoothSocket.getOutputStream()
plus.android.importClass(outputStream)
// 打印字符串
var s = plus.android.importClass('java.lang.String')
var string = new s('测试数据' + new Date().getMilliseconds() + '\n\n\n\n') //必须以创建字符串对象的形式创建对象,否则返回NULL
var bytes = string.getBytes('gbk')
outputStream.write(bytes)
outputStream.flush()
let Util = {
RESET: [27, 64], // 复位
ALIGN_LEFT: [27, 97, 0], // 左对齐
ALIGN_CENTER: [27, 97, 1], // 居中
ALIGN_RIGHT: [27, 97, 2], // 右对齐
BOLD: [27, 69, 1], // 加粗
BOLD_CANCEL: [27, 69, 0], //取消加粗
DOUBLE_HEIGHT_WIDTH: [29, 33, 17], //宽高加倍
DOUBLE_WIDTH: [29, 33, 16], //宽加倍
DOUBLE_HEIGHT: [29, 33, 1], //高加倍
NORMAL: [29, 33, 0], //字体不放大
LINE_SPACING_DEFAULT: [27, 50] // 设置默认间距
}
function setFormat(command) {
outputStream.write(command)
outputStream.flush()
}
function PrintText(text) {
var s = plus.android.importClass('java.lang.String')
var string = new s(text)
var bytes = string.getBytes('gbk')
outputStream.write(bytes)
outputStream.flush()
}
// 获取字符长度
function GetLength(str) {
return str.replace(/[\u0391-\uFFE5]/g, 'aa').length //先把中文替换成两个字节的英文,在计算长度
}
// 输出两列,不能超过32字符
function printTowData(text1, text2) {
let textLength1 = GetLength(text1)
let textLength2 = GetLength(text2)
let blankLength = 32 - textLength1 - textLength2
let blank = ''
for (let i = 0; i < blankLength; i++) {
blank = blank + ' '
}
return text1 + blank + text2
}
PrintText(printTowData('哈哈哈', '嘿嘿嘿'))
var main = plus.android.runtimeMainActivity()
var BluetoothAdapter = plus.android.importClass(
'android.bluetooth.BluetoothAdapter'
)
var IntentFilter = plus.android.importClass('android.content.IntentFilter')
var BluetoothDevice = plus.android.importClass(
'android.bluetooth.BluetoothDevice'
)
var BAdapter = new BluetoothAdapter.getDefaultAdapter()
BAdapter.isEnabled()
BAdapter.enable()
plus.bluetooth.openBluetoothAdapter({
success: function(e) {
console.log('open success: ' + JSON.stringify(e))
plus.bluetooth.startBluetoothDevicesDiscovery({
success: function(e) {
console.log('start discovery success: ' + JSON.stringify(e))
},
fail: function(e) {
console.log('start discovery failed: ' + JSON.stringify(e))
}
})
},
fail: function(e) {
console.log('open failed: ' + JSON.stringify(e))
}
})
plus.bluetooth.getBluetoothDevices({
success: function(e) {
var devices = e.devices
console.log('get devices success: ' + e.length)
for (var i in devices) {
console.log(i + ': ' + JSON.stringify(devices[i]))
}
},
fail: function(e) {
console.log('get devices failed: ' + JSON.stringify(e))
}
})
plus.bluetooth.stopBluetoothDevicesDiscovery({
success: function(e) {
console.log('stop discovery success: ' + JSON.stringify(e))
plus.bluetooth.closeBluetoothAdapter({
success: function(e) {
console.log('close success: ' + JSON.stringify(e))
},
fail: function(e) {
console.log('close failed: ' + JSON.stringify(e))
}
})
},
fail: function(e) {
console.log('stop discovery failed: ' + JSON.stringify(e))
}
})
UUID = plus.android.importClass('java.util.UUID')
uuid = UUID.fromString('00001101-0000-1000-8000-00805F9B34FB') //不需要更改
device = BAdapter.getRemoteDevice('DC:1D:30:34:62:A6') //这里是蓝牙打印机的蓝牙地址
plus.android.importClass(device)
bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(uuid)
plus.android.importClass(bluetoothSocket)
bluetoothSocket.connect() //连接
bluetoothSocket.isConnected()
var outputStream = bluetoothSocket.getOutputStream()
plus.android.importClass(outputStream)
// 打印字符串
var s = plus.android.importClass('java.lang.String')
var string = new s('测试数据' + new Date().getMilliseconds() + '\n\n\n\n') //必须以创建字符串对象的形式创建对象,否则返回NULL
var bytes = string.getBytes('gbk')
outputStream.write(bytes)
outputStream.flush()
let Util = {
RESET: [27, 64], // 复位
ALIGN_LEFT: [27, 97, 0], // 左对齐
ALIGN_CENTER: [27, 97, 1], // 居中
ALIGN_RIGHT: [27, 97, 2], // 右对齐
BOLD: [27, 69, 1], // 加粗
BOLD_CANCEL: [27, 69, 0], //取消加粗
DOUBLE_HEIGHT_WIDTH: [29, 33, 17], //宽高加倍
DOUBLE_WIDTH: [29, 33, 16], //宽加倍
DOUBLE_HEIGHT: [29, 33, 1], //高加倍
NORMAL: [29, 33, 0], //字体不放大
LINE_SPACING_DEFAULT: [27, 50] // 设置默认间距
}
function setFormat(command) {
outputStream.write(command)
outputStream.flush()
}
function PrintText(text) {
var s = plus.android.importClass('java.lang.String')
var string = new s(text)
var bytes = string.getBytes('gbk')
outputStream.write(bytes)
outputStream.flush()
}
// 获取字符长度
function GetLength(str) {
return str.replace(/[\u0391-\uFFE5]/g, 'aa').length //先把中文替换成两个字节的英文,在计算长度
}
// 输出两列,不能超过32字符
function printTowData(text1, text2) {
let textLength1 = GetLength(text1)
let textLength2 = GetLength(text2)
let blankLength = 32 - textLength1 - textLength2
let blank = ''
for (let i = 0; i < blankLength; i++) {
blank = blank + ' '
}
return text1 + blank + text2
}
PrintText(printTowData('哈哈哈', '嘿嘿嘿'))
收起阅读 »

uni-app各环节版本兼容性说明
此文档停止维护,最新的文档见:uni版本说明
uni-app是一个跨度很大的产品,支持多种开发ide、HBuilderX有正式版和alpha版、支持cli和普通项目、支持很多端、有云打包app和本地打包app、编译器模式支持老的模板模式和新的自定义组件模式。
它们都会升级,如果出现一个升级、另一个未升级的情况,可能会运行异常。
正常情况,HBuilderX升级后,其自带的app运行基座、uni-app编译器、云打包配套引擎会同步升级。但在开发者使用cli创建项目、使用自定义基座、使用5+sdk离线打包时,就需要手动维护版本更新。
我们经常遇到的误报问题是:“我的HBuilderX已经是最新版了,升级日志里提到的已解决问题,为什么没有仍然存在?”,其实有的是因为cli项目下编译器是旧的、有的是因为本地打包的sdk是旧的,有的是因为自定义基座的版本是旧的。
-
如果你使用cli创建项目(即项目根目录是package.json),不管用什么ide,即便是用HBuilderX,切记cli项目的编译器是在项目下的,HBuilderX不管怎么升级都不会影响编译器版本。你需要手动npm update来升级编译器。以及如果你想要安装less、scss等预编译器,也需要自己npm安装在项目下,而不是在HBuilderX的插件管理里安装。
-
如果你使用离线打包,请注意HBuilderX升级后,真机运行基座和云打包对应引擎跟随HBuilderX升级,而你的sdk需要手动升级。sdk的版本升级一般滞后HBuilderX正式版升级一两天。在这里下载最新版
-
如果你使用自定义基座,之前制作的自定义基座是不会跟随HBuilderX升级的,升级HBuilderX后你应该重新制作新版自定义基座。
-
如果你使用wgt升级,新版HBuilderX编译的wgt,运行到之前的runtime上,一定要先测试好,看有没有兼容性问题。如果有问题,就不要wgt升级,整包升级。
-
考虑到向下兼容,uni-app编译器在升级为新的自定义组件模式后,同时保留了对老编译模式的向下兼容。
在HBuilderX alpha版中,App端一定会使用新编译器,不理会manifest配置。
在HBuilderX 正式版中,新创建的项目会使用新编译器,老项目不会强制使用,而是开发者自己在manifest里配置开启。 -
如果你使用其他ide开发uni-app,会经常因为拼错单词而运行失败,因为经过webpack编译一道,很多错误反应的不够直观,排错时间很长,不如从开始就依赖有良好提示的HBuilderX,避免敲错单词。
-
云打包的引擎版本说明
自HBuilderX 3.9起,云打包机版本保留了多个可用的版本,具体可用的云端打包版本参考下方的版本对应表。
打包时,服务端会根据用户使用的HBuilderX或cli版本去匹配最合适的打包机,规则如下(匹配优先级从高到低):- HBuilderX或cli版本与云端版本完全一致;
- HBuilderX或cli版本的大版本号与云端一致时,使用该大版本的最新版本;如打包机上有[3.92, 3.93, 3.99, 4.01, 4.10],则3.91使用3.99打包机。
- 当以上规则无法匹配时,使用云端最新版本。
举个例子:
当云打包机有以下版本[3.7.11,3.8.12,3.92, 3.93, 3.99, 4.01, 4.15]可用时:
- 如果HBuilderX使用3.7.11,3.8.12,3.92, 3.93, 3.99, 4.08, 4.15这些版本时,版本号完全匹配,直接使用同版本号打包机;
- 如果HBuilderX使用3.7.3,则云端打包机使用3.7.11版本;HBuilderX使用3.91,则云端打包机使用3.99版本;HBuilderX使用4.01版本,则云端打包机使用4.08版本;
- 如果HBuilderX使用3.7以下的版本,则云端打包机使用最新版本4.15。
很多人在报问题时不说清自己的情况,导致别人给出错误的回答。
很多人在搜问题时没注意看条件,导致使用了并不适用于自己的错误方案。
要想问题少,推荐使用HBuilderX完成一切工作,包括创建项目、运行编译、云打包app。
因为在这套体系里,官方会对很多常见的问题做出提醒和引导,减少问题的概率。随着HBuilderX的升级,uni-app编译器、真机运行基座、云打包引擎都会升级。
版本列表
下面提供 uni-app
开发中各产品的版本对应表:
<iframe src="https://dev.dcloud.net.cn/product/versions/view" width="100%" height="760px" frameborder="0" scrolling="no" style="border: 1px solid #eee; border-radius: 4px;"> </iframe>
此文档停止维护,最新的文档见:uni版本说明
uni-app是一个跨度很大的产品,支持多种开发ide、HBuilderX有正式版和alpha版、支持cli和普通项目、支持很多端、有云打包app和本地打包app、编译器模式支持老的模板模式和新的自定义组件模式。
它们都会升级,如果出现一个升级、另一个未升级的情况,可能会运行异常。
正常情况,HBuilderX升级后,其自带的app运行基座、uni-app编译器、云打包配套引擎会同步升级。但在开发者使用cli创建项目、使用自定义基座、使用5+sdk离线打包时,就需要手动维护版本更新。
我们经常遇到的误报问题是:“我的HBuilderX已经是最新版了,升级日志里提到的已解决问题,为什么没有仍然存在?”,其实有的是因为cli项目下编译器是旧的、有的是因为本地打包的sdk是旧的,有的是因为自定义基座的版本是旧的。
-
如果你使用cli创建项目(即项目根目录是package.json),不管用什么ide,即便是用HBuilderX,切记cli项目的编译器是在项目下的,HBuilderX不管怎么升级都不会影响编译器版本。你需要手动npm update来升级编译器。以及如果你想要安装less、scss等预编译器,也需要自己npm安装在项目下,而不是在HBuilderX的插件管理里安装。
-
如果你使用离线打包,请注意HBuilderX升级后,真机运行基座和云打包对应引擎跟随HBuilderX升级,而你的sdk需要手动升级。sdk的版本升级一般滞后HBuilderX正式版升级一两天。在这里下载最新版
-
如果你使用自定义基座,之前制作的自定义基座是不会跟随HBuilderX升级的,升级HBuilderX后你应该重新制作新版自定义基座。
-
如果你使用wgt升级,新版HBuilderX编译的wgt,运行到之前的runtime上,一定要先测试好,看有没有兼容性问题。如果有问题,就不要wgt升级,整包升级。
-
考虑到向下兼容,uni-app编译器在升级为新的自定义组件模式后,同时保留了对老编译模式的向下兼容。
在HBuilderX alpha版中,App端一定会使用新编译器,不理会manifest配置。
在HBuilderX 正式版中,新创建的项目会使用新编译器,老项目不会强制使用,而是开发者自己在manifest里配置开启。 -
如果你使用其他ide开发uni-app,会经常因为拼错单词而运行失败,因为经过webpack编译一道,很多错误反应的不够直观,排错时间很长,不如从开始就依赖有良好提示的HBuilderX,避免敲错单词。
-
云打包的引擎版本说明
自HBuilderX 3.9起,云打包机版本保留了多个可用的版本,具体可用的云端打包版本参考下方的版本对应表。
打包时,服务端会根据用户使用的HBuilderX或cli版本去匹配最合适的打包机,规则如下(匹配优先级从高到低):- HBuilderX或cli版本与云端版本完全一致;
- HBuilderX或cli版本的大版本号与云端一致时,使用该大版本的最新版本;如打包机上有[3.92, 3.93, 3.99, 4.01, 4.10],则3.91使用3.99打包机。
- 当以上规则无法匹配时,使用云端最新版本。
举个例子:
当云打包机有以下版本[3.7.11,3.8.12,3.92, 3.93, 3.99, 4.01, 4.15]可用时:
- 如果HBuilderX使用3.7.11,3.8.12,3.92, 3.93, 3.99, 4.08, 4.15这些版本时,版本号完全匹配,直接使用同版本号打包机;
- 如果HBuilderX使用3.7.3,则云端打包机使用3.7.11版本;HBuilderX使用3.91,则云端打包机使用3.99版本;HBuilderX使用4.01版本,则云端打包机使用4.08版本;
- 如果HBuilderX使用3.7以下的版本,则云端打包机使用最新版本4.15。
很多人在报问题时不说清自己的情况,导致别人给出错误的回答。
很多人在搜问题时没注意看条件,导致使用了并不适用于自己的错误方案。
要想问题少,推荐使用HBuilderX完成一切工作,包括创建项目、运行编译、云打包app。
因为在这套体系里,官方会对很多常见的问题做出提醒和引导,减少问题的概率。随着HBuilderX的升级,uni-app编译器、真机运行基座、云打包引擎都会升级。
版本列表
下面提供 uni-app
开发中各产品的版本对应表:
<iframe src="https://dev.dcloud.net.cn/product/versions/view" width="100%" height="760px" frameborder="0" scrolling="no" style="border: 1px solid #eee; border-radius: 4px;"> </iframe>

本地uni-app原生插件提交云端打包
从HBuilderX1.9.0开始uni-app原生插件可以直接在插件市场绑定应用后,直接云端打包生效,避免下载uni-app原生插件到本地后再提交云端打包。
同时也继续支持将插件下载到本地后再提交云端打包,通常在以下情况使用这种方式:
- uni-app原生插件开发者,开发后配置提交云端打包验证插件的包格式是否正确
- uni-app原生插件使用者,需要对插件自定义修改(如插件的资源等)
获取本地uni-app原生插件
插件市场下载免费uni-app原生插件
可以登录uni原生插件市场,在免费的插件详情页中点击“下载for离线打包”下载原生插件(zip格式),解压到HBuilderX的uni-app项目下的“nativeplugins”目录(如不存在则创建),以下是“DCloud-RichAlert”插件举例,它的下载地址是:https://ext.dcloud.net.cn/plugin?id=36
下载解压后目录结构如下:
开发者自己开发uni-app原生插件
原生插件开发完成后按指定格式压缩为zip包,参考uni-app原生插件格式说明文档。
按上图的格式配置到uni-app项目下的“nativeplugins”目录。
uni-app原生插件本地配置
将原生插件配置到uni-app项目的“nativeplugins”下,还需要在manifest.json文件的“App原生插件配置”项下点击“选择本地插件”,在列表中选择需要打包生效的插件:
保存后,重新提交云端打包生效
关于云端打包资源大小超限的说明
云端打包资源大小限制40M,如果超限每次打包需支付一定费用。40M—100M,每次打包10元,每增加100M费用增加10元。请登录开发者中心(https://dev.dcloud.net.cn),选择“打包服务”- “App大小超限充值”进行自助充值后,再提交打包。
如果是为了开发uni-app原生插件提交插件市场前的测试打包,大小超限也需付费才能云端打包,插件上线通过审核以后可以申请退还相关打包费用。
提供开发者账号及插件链接地址发邮件到 bd@dcloud.io 申请,谢谢!
使用 Windows 系统提交 iOS 本地插件打包报错的解决方法
如果使用 mac 提交本地插件打包正常,而使用 Windows 系统提交 iOS 本地插件打包时报错,是因为插件包使用的某个 .framework 库中存现软链接,在 Windows 系统上解压后导致软链接失效,打包时导致这个库缺失,所以会报错
报错如下图:
解决办法:
1.依次查看插件iOS目录下面的 .framework 库文件,下面以 UTDID.framework
为例,打开后发现 UTDID、Resources、Headers 大小都为 1kb,说明这几个文件既是软链(在Windows上加压后被转换为文本文件,无法链接到真实文件)
2.用记事本打开这几个文件,里面写的就是链接的真实文件目录,(链接的是
/Versions/A/
目录中的文件)3.把真实文件拷贝到这个库的根目录,将其他文件全部删除即可,最终的库文件
然后重新提交打包即可;
使用uni-app原生插件参考:uni-app原生插件(native plugin)使用说明
更多uni-app原生插件文档参考:uni-app原生插件开发指南
从HBuilderX1.9.0开始uni-app原生插件可以直接在插件市场绑定应用后,直接云端打包生效,避免下载uni-app原生插件到本地后再提交云端打包。
同时也继续支持将插件下载到本地后再提交云端打包,通常在以下情况使用这种方式:
- uni-app原生插件开发者,开发后配置提交云端打包验证插件的包格式是否正确
- uni-app原生插件使用者,需要对插件自定义修改(如插件的资源等)
获取本地uni-app原生插件
插件市场下载免费uni-app原生插件
可以登录uni原生插件市场,在免费的插件详情页中点击“下载for离线打包”下载原生插件(zip格式),解压到HBuilderX的uni-app项目下的“nativeplugins”目录(如不存在则创建),以下是“DCloud-RichAlert”插件举例,它的下载地址是:https://ext.dcloud.net.cn/plugin?id=36
下载解压后目录结构如下:
开发者自己开发uni-app原生插件
原生插件开发完成后按指定格式压缩为zip包,参考uni-app原生插件格式说明文档。
按上图的格式配置到uni-app项目下的“nativeplugins”目录。
uni-app原生插件本地配置
将原生插件配置到uni-app项目的“nativeplugins”下,还需要在manifest.json文件的“App原生插件配置”项下点击“选择本地插件”,在列表中选择需要打包生效的插件:
保存后,重新提交云端打包生效
关于云端打包资源大小超限的说明
云端打包资源大小限制40M,如果超限每次打包需支付一定费用。40M—100M,每次打包10元,每增加100M费用增加10元。请登录开发者中心(https://dev.dcloud.net.cn),选择“打包服务”- “App大小超限充值”进行自助充值后,再提交打包。
如果是为了开发uni-app原生插件提交插件市场前的测试打包,大小超限也需付费才能云端打包,插件上线通过审核以后可以申请退还相关打包费用。
提供开发者账号及插件链接地址发邮件到 bd@dcloud.io 申请,谢谢!
使用 Windows 系统提交 iOS 本地插件打包报错的解决方法
如果使用 mac 提交本地插件打包正常,而使用 Windows 系统提交 iOS 本地插件打包时报错,是因为插件包使用的某个 .framework 库中存现软链接,在 Windows 系统上解压后导致软链接失效,打包时导致这个库缺失,所以会报错
报错如下图:
解决办法:
1.依次查看插件iOS目录下面的 .framework 库文件,下面以 UTDID.framework
为例,打开后发现 UTDID、Resources、Headers 大小都为 1kb,说明这几个文件既是软链(在Windows上加压后被转换为文本文件,无法链接到真实文件)
2.用记事本打开这几个文件,里面写的就是链接的真实文件目录,(链接的是
/Versions/A/
目录中的文件)3.把真实文件拷贝到这个库的根目录,将其他文件全部删除即可,最终的库文件
然后重新提交打包即可;
使用uni-app原生插件参考:uni-app原生插件(native plugin)使用说明
更多uni-app原生插件文档参考:uni-app原生插件开发指南

uni-app模板编译模式和自定义组件编译模式差异说明
更新:这2种编译模式均已下线。本文已过期
uni-app 自 1.8版本开始,同时支持两种编译模式:
template模板模式
:老框架模式,借鉴自mpvue
,将用户编写的Vue
组件,编译为WXML
中的模板(template),变相实现组件化开发,性能差,支持 Vue 语法少,比如不支持过滤器。自定义组件模式
:新框架模式,DCloud自研,将用户编写的Vue
组件,编译为微信小程序自定义组件,实现了更高的性能及更完善的 Vue 语法支持。同时在App端提供了独立的js引擎,大幅提升性能。
如何切换编译模式
在 manifest.json
的源码视图里配置是否启用新编译器, manifest.json
-> %platform%
-> usingComponents
切换编译模式。
%platform%
是指平台名称
// manifest.json
{
// ...
/* App平台特有配置 */
"app-plus": {
"usingComponents":true //是否启用`自定义组件模式`,为true表示新的`自定义组件模式` ,否则为`template模板模式`
}
/* 微信小程序特有配置 */
"mp-weixin": {
"usingComponents":true //是否启用`自定义组件模式`,为true表示新的`自定义组件模式`,否则为`template模板模式`
}
// ...
}
在HBuilderX的manifest的可视化界面,每个平台的也都有配置勾选。
若manifest.json
配置文件中,未明确指定编译模式(即未配置%platform%
-> usingComponents
),则uni-app
默认策略如下:
HbuilderX 2.3.0
正式版之前的版本为保证历史项目兼容,默认使用老编译器(template模板模式
),即不配置的情况下效果等同于usingComponents: false
,而HbuilderX 2.3.0
正式版之后,默认会启用新编译器(自定义组件模式
),即不配置的情况下效果等同于usingComponents: true
,从HbuilderX 2.3.8
正式版开始将停止支持非自定义组件模式,届时,新版HBuilderX真机运行和云打包,都不再支持非自定义组件模式。HBuilderX的云打包,只向下保留2个版本。再升级1个版本后,老版打包机也不再支持非自定义组件模式。详见https://ask.dcloud.net.cn/article/36385- HBuilderX Alpha 为开发者提供最新技术尝鲜,默认会启用新编译器(
自定义组件模式
),即不配置的情况下效果等同于usingComponents: true
- CLI 开发模式下的,默认编译策略同 HBuidlerX 正式版策略
Tips:
- 切换编译环境之后,请重新运行项目
非自定义组件模式升级为自定义组件模式注意
自定义组件模式虽然兼容大部分老模式的写法,但也有部分不兼容。老项目升级时,可能需要修改部分代码,请详细参考自定义组件模式开发注意事项:https://ask.dcloud.net.cn/article/35851
不同编译模式支持的Vue语法差异
自定义组件模式
和模板模式
都不支持的 vue 语法:
- class不支持绑定Obejct变量(使用字符串的形式绑定)
- 不支持事件修饰符:prevent、passive(在App与小程序平台,使用stop修饰符,既可以阻止冒泡也能阻止默认行为)
- 不支持render、inline-template、X-Templates、keep-alive、transition
- 不支持使用 Vue.use 的方式注册全局组件(在main.js使用Vue.component的方式引入)
template模板模式
除了不支持如上Vue语法外,额外还不支持如下语法:
- 不支持过滤器
filter
- 不支持比较复杂的
JavaScript
渲染表达式 - 不支持在
template
内使用methods
中的函数 - 不支持
v-html
- 不支持
v-slot
新语法及后备内容 - 不支持解构插槽
Prop
设置默认值 - 组件不支持原生事件绑定,如:
@tap.native
- 组件不支持通过class绑定样式
问题反馈
- 如果在使用 uni-app 的过程中遇到问题,先认真阅读下 如何准确地反馈 uni-app 的问题 再发帖咨询。
- 在不要在本文章下留言报bug,请发布新帖,并将帖子地址复制到回复栏,并简短说明bug。
扩展阅读
更新:这2种编译模式均已下线。本文已过期
uni-app 自 1.8版本开始,同时支持两种编译模式:
template模板模式
:老框架模式,借鉴自mpvue
,将用户编写的Vue
组件,编译为WXML
中的模板(template),变相实现组件化开发,性能差,支持 Vue 语法少,比如不支持过滤器。自定义组件模式
:新框架模式,DCloud自研,将用户编写的Vue
组件,编译为微信小程序自定义组件,实现了更高的性能及更完善的 Vue 语法支持。同时在App端提供了独立的js引擎,大幅提升性能。
如何切换编译模式
在 manifest.json
的源码视图里配置是否启用新编译器, manifest.json
-> %platform%
-> usingComponents
切换编译模式。
%platform%
是指平台名称
// manifest.json
{
// ...
/* App平台特有配置 */
"app-plus": {
"usingComponents":true //是否启用`自定义组件模式`,为true表示新的`自定义组件模式` ,否则为`template模板模式`
}
/* 微信小程序特有配置 */
"mp-weixin": {
"usingComponents":true //是否启用`自定义组件模式`,为true表示新的`自定义组件模式`,否则为`template模板模式`
}
// ...
}
在HBuilderX的manifest的可视化界面,每个平台的也都有配置勾选。
若manifest.json
配置文件中,未明确指定编译模式(即未配置%platform%
-> usingComponents
),则uni-app
默认策略如下:
HbuilderX 2.3.0
正式版之前的版本为保证历史项目兼容,默认使用老编译器(template模板模式
),即不配置的情况下效果等同于usingComponents: false
,而HbuilderX 2.3.0
正式版之后,默认会启用新编译器(自定义组件模式
),即不配置的情况下效果等同于usingComponents: true
,从HbuilderX 2.3.8
正式版开始将停止支持非自定义组件模式,届时,新版HBuilderX真机运行和云打包,都不再支持非自定义组件模式。HBuilderX的云打包,只向下保留2个版本。再升级1个版本后,老版打包机也不再支持非自定义组件模式。详见https://ask.dcloud.net.cn/article/36385- HBuilderX Alpha 为开发者提供最新技术尝鲜,默认会启用新编译器(
自定义组件模式
),即不配置的情况下效果等同于usingComponents: true
- CLI 开发模式下的,默认编译策略同 HBuidlerX 正式版策略
Tips:
- 切换编译环境之后,请重新运行项目
非自定义组件模式升级为自定义组件模式注意
自定义组件模式虽然兼容大部分老模式的写法,但也有部分不兼容。老项目升级时,可能需要修改部分代码,请详细参考自定义组件模式开发注意事项:https://ask.dcloud.net.cn/article/35851
不同编译模式支持的Vue语法差异
自定义组件模式
和模板模式
都不支持的 vue 语法:
- class不支持绑定Obejct变量(使用字符串的形式绑定)
- 不支持事件修饰符:prevent、passive(在App与小程序平台,使用stop修饰符,既可以阻止冒泡也能阻止默认行为)
- 不支持render、inline-template、X-Templates、keep-alive、transition
- 不支持使用 Vue.use 的方式注册全局组件(在main.js使用Vue.component的方式引入)
template模板模式
除了不支持如上Vue语法外,额外还不支持如下语法:
- 不支持过滤器
filter
- 不支持比较复杂的
JavaScript
渲染表达式 - 不支持在
template
内使用methods
中的函数 - 不支持
v-html
- 不支持
v-slot
新语法及后备内容 - 不支持解构插槽
Prop
设置默认值 - 组件不支持原生事件绑定,如:
@tap.native
- 组件不支持通过class绑定样式
问题反馈
- 如果在使用 uni-app 的过程中遇到问题,先认真阅读下 如何准确地反馈 uni-app 的问题 再发帖咨询。
- 在不要在本文章下留言报bug,请发布新帖,并将帖子地址复制到回复栏,并简短说明bug。