提交 dd3f9793 编写于 作者: fxy060608's avatar fxy060608

Merge branch 'dev' of https://github.com/dcloudio/uni-app into v3

# Conflicts:
#	packages/uni-h5/dist/index.umd.min.js
#	src/core/view/plugins/index.js
#	src/platforms/app-plus-nvue/service/api/index.js
#	src/platforms/app-plus-nvue/service/api/route/util.js
#	src/platforms/app-plus/service/api/route/navigate-to.js
#	src/platforms/app-plus/service/api/route/switch-tab.js
#	src/platforms/app-plus/service/constants.js
#	src/platforms/app-plus/service/framework/app.js
......@@ -57,7 +57,7 @@ uni.getLocation({
- H5:在较新的手机浏览器上,H5 端获取定位信息,要求部署在 **https** 服务上,本地预览(localhost)仍然可以使用 http 协议。
- H5:无 GPS 模块的 PC 设备使用 Chrome 浏览器的时候,位置信息是连接谷歌服务器获取的,国内用户可能获取位置信息失败。
- H5:微信公众号可使用微信js sdk,[详见](https://ask.dcloud.net.cn/article/35380)
- App:Android由于谷歌服务被墙,想在国产手机上正常定位,需要向高德等三方服务商申请SDK资质,获取AppKey。云打包时需要在manifest的SDK配置中填写Appkey。在manifest可视化界面有详细申请指南。离线打包自行在原生工程中配置。
- App:Android由于谷歌服务被墙,想在国产手机上正常定位,需要向高德等三方服务商申请SDK资质,获取AppKey。云打包时需要在manifest的SDK配置中填写Appkey。在manifest可视化界面有详细申请指南。离线打包自行在原生工程中配置。注意包名和appkey信息必须匹配。
- App:``<map>`` 组件默认为国测局坐标gcj02,调用 ``uni.getLocation`` 返回结果传递给 ``<map>`` 组件时,需指定 type 为 gcj02。
- App:持续定位方案:iOS端可以申请持续定位权限,[参考](https://ask.dcloud.net.cn/article/12569)。Android如果进程被杀,代码无法执行。可以使用[unipush](https://ask.dcloud.net.cn/article/35622),通过服务器激活App,执行透传消息,让App启动然后采集位置。Android上,即使自己写原生插件做后台进程,也很容易被杀,unipush是更合适的方案
- 小程序:api默认不返回详细地址中文描述。需要中文地址有2种方式:1、使用高德地图小程序sdk,在app和微信上都可以获得中文地址,[参考](http://ask.dcloud.net.cn/article/35070)。2、只考虑app,使用``plus.geolocation``也可以获取中文地址
......
......@@ -77,6 +77,32 @@ mapContext
|fail|Function|否|接口调用失败的回调函数|
|complete|Function|否|接口调用结束的回调函数(调用成功、失败都会执行)|
## mapSearch 模块(module) #### reverseGeocode(Object,callback) > 反向地理编码
##### Object 属性|类型 |默认值|必填|说明 :--|:--|:--|:--|:--| point|Object| |是|{latitude: 纬度, longitude: 经度}
##### callback 返回 Object 参数说明
属性|类型 |说明 :--|:--|:--| type|String|"success" 表示成功, "fail" 表示失败 code|Number| 成功返回 0,失败返回相应 code 码
message|String|失败描述
address|String|查询后地址 (成功时返回)
#### poiSearchNearBy(Object,callback); > 周边检索 ##### Object 属性|类型 |默认值|必填|说明 :--|:--|:--|:--|:--| point|Object| |是|检索的中心点坐标 {latitude: 纬度, longitude: 经度}
key|String| | 是|搜索关键字 radius|Number|3000|否|检索的半径,单位为米 index|Number|1|否|要获取检索结果的页号索引 ##### callback 返回 Object 参数说明
属性|类型 |说明 :--|:--|:--|
type|String|"success" 表示成功, "fail" 表示失败 code|Number| 成功返回 0,失败返回相应 code 码
message|String|失败描述
totalNumber|Number|返回的POI数目
currentNumber|Number|当前页POI数目
pageNumber|Number|页数
pageIndex|Number|当前页号索引
poiList|Array.&lt;poiObject&gt;|POI信息数组
##### poiObject
属性|类型 |说明 :--|:--|:--|
location|Object|{latitude: 纬度, longitude: 经度}
name|String|名称
type|String|类型
distance|Number|距离(单位米)
address|String|地址
**Tips**
......
......@@ -188,6 +188,7 @@ uni.share({
```javascript
uni.share({
provider: 'weixin',
scene: "WXSceneSession",
type: 5,
imageUrl: 'https://img-cdn-qiniu.dcloud.net.cn/uniapp/app/share-logo@3.png',
title: '欢迎体验uniapp',
......
......@@ -13,7 +13,7 @@
|method|String|否|GET|有效值详见下方说明||
|dataType|String|否|json |如果设为 json,会尝试对返回的数据做一次 JSON.parse||
|responseType|String|否|text |设置响应的数据类型。合法值:text、arraybuffer|5+App和支付宝小程序不支持|
|sslVerify|Boolean|否|true|验证 ssl 证书|仅5+App安卓端支持(HBuilderX 2.3.4+)|
|sslVerify|Boolean|否|true|验证 ssl 证书|仅5+App安卓端支持(HBuilderX 2.3.3+)|
|success|Function|否||收到开发者服务成功返回的回调函数||
|fail|Function|否||接口调用失败的回调函数||
|complete|Function|否||接口调用结束的回调函数(调用成功、失败都会执行)|&nbsp;|
......@@ -124,5 +124,5 @@ requestTask.abort();
- iOS App第一次安装启动后,会弹出是否允许联网的询问框,在用户点击同意前,调用联网API会失败。请注意判断这种情况。比如官方提供的新闻模板示例(HBuilderX新建项目可选择),会判断如果无法联网,则提供一个错误页,提示用户设置网络及下拉刷新重试。
- 良好体验的App,还会判断当前是否处于飞行模式([参考](https://ext.dcloud.net.cn/plugin?id=594))、是wifi还是3G([参考](https://uniapp.dcloud.io/api/system/network)
- 部分安卓设备,真机运行或debug模式下的网络,低于release模式很多。
- 安卓端请求某些 https 服务会失败,可以尝试配置 sslVerify 为 false 关闭 ssl 证书验证
- 使用一些比较小众的证书机构(如:CFCA OV OCA)签发的 ssl 证书在安卓设备请求会失败,因为这些机构的根证书不在系统内置根证书库,可以更换其他常见机构签发的证书(如:Let's Encrypt),或者配置 sslVerify 为 false 关闭 ssl 证书验证(不推荐)。
- 单次网络请求数据量建议控制在50K以下(仅指json数据,不含图片),过多数据应分页获取,以提升应用体验。
......@@ -184,8 +184,17 @@ uni.setTabBarBadge({
|fail|Function|否|接口调用失败的回调函数|
|complete|Function|否|接口调用结束的回调函数(调用成功、失败都会执行)|
### uni.onTabBarMidButtonTap(CALLBACK)
监听中间按钮的点击事件
**平台差异说明**
|App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|QQ小程序|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|√(HBuilderX 2.3.4+)|x|x|x|x|x|x|
**Tip**
- tabbar是原生的,层级高于前端元素
- [uni-app插件市场](https://ext.dcloud.net.cn/search?q=%E5%BA%95%E9%83%A8%E5%9B%BE%E6%A0%87%E8%8F%9C%E5%8D%95)有封装的前端tabbar,但性能不如原生tabbar
- 如果想要一个中间带+号的tabbar,在HBuilderX中新建uni-app项目、选择 底部选项卡 模板
\ No newline at end of file
- HBuilderX 2.3.4 版本以下如果想要一个中间带+号的tabbar,在HBuilderX中新建uni-app项目、选择 底部选项卡 模板
\ No newline at end of file
......@@ -55,6 +55,9 @@
"selectedColor": "#3cc51f",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"height": "56px",
"fontSize": "12px",
"iconWidth": "24px",
"list": [{
"pagePath": "pages/component/index",
"iconPath": "static/image/icon_component.png",
......@@ -65,7 +68,15 @@
"iconPath": "static/image/icon_API.png",
"selectedIconPath": "static/image/icon_API_HL.png",
"text": "接口"
}]
}],
"midButton": {
"width": "80px",
"height": "56px",
"text": "文字",
"iconPath": "static/image/midButton_iconPath.png",
"iconWidth": "24px",
"backgroundImage": "static/image/midButton_backgroundImage.png"
}
}
}
```
......@@ -663,6 +674,10 @@ h5 平台下拉刷新动画,只有 circle 类型。
|borderStyle|String|否|black|tabbar 上边框的颜色,仅支持 black/white||
|list|Array|是||tab 的列表,详见 list 属性说明,最少2个、最多5个 tab||
|position|String|否|bottom|可选值 bottom、top|top 值仅微信小程序支持|
|fontSize|String|否|12px|文字默认大小|App(HBuilderX 2.3.4+)|
|iconWidth|String|否|24px|图标默认宽度(高度等比例缩放)|App(HBuilderX 2.3.4+)|
|height|String|否|56px|tabBar 默认高度|App(HBuilderX 2.3.4+)|
|midButton|Object|否||中间按钮 仅在 list 项为偶数时有效|App(HBuilderX 2.3.4+)|
其中 list 接收一个数组,数组中的每个项都是一个对象,其属性值如下:
......@@ -673,6 +688,17 @@ h5 平台下拉刷新动画,只有 circle 类型。
|iconPath|String|否|图片路径,icon 大小限制为40kb,建议尺寸为 81px * 81px,当 postion 为 top 时,此参数无效,不支持网络图片,不支持字体图标|
|selectedIconPath|String|否|选中时的图片路径,icon 大小限制为40kb,建议尺寸为 81px * 81px ,当 postion 为 top 时,此参数无效|
**midButton 属性说明**
|属性|类型|必填|默认值|描述|
|:-|:-|:-|:-|:-|
|width|String|否|80px|中间按钮的宽度,tabBar 其它项为减去此宽度后平分,默认值为与其它项平分宽度|
|height|String|否|56px|中间按钮的高度,可以大于 tabBar 高度|
|text|String|否||中间按钮的文字|
|iconPath|String|否||中间按钮的图片路径|
|iconWidth|String|否|24px||图片宽度(高度等比例缩放)|
|backgroundImage|String|否||中间按钮的背景图片路径|
#### **tabbar常见问题** @tips-tabbar
- tabbar 的 js api 见[接口-界面-tabbar](https://uniapp.dcloud.io/api/ui/tabbar),可实现动态显示隐藏(如弹出层无法覆盖tabbar)、内容修改(如国际化)、item加角标等功能。hello uni-app中也有示例。
- tabbar 的 item 点击事件见[页面生命周期的onTabItemTap](https://uniapp.dcloud.io/frame?id=%E9%A1%B5%E9%9D%A2%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F)
......@@ -680,7 +706,6 @@ h5 平台下拉刷新动画,只有 circle 类型。
- tabbar 在H5端是div模拟的,属于前端屏幕窗口的一部分,如果要使用bottom居底定位方式,应该使用css变量`--window-bottom`,比如悬浮在tabbar上方10px的按钮,样式如下`bottom: calc(var(--window-bottom) + 10px)`
- tabbar 的默认高度,在不同平台不一样。[详见](https://uniapp.dcloud.io/frame?id=%e5%9b%ba%e5%ae%9a%e5%80%bc)
- 中间带+号的tabbar模板例子,[参考](https://ext.dcloud.net.cn/plugin?id=98)。可跨端,但+号不凸起。
- 如需 tabbar 中间凸起,可自定义tabbar,插件市场有例子,如colorUI等。但注意前端tabbar的性能不如原生tabbar,如果是多页方式,底部tabbar会在切换时闪执行转场动画,如果是单页方式,承载复杂页面内容会有性能问题。[插件市场](https://ext.dcloud.net.cn/search?q=tabbar)搜索tabbar有不少类似例子。
- App端若使用nvue,自定义tabbar,没有性能体验问题。
- 纯nvue项目(manifest里renderer为native),目前使用pages.json里的tabbar反而影响性能,建议使用前端自己实现单页面的tabbar。后续会解决这个bug。
- Android App上弹出键盘顶起tabbar的问题。升级到HBuilderX 2.2后不再存在。
......
......@@ -29,11 +29,11 @@ editor组件目前只有App的vue页面和微信支持,其他端的富文本
| show-img-size | boolean | false | 否 | 点击图片时显示图片大小控件 |
| show-img-toolbar | boolean | false | 否 | 点击图片时显示工具栏控件 |
| show-img-resize | boolean | false | 否 | 点击图片时显示修改尺寸控件 |
| bindready | eventhandle | | 否 | 编辑器初始化完成时触发 |
| bindfocus | eventhandle | | 否 | 编辑器聚焦时触发,event.detail = {html, text, delta} |
| bindblur | eventhandle | | 否 | 编辑器失去焦点时触发,detail = {html, text, delta} |
| bindinput | eventhandle | | 否 | 编辑器内容改变时触发,detail = {html, text, delta} |
| bindstatuschange | eventhandle | | 否 | 通过 Context 方法改变编辑器内样式时触发,返回选区已设置的样式 |
| @ready | eventhandle | | 否 | 编辑器初始化完成时触发 |
| @focus | eventhandle | | 否 | 编辑器聚焦时触发,event.detail = {html, text, delta} |
| @blur | eventhandle | | 否 | 编辑器失去焦点时触发,detail = {html, text, delta} |
| @input | eventhandle | | 否 | 编辑器内容改变时触发,detail = {html, text, delta} |
| @statuschange | eventhandle | | 否 | 通过 Context 方法改变编辑器内样式时触发,返回选区已设置的样式 |
编辑器内支持部分 HTML 标签和内连样式,不支持**class****id**
......
......@@ -21,7 +21,7 @@
|controls|Array||控件||
|include-points|Array||缩放视野以包含所有给定的坐标点|App-nvue 2.1.5+、微信小程序、H5、百度小程序、支付宝小程序|
|show-location|Boolean||显示带有方向的当前定位点|微信小程序、H5、百度小程序、支付宝小程序|
|@markertap|EventHandle||点击标记点时触发|App-nvue暂不支持, App平台需要指定 marker 对象属性 id|
|@markertap|EventHandle||点击标记点时触发|App-nvue 2.3.3+, App平台需要指定 marker 对象属性 id|
|@callouttap|EventHandle||点击标记点对应的气泡时触发||
|@controltap|EventHandle||点击控件时触发||
|@regionchange|EventHandle||视野发生变化时触发|微信小程序、H5、百度小程序、支付宝小程序|
......
......@@ -203,6 +203,7 @@ export default {
// #ifdef APP-PLUS
wv = plus.webview.create("","custom-webview",{
plusrequire:"none", //禁止远程网页使用plus的API,有些使用mui制作的网页可能会监听plus.key,造成关闭页面混乱,可以通过这种方式禁止
'uni-app': 'none', //不加载uni-app渲染层框架,避免样式冲突
top:uni.getSystemInfoSync().statusBarHeight+44 //放置在titleNView下方。如果还想在webview上方加个地址栏的什么的,可以继续降低TOP值
})
wv.loadURL("https://www.baidu.com")
......
......@@ -732,6 +732,7 @@ const package = require('packageName')
|支付宝小程序|支持支付宝小程序组件|mycomponents|
|百度小程序|支持百度小程序组件|swancomponents|
|头条小程序|支持头条小程序组件|ttcomponents|
|QQ小程序|支持QQ小程序组件|wxcomponents|
此文档要求开发者对各端小程序的**自定义组件**有一定了解,没接触过小程序**自定义组件**的可以参考:
......@@ -739,6 +740,7 @@ const package = require('packageName')
- [百度小程序自定义组件](https://smartprogram.baidu.com/docs/develop/framework/custom-component/)
- [支付宝小程序自定义组件](https://docs.alipay.com/mini/framework/custom-component-overview)
- [头条小程序自定义组件](https://developer.toutiao.com/docs/framework/custom_component_intro.html)
- [QQ小程序自定义组件](https://q.qq.com/wiki/develop/miniprogram/frame/diy_components/)
**目录结构**
......@@ -785,7 +787,7 @@ const package = require('packageName')
"path": "index/index",
"style": {
"usingComponents": {
// #ifdef APP-PLUS || MP-WEIXIN
// #ifdef APP-PLUS || MP-WEIXIN || MP-QQ
"custom": "/wxcomponents/custom/index"
// #endif
// #ifdef MP-BAIDU
......
#### 运行原理
``uni-app`` 在 App 端或小程序端运行时,从架构上分为逻辑层和视图层两个部分。逻辑层负责储存数据和执行业务逻辑,视图层负责页面渲染。
1. 逻辑层和视图层分离,且非H5端通信有折损
``uni-app`` 在非H5端运行时,从架构上分为逻辑层和视图层两个部分。逻辑层负责储存数据和执行业务逻辑,视图层负责页面渲染。
页面加载时,联网和逻辑运算在逻辑层(Android是v8,iOS是jscore),然后会传递数据给视图层渲染。这种通信有损耗。同样,在视图层操作时,比如拖动页面,要实时传递事件给逻辑层接收,也是有损耗的。
2. App端渲染引擎可切换
在App端,nvue页面的视图层是由原生引擎渲染的,vue页面的视图层是os的webview渲染的。
uni-app的webview渲染经过优化,性能也足够好。它比nvue弱的地方主要在于启动速度和可左右拖动的长列表。
3. app-vue和小程序的数据更新,分页面级和组件级
对于复杂页面,更新某个区域的数据时,需要把这个区域做成组件,这样更新数据时就只更新这个组件,否则会整个页面的数据更新,造成点击延迟卡顿。
这就是自定义组件编译模式的特点。
比如微博长列表页面,点击一个点赞图标,赞数要立即+1,此时这个点赞图标一定要做成组件。否则这个+1会引发页面级所有数据的更新。
app-nvue和h5不存在此问题。造成差异的原因是小程序目前只提供了组件差量更新的机制,不能自动计算所有页面差量。
#### 优化建议
......@@ -52,7 +65,7 @@
**优化页面切换动画**
* 页面初始化时若存在大量图片渲染和大量数据通讯,很有可能造成页面切换卡顿、掉帧。建议延时100ms~300ms渲染图片,分批进行数据通讯,以减少一次性渲染的节点数量。
* 页面初始化时若存在大量图片或原生组件渲染和大量数据通讯,会发生新页面渲染和窗体进入动画抢资源,造成页面切换卡顿、掉帧。建议延时100ms~300ms渲染图片或复杂原生组件,分批进行数据通讯,以减少一次性渲染的节点数量。
* App端动画效果可以自定义。popin/popout的双窗体联动挤压动画效果对资源的消耗更大,如果动画期间页面里在执行耗时的js,可能会造成动画掉帧。此时可以使用消耗资源更小的动画效果,比如slide-in-right/slide-out-right。
**优化样式渲染速度**
......
# uni-app 更新日志
======================================
#### 2.3.3.20190924
* App-Android平台 新增 uni.request 网络请求增加参数 sslVerify,配置是否验证 ssl 证书。但建议使用普遍受信的证书而不是忽略证书校验。[详情](https://uniapp.dcloud.io/api/request/request)
* App-iOS平台 调整 非自定义组件模式 逻辑层默认从 WKWebview 切回 UIWebview,避免 uni.request 无法跨域的问题。但仍建议开发者尽快升级自定义组件模式
* App-iOS平台 新增 非自定义组件模式 iOS13上页面无法滚动的问题,如不能很快升级为自定义组件模式,可临时使用本文的方案2来解决,[详情](https://ask.dcloud.net.cn/article/36410)
* App-iOS平台 修复 nvue swiper组件包含子组件少于3个时布局可能不正确的Bug
* App-iOS平台 修复 nvue video组件退出全屏动画会闪现底层组件的Bug
* H5端 修复 监听页面滚动(onPageScroll)后切换页面报错的Bug [详情](https://ask.dcloud.net.cn/question/78955)
#### 2.3.2.20190921
* App平台 修复 uni.writeBLECharacteristicValue 无法写入数据的 Bug [详情](https://ask.dcloud.net.cn/question/79204)
* App平台 修复 调用 uni.pageScrollTo 时页面内元素 fixed 定位失效的 Bug [详情](https://ask.dcloud.net.cn/question/73179)
......
......@@ -12,5 +12,5 @@
"message": "chore(release): publish %s"
}
},
"version": "2.0.0-23020190919001"
"version": "2.0.0-23320190923002"
}
......@@ -115,7 +115,7 @@ const device = [
]
const keyboard = [
'hideKeyboard',
'hideKeyboard',
'onKeyboardHeightChange'
]
......@@ -138,6 +138,7 @@ const ui = [
'removeTabBarBadge',
'showTabBarRedDot',
'hideTabBarRedDot',
'onTabBarMidButtonTap',
'setBackgroundColor',
'setBackgroundTextStyle',
'createAnimation',
......@@ -209,4 +210,4 @@ const apis = [
...third
]
module.exports = apis
module.exports = apis
......@@ -24,7 +24,7 @@ module.exports = function genRequireCode (baseDirname, modules) {
const moduleAbsolutePath = Path.resolve(baseDirname, file).replace(/\\/g, '/')
importCode += genImportCode(moduleName, moduleAbsolutePath)
moduleProps += genPropsCode(file, moduleName)
moduleProps += genPropsCode(file.replace(/\\/g, '/'), moduleName)
})
const requireFnCode = (`
(function() {
......
{
"name": "@dcloudio/uni-app-plus-nvue",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-app app-plus-nvue",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/uni-app-plus",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-app app-plus",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
......@@ -71,7 +71,11 @@ function updateComponentJson (name, jsonObj, usingComponents = true) {
const oldJsonStr = getJsonFile(name)
if (oldJsonStr) { // update
if (usingComponents) { // merge usingComponents
jsonObj.usingComponents = JSON.parse(oldJsonStr).usingComponents || {}
const oldJsonObj = JSON.parse(oldJsonStr)
jsonObj.usingComponents = oldJsonObj.usingComponents || {}
if (oldJsonObj.usingGlobalComponents) { // 复制 global components(针对不支持全局 usingComponents 的平台)
jsonObj.usingGlobalComponents = oldJsonObj.usingGlobalComponents
}
}
const newJsonStr = JSON.stringify(jsonObj, null, 2)
if (newJsonStr !== oldJsonStr) {
......
{
"name": "@dcloudio/uni-cli-shared",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-cli-shared",
"main": "lib/index.js",
"repository": {
......@@ -20,5 +20,5 @@
"hash-sum": "^1.0.2",
"strip-json-comments": "^2.0.1"
},
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/uni-h5-ui",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-app h5 ui",
"main": "dist/index.umd.min.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/uni-h5",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-app h5",
"main": "dist/index.umd.min.js",
"repository": {
......@@ -18,5 +18,5 @@
"intersection-observer": "^0.7.0",
"safe-area-insets": "^1.4.1"
},
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/uni-mp-alipay",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-app mp-alipay",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/uni-mp-baidu",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-app mp-baidu",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/uni-mp-qq",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-app mp-qq",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/uni-mp-toutiao",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-app mp-toutiao",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/uni-mp-weixin",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-app mp-weixin",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/uni-stat",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "",
"main": "dist/index.js",
"repository": {
......@@ -34,5 +34,5 @@
"rollup-plugin-replace": "^2.2.0",
"rollup-plugin-uglify": "^6.0.2"
},
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/uni-template-compiler",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-template-compiler",
"main": "lib/index.js",
"repository": {
......@@ -22,5 +22,5 @@
"@babel/types": "^7.3.3",
"vue-template-compiler": "^2.6.10"
},
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/vue-cli-plugin-hbuilderx",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "HBuilderX plugin for vue-cli 3",
"main": "index.js",
"repository": {
......@@ -18,5 +18,5 @@
"css": "~2.2.1",
"escodegen": "^1.8.1"
},
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/vue-cli-plugin-uni-optimize",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-app optimize plugin for vue-cli 3",
"main": "index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/vue-cli-plugin-uni",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-app plugin for vue-cli 3",
"main": "index.js",
"repository": {
......@@ -17,7 +17,7 @@
"author": "fxy060608",
"license": "Apache-2.0",
"dependencies": {
"@dcloudio/uni-stat": "^2.0.0-23020190919001",
"@dcloudio/uni-stat": "^2.0.0-23320190923002",
"copy-webpack-plugin": "^4.6.0",
"cross-env": "^5.2.0",
"envinfo": "^6.0.1",
......@@ -34,5 +34,5 @@
"wrap-loader": "^0.2.0",
"xregexp": "4.0.0"
},
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
{
"name": "@dcloudio/webpack-uni-mp-loader",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "webpack-uni-mp-loader",
"main": "index.js",
"repository": {
......@@ -16,5 +16,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
......@@ -67,6 +67,8 @@ module.exports = function(pagesJson, userManifestJson) {
navigationBarTextStyle = 'white',
navigationBarBackgroundColor = '#000000'
} = appJson['window'] || {}
const TABBAR_HEIGHT = 50
let manifestJson = JSON.parse(fs.readFileSync(path.resolve(__dirname, './manifest.json'), 'utf8'))
......@@ -302,6 +304,30 @@ module.exports = function(pagesJson, userManifestJson) {
manifestJson.plus.popGesture = 'close'
}
// 检查原生混淆选项
const confusion = manifestJson.plus.confusion
if (confusion && confusion.resources) {
const resources = {}
for (const key in confusion.resources) {
if (!/\.nvue$/.test(key)) {
throw new Error(`原生混淆仅支持 nvue 页面,错误的页面路径:${key}`)
} else {
resources[key.replace(/\.nvue$/, '.js')] = confusion.resources[key]
}
if (!Object.keys(appJson.nvue.pages).find(path => {
const subNVues = appJson.nvue.pages[path].window.subNVues || []
return path.replace(/\.html$/, '.nvue') === key || subNVues.find(({ path }) => path === key.replace(/\.nvue$/, ''))
}) && !pagesJson.pages.find(({ style = {} }) => {
style = Object.assign(style, style['app-plus'])
const subNVues = style.subNVues || []
return subNVues.find(({ path }) => path === key.replace(/\.nvue$/, ''))
})) {
throw new Error(`原生混淆页面未在项目内使用,错误的页面路径:${key}`)
}
}
confusion.resources = resources
}
// uni-app
const uniApp = require('../../../package.json')['uni-app']
manifestJson.plus['uni-app'] = uniApp
......@@ -334,6 +360,13 @@ module.exports = function(pagesJson, userManifestJson) {
if (conditionPagePath && isNVueEntryPage) {
isNVueEntryPage = appJson.nvue.entryPagePath === conditionPagePath
}
manifestJson.plus.useragent.value = 'uni-app'
manifestJson.launch_path = '__uniappview.html'
Object.assign(manifestJson.plus.launchwebview, {
id: '1',
kernel: 'WKWebview',
'uni-app': 'auto'
})
if (process.env.UNI_USING_NATIVE) {
appJson.entryPagePath = appJson.nvue.entryPagePath
// networkTimeout
......@@ -349,50 +382,33 @@ module.exports = function(pagesJson, userManifestJson) {
})
delete appJson.nvue
// 纯 nvue 带 tab
if (pagesJson.tabBar && pagesJson.tabBar.list && pagesJson.tabBar.list.length) {
manifestJson.launch_path = '__uniapptabbar.html'
manifestJson.plus.secondwebview = {
id: '1',
mode: 'child',
top: 0,
bottom: 56,
uniNView: {
path: appJson.pages[0]
}
delete manifestJson.plus.launchwebview.kernel
manifestJson.launch_path = ''
Object.assign(manifestJson.plus.launchwebview, {
uniNView: {
path: appJson.entryPagePath
}
})
} else if (isNVueEntryPage) {
// 非纯 nvue 项目首页为 nvue 页面
manifestJson.plus.launchwebview.id = '2'
}
// 带 tab
if (pagesJson.tabBar && pagesJson.tabBar.list && pagesJson.tabBar.list.length) {
const tabBar = manifestJson.plus.tabBar = Object.assign({}, pagesJson.tabBar)
tabBar.borderStyle = tabBar.borderStyle === 'white' ? '#ffffff' : '#c6c6c6'
tabBar.height = `${parseFloat(tabBar.height) || TABBAR_HEIGHT}px`
// 非纯 nvue 项目首页为 nvue 页面
if (!process.env.UNI_USING_NATIVE && isNVueEntryPage) {
manifestJson.plus.launchwebview.id = '2'
} else {
// 首页是 tabBar 页面
const item = tabBar.list.find(page => page.pagePath === (process.env.UNI_USING_NATIVE ? appJson.entryPagePath : entryPagePath))
if (item) {
tabBar.child = ['lauchwebview']
tabBar.selected = tabBar.list.indexOf(item)
}
} else { // 纯 nvue 不带 tab
manifestJson.launch_path = ''
Object.assign(manifestJson.plus.launchwebview, {
id: '1',
uniNView: {
path: appJson.pages[0]
}
})
}
} else if (isNVueEntryPage) { // 临时 tabBar 页面
manifestJson.launch_path = '__uniapptabbar.html'
} else if (pagesJson.tabBar && pagesJson.tabBar.list && pagesJson.tabBar.list.length) {
manifestJson.launch_path = '__uniapptabbar.html'
manifestJson.plus.secondwebview = {
id: '1'
}
manifestJson.plus.secondwebview.launch_path = '__uniappview.html'
if (!manifestJson.plus.secondwebview.kernel) {
manifestJson.plus.secondwebview.kernel = 'WKWebview'
}
// 首页是 tabBar 页面
if (pagesJson.tabBar.list.find(page => page.pagePath === entryPagePath)) {
manifestJson.plus.secondwebview.mode = 'child'
manifestJson.plus.secondwebview.top = 0
manifestJson.plus.secondwebview.bottom = 56
}
} else { // 无 tabbar 的页面,launchWebview 的 id 为1
manifestJson.launch_path = '__uniappview.html'
manifestJson.plus.launchwebview.id = '1'
if (!manifestJson.plus.launchwebview.kernel) {
manifestJson.plus.launchwebview.kernel = 'WKWebview'
}
}
}
......@@ -443,4 +459,4 @@ module.exports = function(pagesJson, userManifestJson) {
return [manifest, parseV3Config(appJson)]
}
return [app, manifest]
}
}
{
"name": "@dcloudio/webpack-uni-pages-loader",
"version": "2.0.0-23020190919001",
"version": "2.0.0-23320190923002",
"description": "uni-app pages.json loader",
"main": "lib/index.js",
"repository": {
......@@ -21,7 +21,7 @@
"strip-json-comments": "^2.0.1"
},
"uni-app": {
"compilerVersion": "2.3.0"
"compilerVersion": "2.3.3"
},
"gitHead": "0fac47b62d100213ce48c29dd9d0a335f8a00264"
"gitHead": "10184426b19cb76e01c93fb25c982c72887557e8"
}
......@@ -158,9 +158,7 @@ if (pixelRatio !== 1) {
}
export function wrapper (canvas) {
canvas.style.height = canvas.height + 'px'
canvas.style.width = canvas.width + 'px'
canvas.width *= pixelRatio
canvas.height *= pixelRatio
canvas.width = canvas.offsetWidth * pixelRatio
canvas.height = canvas.offsetHeight * pixelRatio
canvas.getContext('2d').__hidpi__ = true
}
import {
isFn
} from 'uni-shared'
} from 'uni-shared'
const todoApis = Object.create(null)
const TODOS = [
'onTabBarMidButtonTap',
'subscribePush',
'unsubscribePush',
'onPush',
......@@ -29,4 +30,4 @@ TODOS.forEach(function (name) {
todoApis[name] = createTodoApi(name)
})
export default todoApis
export default todoApis
import {
onMethod,
invokeMethod
} from '../../platform'
import {
invoke
} from 'uni-core/service/bridge'
export function removeTabBarBadge ({
index
}) {
......@@ -20,4 +25,16 @@ export function showTabBarRedDot ({
})
}
export const hideTabBarRedDot = removeTabBarBadge
export const hideTabBarRedDot = removeTabBarBadge
const callbacks = []
onMethod('onTabBarMidButtonTap', res => {
callbacks.forEach(callbackId => {
invoke(callbackId, res)
})
})
export function onTabBarMidButtonTap (callbackId) {
callbacks.push(callbackId)
}
import {
hasOwn
} from 'uni-shared'
export default function createPage (pageVm) {
const $route = pageVm.$route
pageVm.route = $route.meta.pagePath
const id = hasOwn($route.params, '__id__') ? $route.params.__id__ : $route.meta.id
pageVm.__page__ = {
id: $route.params.__id__,
id,
path: $route.path,
route: $route.meta.pagePath,
meta: Object.assign({}, $route.meta)
}
// 兼容 mpvue
pageVm.$vm = pageVm
pageVm.$root = pageVm
pageVm.$root = pageVm
pageVm.$holder = pageVm.$parent.$parent
// 补充 mp 相关属性
pageVm.$mp = {
......@@ -19,4 +25,4 @@ export default function createPage (pageVm) {
// 暂不支持
status: ''
}
}
}
......@@ -21,6 +21,7 @@ import {
} from 'uni-mixins'
import {
pixelRatio,
wrapper
} from 'uni-helpers/hidpi'
......@@ -106,16 +107,8 @@ export default {
method(data)
}
},
_resize ({
width,
height
}) {
var canvas = this.$refs.canvas
if (canvas.style.width !== (width + 'px') || canvas.style.height !== (height + 'px')) {
canvas.width = width
canvas.height = height
wrapper(canvas)
}
_resize () {
wrapper(this.$refs.canvas)
},
_touchmove (event) {
event.preventDefault()
......@@ -381,22 +374,44 @@ export default {
}
},
getImageData ({
x,
y,
x = 0,
y = 0,
width,
height,
destWidth,
destHeight,
hidpi = true,
callbackId
}) {
var imgData
var canvas = this.$refs.canvas
if (!width) {
width = canvas.width
width = canvas.offsetWidth - x
}
if (!height) {
height = canvas.height
height = canvas.offsetHeight - y
}
try {
imgData = canvas.getContext('2d').getImageData(x, y, width, height)
const newCanvas = document.createElement('canvas')
if (!hidpi) {
if (!destWidth && !destHeight) {
destWidth = Math.round(width * pixelRatio)
destHeight = Math.round(height * pixelRatio)
} else if (!destWidth) {
destWidth = Math.round(width / height * destHeight)
} else if (!destHeight) {
destHeight = Math.round(height / width * destWidth)
}
} else {
destWidth = width
destHeight = height
}
newCanvas.width = destWidth
newCanvas.height = destHeight
const context = newCanvas.getContext('2d')
context.__hidpi__ = true
context.drawImageByCanvas(canvas, x, y, width, height, 0, 0, destWidth, destHeight, false)
imgData = context.getImageData(0, 0, destWidth, destHeight)
} catch (error) {
UniViewJSBridge.publishHandler('onCanvasMethodCallback', {
callbackId,
......@@ -411,8 +426,8 @@ export default {
data: {
errMsg: 'canvasGetImageData:ok',
data: [...imgData.data],
width,
height
width: destWidth,
height: destHeight
}
}, this.$page.id)
},
......@@ -428,8 +443,12 @@ export default {
if (!height) {
height = Math.round(data.length / 4 / width)
}
this.$refs.canvas.getContext('2d').putImageData(new ImageData(new Uint8ClampedArray(data), width,
height), x, y)
const canvas = document.createElement('canvas')
canvas.width = width
canvas.height = height
const context = canvas.getContext('2d')
context.putImageData(new ImageData(new Uint8ClampedArray(data), width, height), 0, 0)
this.$refs.canvas.getContext('2d').drawImage(canvas, x, y, width, height)
} catch (error) {
UniViewJSBridge.publishHandler('onCanvasMethodCallback', {
callbackId,
......
......@@ -108,7 +108,7 @@ class ComponentDescriptor {
const clsIndex = addWxsClsArr.findIndex(oldCls => oldCls === cls)
if (clsIndex !== -1) { // 在 addWxsClass 中
addWxsClsArr.splice(clsIndex, 1)
}
}
removeWxsClsArr.push(cls)
})
this.$el.__wxsRemoveClass = removeWxsClsArr
......@@ -147,6 +147,10 @@ class ComponentDescriptor {
}
export function createComponentDescriptor (vm) {
if (vm && vm.$options.name && vm.$options.name.indexOf('VUni') === 0) {
// 内置组件需要使用父 vm
vm = vm.$parent
}
if (vm && vm.$el) {
if (!vm.$el.__wxsComponentDescriptor) {
vm.$el.__wxsComponentDescriptor = new ComponentDescriptor(vm)
......
import {
isFn
} from 'uni-shared'
class NodesRef {
constructor (selectorQuery, component, selector, single) {
this._selectorQuery = selectorQuery
this._component = component
this._selector = selector
this._single = single
}
boundingClientRect (callback) {
this._selectorQuery._push(
this._selector,
this._component,
this._single, {
id: true,
dataset: true,
rect: true,
size: true
},
callback)
return this._selectorQuery
}
fields (fields, callback) {
this._selectorQuery._push(
this._selector,
this._component,
this._single,
fields,
callback
)
return this._selectorQuery
}
scrollOffset (callback) {
this._selectorQuery._push(
this._selector,
this._component,
this._single, {
id: true,
dataset: true,
scrollOffset: true
},
callback
)
return this._selectorQuery
}
}
function processDataset (attr) {
const dataset = {}
Object.keys(attr || {}).forEach(key => {
if (key.indexOf('data') === 0) {
let str = key.replace('data', '')
str = str.charAt(0).toLowerCase() + str.slice(1)
dataset[str] = attr[key]
}
})
return dataset
}
function findAttrs (ids, elm, result) {
let nodes = elm.children
if (!Array.isArray(nodes)) {
return false
}
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i]
if (node.attr) {
let index = ids.indexOf(node.attr.id)
if (index >= 0) {
result[index] = {
id: ids[index],
ref: node.ref,
dataset: processDataset(node.attr)
}
if (ids.length === 1) {
break
}
}
}
if (node.children) {
findAttrs(ids, node, result)
}
}
}
function getSelectors (queue) {
let ids = []
for (let i = 0; i < queue.length; i++) {
const selector = queue[i].selector
if (selector.indexOf('#') === 0) {
ids.push(selector.substring(1))
}
}
return ids
}
function getComponentRectAll (dom, attrs, index, result, callback) {
const attr = attrs[index]
dom.getComponentRect(attr.ref, option => {
option.size.id = attr.id
option.size.dataset = attr.dataset
result.push(option.size)
index += 1
if (index < attrs.length) {
getComponentRectAll(dom, attrs, index, result, callback)
} else {
callback(result)
}
})
}
function requestComponentInfo (dom, component, queue, callback) {
const selectors = getSelectors(queue)
let outAttrs = new Array(selectors.length)
findAttrs(selectors, component.$el, outAttrs)
getComponentRectAll(dom, outAttrs, 0, [], (result) => {
callback(result)
})
}
class SelectorQuery {
constructor (pageId) {
this.pageId = pageId
this._queue = []
this._queueCb = []
}
exec (callback) {
if (!this._component) {
return
}
this._dom = this._component._$weex.requireModule('dom')
requestComponentInfo(this._dom, this._component, this._queue, res => {
const queueCbs = this._queueCb
res.forEach((result, index) => {
const queueCb = queueCbs[index]
if (isFn(queueCb)) {
queueCb.call(this, result)
}
})
isFn(callback) && callback.call(this, res)
})
}
['in'] (component) {
if (!component) {
return console.warn('uni.createSelectorQuery 必须传入当前 vm 对象(this)')
}
this._component = component
return this
}
select (selector) {
return new NodesRef(this, this._component, selector, true)
}
selectAll (selector) {
return new NodesRef(this, this._component, selector, false)
}
selectViewport () {
return new NodesRef(this, 0, '', true)
}
_push (selector, component, single, fields, callback) {
this._queue.push({
component,
selector,
single,
fields
})
this._queueCb.push(callback)
}
}
export function createSelectorQuery () {
return new SelectorQuery()
}
......@@ -13,5 +13,6 @@ export {
export * from '../../../service/api/context/map'
export * from '../../../service/api/context/video'
export * from '../../../service/api/context/live-pusher'
export * from 'uni-core/service/api/base/interceptor'
export * from '../../../service/api/context/live-pusher'
export * from '../../../service/api/ui/create-selector-query'
export * from 'uni-core/service/api/base/interceptor'
......@@ -5,7 +5,6 @@ import {
} from '../util'
import {
TABBAR_HEIGHT,
TITLEBAR_HEIGHT
} from '../../constants'
......@@ -50,7 +49,7 @@ export function getSystemInfo () {
safeAreaInsets = ios ? plus.navigator.getSafeAreaInsets() : getSafeAreaInsets()
}
var windowHeight = Math.min(screenHeight - (titleNView ? (statusBarHeight + TITLEBAR_HEIGHT)
: 0) - (isTabBarPage() && tabBar.visible ? TABBAR_HEIGHT : 0), screenHeight)
: 0) - (isTabBarPage() && tabBar.visible ? tabBar.height : 0), screenHeight)
var windowWidth = screenWidth
var safeArea = {
left: safeAreaInsets.left,
......
......@@ -79,7 +79,7 @@ export function navigateBack ({
animationType,
animationDuration
}) {
const pages = getCurrentPages()
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
if (
......@@ -91,11 +91,15 @@ export function navigateBack ({
})
) {
return
}
}
uni.hideToast() // 后退时,关闭 toast,loading
currentPage.$page.meta.isQuit
? quit()
: back(delta, animationType, animationDuration)
}
return {
errMsg: 'navigateBack:ok'
}
}
......@@ -7,7 +7,8 @@ import {
} from './util'
import {
setStatusBarStyle
setStatusBarStyle,
invoke
} from '../../bridge'
import {
......@@ -18,7 +19,7 @@ import tabBar from '../../../../app-plus/service/framework/tab-bar'
export function reLaunch ({
url
}) {
}, callbackId) {
const urls = url.split('?')
const path = urls[0]
......@@ -39,7 +40,12 @@ export function reLaunch ({
openType: 'reLaunch'
}),
'none',
0
0,
() => {
invoke(callbackId, {
errMsg: 'reLaunch:ok'
})
}
)
pages.forEach(page => {
......@@ -48,4 +54,4 @@ export function reLaunch ({
})
setStatusBarStyle()
}
}
......@@ -7,7 +7,8 @@ import {
} from './util'
import {
setStatusBarStyle
setStatusBarStyle,
invoke
} from '../../bridge'
import {
......@@ -16,7 +17,7 @@ import {
export function redirectTo ({
url
}) {
}, callbackId) {
const urls = url.split('?')
const path = urls[0]
......@@ -37,8 +38,11 @@ export function redirectTo ({
0,
() => {
lastPage && lastPage.$getAppWebview().close('none')
invoke(callbackId, {
errMsg: 'redirectTo:ok'
})
}
)
setStatusBarStyle()
}
}
......@@ -47,7 +47,7 @@ export function setTabBarStyle ({
color,
selectedColor,
backgroundColor,
borderStyle
borderStyle: borderStyle === 'white' ? '#ffffff' : '#c6c6c6'
})
return {
errMsg: 'setTabBarStyle:ok'
......@@ -80,4 +80,4 @@ export function showTabBar ({
return {
errMsg: 'showTabBar:ok'
}
}
}
......@@ -12,6 +12,8 @@ import {
perf
} from './perf'
import tabBar from '../framework/tab-bar'
const pages = []
export function getCurrentPages (returnAll) {
......@@ -52,6 +54,8 @@ export function registerPage ({
if (openType === 'reLaunch' || pages.length === 0) {
// pages.length===0 表示首页触发 redirectTo
routeOptions.meta.isQuit = true
} else if (!routeOptions.meta.isTabBar) {
routeOptions.meta.isQuit = false
}
if (!webview) {
......@@ -70,8 +74,7 @@ export function registerPage ({
}
if (routeOptions.meta.isTabBar && webview.id !== '1') {
const launchWebview = plus.webview.getLaunchWebview()
launchWebview && launchWebview.append(webview)
tabBar.append(webview)
}
if (process.env.NODE_ENV !== 'production') {
......
import {
TABBAR_HEIGHT
} from '../constants'
import {
getRealPath,
isTabBarPage
getRealPath
} from '../api/util'
import safeArea from './safe-area'
import {
publish,
requireNativePlugin
} from '../bridge'
const IMAGE_TOP = 7
const IMAGE_WIDTH = 24
const IMAGE_HEIGHT = 24
const TEXT_TOP = 36
const TEXT_SIZE = 12
const TEXT_NOICON_SIZE = 17
const TEXT_HEIGHT = 12
const IMAGE_ID = 'TABITEM_IMAGE_'
const TABBAR_VIEW_ID = 'TABBAR_VIEW_'
const TABBAR_HEIGHT = 56
let view
let config
let winWidth
let itemWidth
let itemLength
let itemImageLeft
let itemRects = []
const itemIcons = []
const itemLayouts = []
const itemDot = []
const itemBadge = []
let itemClickCallback
let selected = 0
/**
* tabbar显示状态
*/
let visible = true
const init = function () {
const list = config.list
itemLength = config.list.length
calcItemLayout(list) // 计算选项卡布局
initBitmaps(list) // 初始化选项卡图标
initView()
}
let initView = function () {
const viewStyles = {
height: TABBAR_HEIGHT
}
if (config.position === 'top') {
viewStyles.top = 0
} else {
viewStyles.bottom = 0
viewStyles.height += safeArea.bottom
}
view = new plus.nativeObj.View(TABBAR_VIEW_ID, viewStyles, getDraws())
view.interceptTouchEvent(true)
view.addEventListener('click', (e) => {
if (!__uniConfig.__ready__) { // 未 ready,不允许点击
return
}
const x = e.clientX
const y = e.clientY
for (let i = 0; i < itemRects.length; i++) {
if (isCross(x, y, itemRects[i])) {
const draws = getSelectedDraws(i)
const drawTab = !!draws.length
itemClickCallback && itemClickCallback(config.list[i], i, drawTab)
if (drawTab) {
setTimeout(() => view.draw(draws))
}
break
}
}
})
plus.globalEvent.addEventListener('orientationchange', () => {
calcItemLayout(config.list)
if (config.position !== 'top') {
let height = TABBAR_HEIGHT + safeArea.bottom
view.setStyle({
height: height
})
if (visible) {
setWebviewPosition(height)
}
}
view.draw(getDraws())
})
if (!visible) {
view.hide()
}
}
let isCross = function (x, y, rect) {
if (x > rect.left && x < (rect.left + rect.width) && y > rect.top && y < (rect.top + rect.height)) {
return true
}
return false
}
let initBitmaps = function (list) {
for (let i = 0; i < list.length; i++) {
const item = list[i]
if (item.iconData) {
const bitmap = new plus.nativeObj.Bitmap(IMAGE_ID + i)
bitmap.loadBase64Data(item.iconData)
const selectedBitmap = new plus.nativeObj.Bitmap(`${IMAGE_ID}SELECTED_${i}`)
selectedBitmap.loadBase64Data(item.selectedIconData)
itemIcons[i] = {
icon: bitmap,
selectedIcon: selectedBitmap
}
} else if (item.iconPath) {
itemIcons[i] = {
icon: item.iconPath,
selectedIcon: item.selectedIconPath
}
} else {
itemIcons[i] = {
icon: false,
selectedIcon: false
}
}
}
}
let getDraws = function () {
const backgroundColor = config.backgroundColor
const borderHeight = Math.max(0.5, 1 / plus.screen.scale) // 高分屏最少0.5
const borderTop = config.position === 'top' ? (TABBAR_HEIGHT - borderHeight) : 0
const borderStyle = config.borderStyle === 'white' ? 'rgba(255,255,255,0.33)' : 'rgba(0,0,0,0.33)'
const draws = [{
id: `${TABBAR_VIEW_ID}BG`, // 背景色
tag: 'rect',
color: backgroundColor,
position: {
top: 0,
left: 0,
width: '100%',
height: TABBAR_HEIGHT + safeArea.bottom
}
}, {
id: `${TABBAR_VIEW_ID}BORDER`,
tag: 'rect',
color: borderStyle,
position: {
top: borderTop,
left: 0,
width: '100%',
height: `${borderHeight}px`
}
}]
for (let i = 0; i < itemLength; i++) {
const item = config.list[i]
if (i === selected) {
drawTabItem(draws, i, item.text, config.selectedColor, itemIcons[i].selectedIcon)
} else {
drawTabItem(draws, i, item.text, config.color, itemIcons[i].icon)
}
}
return draws
}
let getSelectedDraws = function (newSelected) {
if (selected === newSelected) {
return false
}
const draws = []
const lastSelected = selected
selected = newSelected
drawTabItem(draws, lastSelected)
drawTabItem(draws, selected)
return draws
}
/**
* 获取文字宽度(全角为1)
* @param {*} text
*/
function getFontWidth (text) {
// eslint-disable-next-line
return text.length - (text.match(/[\u0000-\u00ff]/g) || []).length / 2
}
let calcItemLayout = function () {
winWidth = plus.screen.resolutionWidth
itemWidth = winWidth / itemLength
itemImageLeft = (itemWidth - IMAGE_WIDTH) / 2
itemRects = []
let dotTop = 0
let dotLeft = 0
for (let i = 0; i < itemLength; i++) {
itemRects.push({
top: 0,
left: i * itemWidth,
width: itemWidth,
height: TABBAR_HEIGHT
})
}
for (let i = 0; i < itemLength; i++) {
const item = config.list[i]
let imgLeft = itemWidth * i + itemImageLeft
if ((item.iconData || item.iconPath) && item.text) { // 图文
itemLayouts[i] = {
text: {
top: TEXT_TOP,
left: `${i * itemWidth}px`,
width: `${itemWidth}px`,
height: TEXT_HEIGHT
},
img: {
top: IMAGE_TOP,
left: `${imgLeft}px`,
width: IMAGE_WIDTH,
height: IMAGE_HEIGHT
}
}
dotTop = IMAGE_TOP
dotLeft = imgLeft + IMAGE_WIDTH
} else if (!(item.iconData || item.iconPath) && item.text) { // 仅文字
let textLeft = i * itemWidth
itemLayouts[i] = {
text: {
top: 0,
left: `${textLeft}px`,
width: `${itemWidth}px`,
height: TABBAR_HEIGHT
}
}
dotTop = (44 - TEXT_NOICON_SIZE) / 2
dotLeft = textLeft + itemWidth * 0.5 + getFontWidth(item.text) * TEXT_NOICON_SIZE * 0.5
} else if ((item.iconData || item.iconPath) && !item.text) { // 仅图片
const diff = 10
let imgTop = (TABBAR_HEIGHT - IMAGE_HEIGHT - diff) / 2
let imgLeft = itemWidth * i + itemImageLeft - diff / 2
itemLayouts[i] = {
img: {
top: `${imgTop}px`,
left: `${imgLeft}px`,
width: IMAGE_WIDTH + diff,
height: IMAGE_HEIGHT + diff
}
}
dotTop = imgTop
dotLeft = imgLeft + IMAGE_WIDTH + diff
}
let height = itemBadge[i] ? 14 : 10
let badge = itemBadge[i] || '0'
let font = getFontWidth(badge) - 0.5
font = font > 1 ? 1 : font
let width = height + font * 12
width = width < height ? height : width
let itemLayout = itemLayouts[i]
if (itemLayout) {
itemLayout.doc = {
top: dotTop,
left: `${dotLeft - width * 0.382}px`,
width: `${width}px`,
height: `${height}px`
}
itemLayout.badge = {
top: dotTop,
left: `${dotLeft - width * 0.382}px`,
width: `${width}px`,
height: `${height}px`
}
}
}
}
let drawTabItem = function (draws, index) {
const layout = itemLayouts[index]
const item = config.list[index]
let color = config.color
let icon = itemIcons[index].icon
let dot = itemDot[index]
let badge = itemBadge[index] || ''
if (index === selected) {
color = config.selectedColor
icon = itemIcons[index].selectedIcon
}
if (icon) {
draws.push({
id: `${TABBAR_VIEW_ID}ITEM_${index}_ICON`,
tag: 'img',
position: layout.img,
src: icon
})
}
if (item.text) {
draws.push({
id: `${TABBAR_VIEW_ID}ITEM_${index}_TEXT`,
tag: 'font',
position: layout.text,
text: item.text,
textStyles: {
size: icon ? TEXT_SIZE : `${TEXT_NOICON_SIZE}px`,
color
}
})
}
const hiddenPosition = {
letf: 0,
top: 0,
width: 0,
height: 0
}
// 绘制小红点(角标背景)
draws.push({
id: `${TABBAR_VIEW_ID}ITEM_${index}_DOT`,
tag: 'rect',
position: (dot || badge) ? layout.doc : hiddenPosition,
rectStyles: {
color: '#ff0000',
radius: badge ? '7px' : '5px'
}
})
// 绘制角标文本
draws.push({
id: `${TABBAR_VIEW_ID}ITEM_${index}_BADGE`,
tag: 'font',
position: badge ? layout.badge : hiddenPosition,
text: badge || ' ',
textStyles: {
align: 'center',
verticalAlign: 'middle',
color: badge ? '#ffffff' : 'rgba(0,0,0,0)',
overflow: 'ellipsis',
size: '10px'
}
})
}
/**
* {
"color": "#7A7E83",
"selectedColor": "#3cc51f",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "page/component/index.html",
"iconData": "",
"selectedIconData": "",
"text": "组件"
}, {
"pagePath": "page/API/index.html",
"iconData": "",
"selectedIconData": "",
"text": "接口"
}],
"position":"bottom"//bottom|top
}
*/
let tabBar
/**
* 设置角标
......@@ -371,112 +25,99 @@ let drawTabItem = function (draws, index) {
* @param {string} text
*/
function setTabBarBadge (type, index, text) {
if (!tabBar) {
return
}
if (type === 'none') {
itemDot[index] = false
itemBadge[index] = ''
tabBar.hideTabBarRedDot({
index
})
tabBar.removeTabBarBadge({
index
})
} else if (type === 'text') {
itemBadge[index] = text
tabBar.setTabBarBadge({
index,
text
})
} else if (type === 'redDot') {
itemDot[index] = true
}
if (view) {
calcItemLayout(config.list)
view.draw(getDraws())
tabBar.showTabBarRedDot({
index
})
}
}
/**
* 动态设置 tabBar 某一项的内容
*/
function setTabBarItem (index, text, iconPath, selectedIconPath) {
if (iconPath || selectedIconPath) {
let itemIcon = itemIcons[index] = itemIcons[index] || {}
if (iconPath) {
itemIcon.icon = getRealPath(iconPath)
}
if (selectedIconPath) {
itemIcon.selectedIcon = getRealPath(selectedIconPath)
}
const item = {}
if (iconPath) {
item.iconPath = getRealPath(iconPath)
}
if (text) {
config.list[index].text = text
if (selectedIconPath) {
item.selectedIconPath = getRealPath(selectedIconPath)
}
view.draw(getDraws())
tabBar && tabBar.setTabBarItem(Object.assign({
index,
text
}, item))
}
/**
* 动态设置 tabBar 的整体样式
* @param {Object} style 样式
*/
function setTabBarStyle (style) {
for (const key in style) {
config[key] = style[key]
}
view.draw(getDraws())
}
/**
* 设置tab页底部或顶部距离
* @param {*} value 距离
*/
function setWebviewPosition (value) {
const position = config.position === 'top' ? 'top' : 'bottom'
plus.webview.all().forEach(webview => {
if (isTabBarPage(String(webview.__uniapp_route))) {
webview.setStyle({
[position]: value
})
}
})
tabBar && tabBar.setTabBarStyle(style)
}
/**
* 隐藏 tabBar
* @param {boolean} animation 是否需要动画效果 暂未支持
*/
function hideTabBar (animation) {
if (visible === false) {
return
}
visible = false
if (view) {
view.hide()
setWebviewPosition(0)
}
tabBar && tabBar.hideTabBar({
animation
})
}
/**
* 显示 tabBar
* @param {boolean} animation 是否需要动画效果 暂未支持
*/
function showTabBar (animation) {
if (visible === true) {
return
}
visible = true
if (view) {
view.show()
setWebviewPosition(TABBAR_HEIGHT + safeArea.bottom)
}
tabBar && tabBar.showTabBar({
animation
})
}
export default {
init (options, clickCallback) {
if (options && options.list.length) {
selected = options.selected || 0
config = options
config.position = 'bottom' // 暂时强制使用bottom
itemClickCallback = clickCallback
init()
return view
}
try {
tabBar = requireNativePlugin('uni-tabview')
} catch (error) {
console.log(`uni.requireNativePlugin("uni-tabview") error ${error}`)
}
tabBar && tabBar.onClick(({ index }) => {
clickCallback(config.list[index], index, true)
})
tabBar && tabBar.onMidButtonClick(() => {
publish('onTabBarMidButtonTap', {})
})
},
switchTab (page) {
const itemLength = config.list.length
if (itemLength) {
for (let i = 0; i < itemLength; i++) {
if (
config.list[i].pagePath === page ||
config.list[i].pagePath === `${page}.html`
) {
const draws = getSelectedDraws(i)
if (draws.length) {
view.draw(draws)
}
tabBar && tabBar.switchSelect({
index: i
})
return true
}
}
......@@ -488,7 +129,22 @@ export default {
setTabBarStyle,
hideTabBar,
showTabBar,
append (webview) {
tabBar && tabBar.append({
id: webview.id
}, ({ code }) => {
if (code !== 0) {
// console.log('tab append error')
setTimeout(() => {
this.append(webview)
}, 20)
}
})
},
get visible () {
return visible
},
get height () {
return config && config.height ? parseFloat(config.height) : TABBAR_HEIGHT
}
}
}
......@@ -15,13 +15,32 @@ export function parseTitleNView (routeOptions) {
)
) {
return false
}
const titleImage = windowOptions.titleImage || ''
const transparentTitle = windowOptions.transparentTitle || 'none'
const titleNViewTypeList = {
'none': 'default',
'auto': 'transparent',
'always': 'float'
}
const ret = {
autoBackButton: !routeOptions.meta.isQuit,
backgroundColor: windowOptions.navigationBarBackgroundColor || '#000000',
titleText: windowOptions.navigationBarTitleText || '',
titleColor: windowOptions.navigationBarTextStyle === 'black' ? '#000000' : '#ffffff'
titleText: titleImage === '' ? windowOptions.navigationBarTitleText || '' : '',
titleColor: windowOptions.navigationBarTextStyle === 'black' ? '#000000' : '#ffffff',
type: titleNViewTypeList[transparentTitle],
backgroundColor: transparentTitle !== 'always' ? windowOptions.navigationBarBackgroundColor || '#000000' : 'rgba(0,0,0,0)',
tags: titleImage === '' ? [] : [{
'tag': 'img',
'src': titleImage,
'position': {
'left': 'auto',
'top': 'auto',
'width': 'auto',
'height': '26px'
}
}]
}
routeOptions.meta.statusBarStyle = windowOptions.navigationBarTextStyle === 'black' ? 'dark' : 'light'
......
......@@ -6,10 +6,6 @@ import {
parsePullToRefresh
} from './pull-to-refresh-parser'
import {
TABBAR_HEIGHT
} from '../../../constants'
const WEBVIEW_STYLE_BLACKLIST = [
'navigationBarBackgroundColor',
'navigationBarTextStyle',
......@@ -73,10 +69,5 @@ export function parseWebviewStyle (id, path, routeOptions = {}) {
}
}
if (routeOptions.meta.isTabBar) {
webviewStyle.top = 0
webviewStyle.bottom = TABBAR_HEIGHT
}
return webviewStyle
}
}
import createCallbacks from 'uni-helpers/callbacks'
import { pixelRatio } from 'uni-helpers/hidpi'
const canvasEventCallbacks = createCallbacks('canvasEvent')
......@@ -808,8 +807,8 @@ export function canvasPutImageData ({
}
export function canvasToTempFilePath ({
x,
y,
x = 0,
y = 0,
width,
height,
destWidth,
......@@ -818,13 +817,7 @@ export function canvasToTempFilePath ({
fileType,
qualit
}, callbackId) {
if (typeof width !== 'undefined') {
width *= pixelRatio
}
if (typeof height !== 'undefined') {
height *= pixelRatio
}
var pageId
let pageId
const app = getApp()
if (app.$route && app.$route.params.__id__) {
pageId = app.$route.params.__id__
......@@ -834,37 +827,39 @@ export function canvasToTempFilePath ({
})
return
}
var cId = canvasEventCallbacks.push(function (data) {
var imgData = data.data
if (!imgData || !imgData.length) {
const cId = canvasEventCallbacks.push(function ({
data,
width,
height
}) {
if (!data || !data.length) {
invoke(callbackId, {
errMsg: 'canvasToTempFilePath:fail'
})
return
}
let imgData
try {
imgData = new ImageData(new Uint8ClampedArray(imgData), data.width, data.height)
imgData = new ImageData(new Uint8ClampedArray(data), width, height)
} catch (error) {
invoke(callbackId, {
errMsg: 'canvasToTempFilePath:fail'
})
return
}
var canvas = getTempCanvas()
canvas.width = data.width
canvas.height = data.height
var c2d = canvas.getContext('2d')
const canvas = getTempCanvas()
canvas.width = width
canvas.height = height
const c2d = canvas.getContext('2d')
c2d.putImageData(imgData, 0, 0)
var base64 = canvas.toDataURL('image/png')
var img = new Image()
let base64 = canvas.toDataURL('image/png')
const img = new Image()
img.onload = function () {
var width = canvas.width = typeof destWidth === 'number' ? destWidth : imgData.width * pixelRatio
var height = canvas.height = typeof destHeight === 'number' ? destHeight : imgData.height * pixelRatio
if (fileType === 'jpeg') {
c2d.fillStyle = '#fff'
c2d.fillRect(0, 0, width, height)
c2d.fillRect(0, 0, width, width)
}
c2d.drawImage(img, 0, 0, img.width, img.height, 0, 0, width, height)
c2d.drawImage(img, 0, 0)
base64 = canvas.toDataURL(`image/${fileType}`, qualit)
invoke(callbackId, {
errMsg: 'canvasToTempFilePath:ok',
......@@ -878,6 +873,9 @@ export function canvasToTempFilePath ({
y,
width,
height,
destWidth,
destHeight,
hidpi: false,
callbackId: cId
})
}
......@@ -7934,6 +7934,10 @@ shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
shell-exec@^1.0.2:
version "1.0.2"
resolved "https://registry.npm.taobao.org/shell-exec/download/shell-exec-1.0.2.tgz#2e9361b0fde1d73f476c4b6671fa17785f696756"
shell-quote@^1.6.1:
version "1.6.1"
resolved "https://registry.npm.taobao.org/shell-quote/download/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册