未验证 提交 4e3453be 编写于 作者: C changan12 提交者: GitHub

Merge pull request #2 from dcloudio/master

update from dcloudio master
...@@ -6,7 +6,7 @@ root = true ...@@ -6,7 +6,7 @@ root = true
[*] [*]
charset = utf-8 charset = utf-8
indent_style = space indent_style = space
indent_size = 4 indent_size = 2
end_of_line = lf end_of_line = lf
insert_final_newline = true insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true
......
src/core/helpers/html-parser.js src/core/helpers/html-parser.js
\ No newline at end of file src/platforms/app-plus-nvue/runtime
build/rollup-plugin-require-context
packages/*/packages
node_modules/ node_modules/
.project .project
unpackage/ unpackage/
.vscode/ .vscode/
\ No newline at end of file .DS_Store
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
## 扫码体验 ## 扫码体验
一套代码编译到7个平台,开发一次、多处运行,这不是梦想,而是现实。依次扫描7个二维码,亲自体验最全面的跨平台效果! 一套代码编译到8个平台,开发一次、多处运行,这不是梦想,而是现实。依次扫描8个二维码,亲自体验最全面的跨平台效果!
<img src="http://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/barcode-20190131.png"/> <img src="https://img-cdn-qiniu.dcloud.net.cn/uni-app-qr-all.jpg"/>
*注: Appstore、百度、头条平台不能提交简单demo,故iOS、百度小程序、头条小程序版补充了一些其他功能。* *注: Appstore、百度、头条平台不能提交简单demo,故iOS、百度小程序、头条小程序版补充了一些其他功能。*
...@@ -29,13 +29,17 @@ ...@@ -29,13 +29,17 @@
## 项目案例 ## 项目案例
案例:[uniapp.dcloud.io/case](https://uniapp.dcloud.io/case) 案例展示[uniapp.dcloud.io/case](https://uniapp.dcloud.io/case)
欢迎广大开发者踊跃提交自己的应用案例[uni-app案例征集](https://github.com/dcloudio/uni-app/issues/6) 欢迎提交你的应用[uni-app案例征集](https://github.com/dcloudio/uni-app/issues/6)
## 需求墙 ## 需求墙
`uni-app`计划支持的功能点,会在需求墙上进行展示,并允许开发者对需求进行投票,[前往投票](https://dev.dcloud.net.cn/wish/) `uni-app`计划支持的功能点,会在需求墙上进行展示,征集开发者的投票意见,[前往投票](https://dev.dcloud.net.cn/wish/)
## 更新日志
`uni-app`一直保持高频的更新迭代,详见[uni-app 更新日志](docs/release.md)
## 论坛 ## 论坛
......
module.exports = { const config = {
ignore: [ ignore: [
"./packages", "./packages",
], ],
presets: [ presets: [
["@vue/app", { ["@vue/app", {
useBuiltIns: "entry" useBuiltIns: "entry"
}] }]
] ],
plugins: [require('./lib/babel-plugin-uni-api/index.js')]
}
if (process.env.NODE_ENV === 'test') {
delete config.ignore
} }
module.exports = config
...@@ -9,9 +9,15 @@ const copy = require('copy') ...@@ -9,9 +9,15 @@ const copy = require('copy')
const path = require('path') const path = require('path')
const jsonfile = require('jsonfile') const jsonfile = require('jsonfile')
const {
generateApiManifest
} = require('./manifest')
const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd(), { const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd(), {
inlineOptions: require('./vue.config.js') inlineOptions: require('./vue.config.js')
}) })
// 删除 cache 目录
del.sync(['node_modules/.cache'])
service.run('build', { service.run('build', {
name: 'index', name: 'index',
...@@ -19,6 +25,11 @@ service.run('build', { ...@@ -19,6 +25,11 @@ service.run('build', {
target: 'lib', target: 'lib',
formats: process.env.UNI_WATCH === 'true' ? 'umd' : 'umd-min', formats: process.env.UNI_WATCH === 'true' ? 'umd' : 'umd-min',
entry: './lib/' + process.env.UNI_PLATFORM + '/main.js' entry: './lib/' + process.env.UNI_PLATFORM + '/main.js'
}).then(function () {
generateApiManifest(
JSON.parse(JSON.stringify(process.UNI_SERVICE_API_MANIFEST)),
JSON.parse(JSON.stringify(process.UNI_SERVICE_API_PROTOCOL))
)
}).catch(err => { }).catch(err => {
error(err) error(err)
process.exit(1) process.exit(1)
...@@ -44,9 +55,11 @@ if (process.env.UNI_WATCH === 'false') { ...@@ -44,9 +55,11 @@ if (process.env.UNI_WATCH === 'false') {
}) })
}) })
.then(obj => { .then(obj => {
return jsonfile.writeFile(packageJsonPath, obj, { spaces: 2 }) return jsonfile.writeFile(packageJsonPath, obj, {
spaces: 2
})
}) })
.catch(err => { .catch(err => {
throw err throw err
}) })
} }
const fs = require('fs')
const path = require('path')
const apis = require('../lib/apis')
const AUTO_LOADS = [
'upx2px',
'canIUse',
'getSystemInfo',
'getSystemInfoSync',
'navigateTo',
'redirectTo',
'switchTab',
'reLaunch',
'navigateBack'
]
const TOAST_DEPS = [
['/platforms/h5/components/app/popup/toast.vue', 'Toast'],
['/platforms/h5/components/app/popup/mixins/toast.js', 'ToastMixin']
]
// TODO 暂不考虑 head,tabBar 的动态拆分
const DEPS = {
'chooseLocation': [
['/platforms/h5/components/system-routes/choose-location/index.vue', 'ChooseLocation']
],
'openLocation': [
['/platforms/h5/components/system-routes/open-location/index.vue', 'OpenLocation']
],
'previewImage': [
['/platforms/h5/components/system-routes/preview-image/index.vue', 'PreviewImage']
],
'showToast': TOAST_DEPS,
'hideToast': TOAST_DEPS,
'showLoading': TOAST_DEPS,
'hideLoading': TOAST_DEPS,
'showModal': [
['/platforms/h5/components/app/popup/modal.vue', 'Modal'],
['/platforms/h5/components/app/popup/mixins/modal.js', 'ModalMixin']
],
'showActionSheet': [
['/platforms/h5/components/app/popup/actionSheet.vue', 'ActionSheet'],
['/platforms/h5/components/app/popup/mixins/action-sheet.js', 'ActionSheetMixin']
],
'createSelectorQuery': [
['/core/view/bridge/subscribe/api/request-component-info.js', 'requestComponentInfo']
],
'createIntersectionObserver': [
['/core/view/bridge/subscribe/api/request-component-observer.js', 'requestComponentObserver'],
['/core/view/bridge/subscribe/api/request-component-observer.js', 'destroyComponentObserver']
]
}
// 检查依赖文件是否存在
Object.keys(DEPS).reduce(function (depFiles, name) {
DEPS[name].forEach(function (dep) {
depFiles.add(dep[0])
})
return depFiles
}, new Set()).forEach(file => {
if (!fs.existsSync(path.join(__dirname, '../src', file))) {
console.error(file + ' 不存在')
process.exit(0)
}
})
function parseApiManifestDeps (manifest, protocol) {
// 解析 platform 依赖
Object.keys(manifest).forEach(name => {
const deps = manifest[name][1]
if (deps.length) {
deps.forEach(dep => {
if (manifest[dep[1]]) {
dep[0] = manifest[dep[1]][0]
} else {
console.error(`依赖模块[${dep[1]}]不存在,删除 ${name} 接口\n`)
delete manifest[name]
}
})
}
})
// 解析 protocol 依赖
Object.keys(manifest).forEach(name => {
const deps = manifest[name][1]
if (protocol[name]) {
deps.push([protocol[name], name])
} else {
console.warn(`${name} 缺少 protocol`)
}
})
// 追加默认依赖
Object.keys(DEPS).forEach(name => {
if (manifest[name]) {
manifest[name][1].push(...DEPS[name])
} else {
console.error(`缺少 ${name}`)
}
})
// 设置自动加载标记
AUTO_LOADS.forEach(name => {
if (manifest[name]) {
manifest[name][2] = true
} else {
console.error(`缺少 ${name}`)
}
})
}
module.exports = {
generateApiManifest (manifest, protocol) {
if (!Object.keys(manifest).length) {
throw new Error('api manifest.json 生成失败')
}
parseApiManifestDeps(manifest, protocol)
const manifestJson = Object.create(null)
const todoApis = []
apis.forEach(name => {
if (manifest[name]) {
manifestJson[name] = manifest[name]
} else {
todoApis.push(name)
}
})
if (todoApis.length) {
console.log('\n')
console.warn(`${process.env.UNI_PLATFORM} 平台缺少以下 API 实现(共 ${todoApis.length} 个)`)
todoApis.forEach(name => {
console.warn(name)
})
}
fs.writeFileSync(path.resolve(__dirname, '../packages/uni-' + process.env.UNI_PLATFORM + '/manifest.json'),
JSON.stringify(manifestJson, null, 4)
)
}
}
const path = require('path')
const alias = require('rollup-plugin-alias')
const replace = require('rollup-plugin-replace')
const nodeResolve = require('rollup-plugin-node-resolve')
const commonjs = require('rollup-plugin-commonjs')
const requireContext = require('../lib/rollup-plugin-require-context')
let input = 'src/platforms/app-plus/service/framework/create-instance-context.js'
const output = {
file: 'packages/uni-app-plus-nvue/dist/index.js',
format: 'es'
}
const external = []
if (process.env.UNI_SERVICE === 'legacy') {
input = 'src/platforms/app-plus-nvue/services/index.legacy.js'
output.file = 'packages/uni-app-plus-nvue/dist/index.legacy.js'
} else {
input = 'src/platforms/app-plus/service/index.js'
output.file = 'packages/uni-app-plus-nvue/dist/index.js'
output.format = 'iife'
output.name = 'serviceContext'
output.banner =
`export function createServiceContext(Vue, weex, plus, __uniConfig, __uniRoutes, UniServiceJSBridge,instanceContext){
var localStorage = plus.storage
var setTimeout = instanceContext.setTimeout
var clearTimeout = instanceContext.clearTimeout
var setInterval = instanceContext.setInterval
var clearInterval = instanceContext.clearInterval
`
output.footer =
`
var uni = serviceContext.uni
var getApp = serviceContext.getApp
var getCurrentPages = serviceContext.getCurrentPages
var __registerPage = serviceContext.__registerPage
return serviceContext \n}
`
}
const resolve = dir => path.resolve(__dirname, '../', dir)
module.exports = {
input,
output,
plugins: [
nodeResolve(),
commonjs(),
requireContext(),
alias({
'uni-core': resolve('src/core'),
'uni-platform': resolve('src/platforms/' + process.env.UNI_PLATFORM),
'uni-platforms': resolve('src/platforms'),
'uni-shared': resolve('src/shared/index.js'),
'uni-helpers': resolve('src/core/helpers'),
'uni-invoke-api': resolve('src/platforms/app-plus/service/api'),
'uni-service-api': resolve('src/core/service/platform-api'),
'uni-api-protocol': resolve('src/core/helpers/protocol')
}),
replace({
__GLOBAL__: 'getGlobalUni()',
__PLATFORM__: JSON.stringify('app-plus'),
__PLATFORM_TITLE__: 'app-plus-nvue'
})
],
external
}
...@@ -6,10 +6,10 @@ const PLATFORMS = { ...@@ -6,10 +6,10 @@ const PLATFORMS = {
'mp-weixin': { 'mp-weixin': {
prefix: 'wx', prefix: 'wx',
title: '微信小程序' title: '微信小程序'
}, },
'mp-qq': { 'mp-qq': {
prefix: 'wx', prefix: 'wx',
title: 'QQ小程序' title: 'QQ小程序'
}, },
'mp-alipay': { 'mp-alipay': {
prefix: 'my', prefix: 'my',
...@@ -40,8 +40,8 @@ module.exports = { ...@@ -40,8 +40,8 @@ module.exports = {
plugins: [ plugins: [
alias({ alias({
'uni-shared': path.resolve(__dirname, '../src/shared/util.js'), 'uni-shared': path.resolve(__dirname, '../src/shared/util.js'),
'uni-platform': path.resolve(__dirname, '../src/platforms/' + process.env.UNI_PLATFORM), 'uni-platform': path.resolve(__dirname, '../src/platforms/' + process.env.UNI_PLATFORM),
'uni-wrapper': path.resolve(__dirname, '../src/core/runtime/wrapper'), 'uni-wrapper': path.resolve(__dirname, '../src/core/runtime/wrapper'),
'uni-helpers': path.resolve(__dirname, '../src/core/helpers') 'uni-helpers': path.resolve(__dirname, '../src/core/helpers')
}), }),
replace({ replace({
......
const path = require('path')
const alias = require('rollup-plugin-alias')
const replace = require('rollup-plugin-replace')
module.exports = {
input: 'src/platforms/app-plus-nvue/services/index.legacy.js',
output: {
file: `packages/uni-app-plus-nvue/dist/service.legacy.js`,
format: 'es'
},
plugins: [
alias({
'uni-core': path.resolve(__dirname, '../src/core'),
'uni-shared': path.resolve(__dirname, '../src/shared/util.js')
}),
replace({
__GLOBAL__: 'getGlobalUni()',
__PLATFORM_TITLE__: 'app-plus-nvue'
})
]
}
module.exports = {
input: 'packages/uni-stat/src/index.js',
output: {
file: 'packages/uni-stat/dist/index.js',
format: 'es'
},
external: ['vue', '../package.json'],
plugins: []
}
...@@ -29,7 +29,16 @@ module.exports = { ...@@ -29,7 +29,16 @@ module.exports = {
'uni-mixins': resolve('src/core/view/mixins'), 'uni-mixins': resolve('src/core/view/mixins'),
'uni-helpers': resolve('src/core/helpers'), 'uni-helpers': resolve('src/core/helpers'),
'uni-platform': resolve('src/platforms/' + process.env.UNI_PLATFORM), 'uni-platform': resolve('src/platforms/' + process.env.UNI_PLATFORM),
'uni-components': resolve('src/core/view/components') // tree shaking
'uni-components': resolve('src/core/view/components'),
'uni-invoke-api': resolve('src/platforms/' + process.env.UNI_PLATFORM + '/service/api'),
'uni-service-api': resolve('src/core/service/platform-api'),
'uni-api-protocol': resolve('src/core/helpers/protocol'),
'uni-api-subscribe': resolve('src/core/view/bridge/subscribe/api/index'),
// h5 components
'uni-h5-app-components': resolve('src/platforms/h5/components/app/popup/index'),
'uni-h5-app-mixins': resolve('src/platforms/h5/components/app/popup/mixins/index'),
'uni-h5-system-routes': resolve('src/platforms/h5/components/system-routes/index')
} }
}, },
module: { module: {
...@@ -42,8 +51,8 @@ module.exports = { ...@@ -42,8 +51,8 @@ module.exports = {
}), }),
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
'console': [resolve('src/core/helpers/console'), 'default'], 'console': [resolve('src/core/helpers/console'), 'default'],
'UniViewJSBridge': [resolve('src/core/view/bridge')], 'UniViewJSBridge': [resolve('src/core/view/bridge/index')],
'UniServiceJSBridge': [resolve('src/core/service/bridge')] 'UniServiceJSBridge': [resolve('src/core/service/bridge/index')]
}) })
] ]
} }
...@@ -23,7 +23,16 @@ config.resolve.alias = { ...@@ -23,7 +23,16 @@ config.resolve.alias = {
'uni-mixins': resolve('src/core/view/mixins'), 'uni-mixins': resolve('src/core/view/mixins'),
'uni-helpers': resolve('src/core/helpers'), 'uni-helpers': resolve('src/core/helpers'),
'uni-platform': resolve('src/platforms/' + process.env.UNI_PLATFORM), 'uni-platform': resolve('src/platforms/' + process.env.UNI_PLATFORM),
'uni-components': resolve('src/core/view/components') // tree shaking
'uni-components': resolve('src/core/view/components'),
'uni-invoke-api': resolve('src/platforms/' + process.env.UNI_PLATFORM + '/service/api'),
'uni-service-api': resolve('src/core/service/platform-api'),
'uni-api-protocol': resolve('src/core/helpers/protocol'),
'uni-api-subscribe': resolve('src/core/view/bridge/subscribe/api/index'),
// h5 components
'uni-h5-app-components': resolve('src/platforms/h5/components/app/popup/index'),
'uni-h5-app-mixins': resolve('src/platforms/h5/components/app/popup/mixins/index'),
'uni-h5-system-routes': resolve('src/platforms/h5/components/system-routes/index')
} }
const isEslintLoader = config.module.rules[config.module.rules.length - 1].enforce const isEslintLoader = config.module.rules[config.module.rules.length - 1].enforce
...@@ -41,8 +50,8 @@ config.plugins = config.plugins.concat([ ...@@ -41,8 +50,8 @@ config.plugins = config.plugins.concat([
}), }),
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
'console': [resolve('src/core/helpers/console'), 'default'], 'console': [resolve('src/core/helpers/console'), 'default'],
'UniViewJSBridge': [resolve('src/core/view/bridge')], 'UniViewJSBridge': [resolve('src/core/view/bridge/index')],
'UniServiceJSBridge': [resolve('src/core/service/bridge')] 'UniServiceJSBridge': [resolve('src/core/service/bridge/index')]
}) })
]) ])
module.exports = config module.exports = config
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<div class="quick"> <div class="quick">
<h3 id="快速体验"><a href="/README?id=%e5%bf%ab%e9%80%9f%e4%bd%93%e9%aa%8c" data-id="快速体验" class="anchor"><span>快速体验</span></a></h3> <h3 id="快速体验"><a href="/README?id=%e5%bf%ab%e9%80%9f%e4%bd%93%e9%aa%8c" data-id="快速体验" class="anchor"><span>快速体验</span></a></h3>
<p>一套代码编到7个平台,这不是梦想。眼见为实,扫描7个二维码,亲自体验最全面的跨平台效果!</p> <p>一套代码编到8个平台,这不是梦想。眼见为实,扫描8个二维码,亲自体验最全面的跨平台效果!</p>
<div class="flex-img-group-view"> <div class="flex-img-group-view">
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> <a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view">
<div class="barcode-img-box"> <div class="barcode-img-box">
...@@ -45,6 +45,12 @@ ...@@ -45,6 +45,12 @@
</div> </div>
<b>头条小程序版</b> <b>头条小程序版</b>
</a> </a>
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view">
<div class="barcode-img-box">
<img src="http://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/hello-uni-qq.png" width="160"/>
</div>
<b>QQ小程序版</b>
</a>
</div> </div>
<p> <p>
<em>注:Appstore、百度、头条平台不能提交简单demo,故补充了一些其他功能。</em></br> <em>注:Appstore、百度、头条平台不能提交简单demo,故补充了一些其他功能。</em></br>
...@@ -148,10 +154,10 @@ ...@@ -148,10 +154,10 @@
### 一套代码,运行到多个平台 ### 一套代码,运行到多个平台
```uni-app```实现了一套代码,同时运行到多个平台;如下图所示,一套代码,同时运行到iOS模拟器、Android模拟器、H5、微信开发者工具、支付宝小程序Studio、百度开发者工具、字节跳动开发者工具(底部7个终端选项卡代表7个终端模拟器): ```uni-app```实现了一套代码,同时运行到多个平台;如下图所示,一套代码,同时运行到iOS模拟器、Android模拟器、H5、微信开发者工具、支付宝小程序Studio、百度开发者工具、字节跳动开发者工具、QQ开发者工具(底部8个终端选项卡代表8个终端模拟器):
![](http://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/dev1x7.png) ![](https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/dev1x8.jpg)
实际运行效果如下(点击图片可放大): 实际运行效果如下(点击图片可放大):
![](http://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/run1x7.png) ![](https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/run1x8.jpg)
...@@ -250,6 +250,7 @@ function async request () { ...@@ -250,6 +250,7 @@ function async request () {
|API|说明| |API|说明|
|:-|:-| |:-|:-|
|[uni.vibrate](api/system/vibrate?id=vibrate)|使手机发生振动|
|[uni.vibrateLong](api/system/vibrate?id=vibratelong)|使手机发生较长时间的振动| |[uni.vibrateLong](api/system/vibrate?id=vibratelong)|使手机发生较长时间的振动|
|[uni.vibrateShort](api/system/vibrate?id=vibrateshort)|使手机发生较短时间的振动| |[uni.vibrateShort](api/system/vibrate?id=vibrateshort)|使手机发生较短时间的振动|
##### 手机联系人 ##### 手机联系人
......
* 基础 * 基础
* [日志打印](api/log.md) * [日志打印](api/log.md)
* [uni.base64ToArrayBuffer](api/base64ToArrayBuffer?id=base64toarraybuffer) * [uni.base64ToArrayBuffer](api/base64ToArrayBuffer?id=base64toarraybuffer)
* [uni.arrayBufferToBase64](api/arrayBufferToBase64?id=arraybuffertobase64) * [uni.arrayBufferToBase64](api/arrayBufferToBase64?id=arraybuffertobase64)
* [定时器](api/timer.md) * [定时器](api/timer.md)
* [生命周期](api/lifetime.md) * [生命周期](api/lifetime.md)
* 网络 * 网络
* [发起请求](api/request/request.md) * [发起请求](api/request/request.md)
* [上传、下载](api/request/network-file.md) * [上传、下载](api/request/network-file.md)
* [WebSocket](api/request/websocket.md) * [WebSocket](api/request/websocket.md)
* [SocketTask](api/request/socket-task.md) * [SocketTask](api/request/socket-task.md)
* [mDNS](api/request/mDNS.md) * [mDNS](api/request/mDNS.md)
* [UDP 通信](api/request/UDP.md) * [UDP 通信](api/request/UDP.md)
* 路由与页面跳转 * 路由与页面跳转
* [uni.navigateTo](/api/router?id=navigateto) * [uni.navigateTo](/api/router?id=navigateto)
...@@ -41,8 +41,8 @@ ...@@ -41,8 +41,8 @@
* [视频](api/media/video.md) * [视频](api/media/video.md)
* [视频组件控制](api/media/video-context.md) * [视频组件控制](api/media/video-context.md)
* [相机组件控制](api/media/camera-context.md) * [相机组件控制](api/media/camera-context.md)
* [直播组件控制](api/media/live-player-context.md) * [直播组件控制](api/media/live-player-context.md)
* [富文本](api/media/editor-context.md) * [富文本](api/media/editor-context.md)
* 设备 * 设备
* [系统信息](api/system/info.md) * [系统信息](api/system/info.md)
* [内存](api/system/memory.md) * [内存](api/system/memory.md)
...@@ -56,17 +56,18 @@ ...@@ -56,17 +56,18 @@
* [屏幕](api/system/brightness.md) * [屏幕](api/system/brightness.md)
* [用户截屏事件](api/system/capture-screen.md) * [用户截屏事件](api/system/capture-screen.md)
* [振动](api/system/vibrate.md) * [振动](api/system/vibrate.md)
* [手机联系人](api/system/contact.md) * [手机联系人](api/system/contact.md)
* [蓝牙](api/system/bluetooth.md) * [蓝牙](api/system/bluetooth.md)
* [低功耗蓝牙](api/system/ble.md) * [低功耗蓝牙](api/system/ble.md)
* [iBeacon](api/system/ibeacon.md) * [iBeacon](api/system/ibeacon.md)
* [Wi-Fi](api/system/wifi.md) * [Wi-Fi](api/system/wifi.md)
* [电量](api/system/batteryInfo.md) * [电量](api/system/batteryInfo.md)
* [NFC](api/system/nfc.md) * [NFC](api/system/nfc.md)
* [设备方向](api/system/deviceMotion.md) * [设备方向](api/system/deviceMotion.md)
* [Worker](api/worder.md) * [Worker](api/worder.md)
* 键盘 * 键盘
* [uni.hideKeyboard](/api/key?id=hidekeyboard) * [uni.hideKeyboard](/api/key?id=hidekeyboard)
* [uni.onKeyboardHeightChange](/api/key?id=onkeyboardheightchange)
* 界面 * 界面
* [交互反馈](api/ui/prompt.md) * [交互反馈](api/ui/prompt.md)
* [设置导航条](api/ui/navigationbar.md) * [设置导航条](api/ui/navigationbar.md)
...@@ -78,22 +79,22 @@ ...@@ -78,22 +79,22 @@
* [字体](api/ui/font.md) * [字体](api/ui/font.md)
* [下拉刷新](api/ui/pulldown.md) * [下拉刷新](api/ui/pulldown.md)
* [节点信息](api/ui/nodes-info.md) * [节点信息](api/ui/nodes-info.md)
* [节点布局相交状态](api/ui/intersection-observer.md) * [节点布局相交状态](api/ui/intersection-observer.md)
* [自定义组件](api/ui/nextTick.md) * [自定义组件](api/ui/nextTick.md)
* [菜单](api/ui/menuButton.md) * [菜单](api/ui/menuButton.md)
* 页面和窗体 * 页面和窗体
* [页面](api/window/window.md) * [页面](api/window/window.md)
* [页面通讯](api/window/communication.md) * [页面通讯](api/window/communication.md)
* [subNVue原生子窗体](api/window/subNVues.md) * [subNVue原生子窗体](api/window/subNVues.md)
* 文件 * 文件
* [uni.saveFile](/api/file/file?id=savefile) * [uni.saveFile](/api/file/file?id=savefile)
* [uni.getSavedFileList](/api/file/file?id=getSavedFileList) * [uni.getSavedFileList](/api/file/file?id=getSavedFileList)
* [uni.getSavedFileInfo](/api/file/file?id=getSavedFileInfo) * [uni.getSavedFileInfo](/api/file/file?id=getSavedFileInfo)
* [uni.removeSavedFile](/api/file/file?id=removeSavedFile) * [uni.removeSavedFile](/api/file/file?id=removeSavedFile)
* [uni.getFileInfo](/api/file/file?id=getFileInfo) * [uni.getFileInfo](/api/file/file?id=getFileInfo)
* [uni.openDocument](/api/file/file?id=openDocument) * [uni.openDocument](/api/file/file?id=openDocument)
* [uni.getFileSystemManager](/api/file/getFileSystemManager) * [uni.getFileSystemManager](/api/file/getFileSystemManager)
* 绘画 * 绘画
* [uni.createOffscreenCanvas](api/canvas/createOffscreenCanvas.md) * [uni.createOffscreenCanvas](api/canvas/createOffscreenCanvas.md)
* [uni.createCanvasContext](api/canvas/createCanvasContext.md) * [uni.createCanvasContext](api/canvas/createCanvasContext.md)
* [uni.canvasToTempFilePath](api/canvas/canvasToTempFilePath.md) * [uni.canvasToTempFilePath](api/canvas/canvasToTempFilePath.md)
...@@ -115,16 +116,16 @@ ...@@ -115,16 +116,16 @@
* [设置](api/other/setting.md) * [设置](api/other/setting.md)
* [收货地址](api/other/choose-address.md) * [收货地址](api/other/choose-address.md)
* [获取发票抬头](api/other/invoice-title.md) * [获取发票抬头](api/other/invoice-title.md)
* [小程序跳转](api/other/open-miniprogram.md) * [小程序跳转](api/other/open-miniprogram.md)
* [账号信息](api/other/getAccountInfoSync.md) * [账号信息](api/other/getAccountInfoSync.md)
* [生物认证(指纹及人脸识别)](api/other/authentication.md) * [生物认证(指纹及人脸识别)](api/other/authentication.md)
* [运动(计步器)](api/other/sport.md) * [运动(计步器)](api/other/sport.md)
* [统计](api/other/report.md) * [统计](api/other/report.md)
* [卡券](api/other/card.md) * [卡券](api/other/card.md)
* [模板消息](api/other/template.md) * [模板消息](api/other/template.md)
* [小程序更新](api/other/update.md) * [小程序更新](api/other/update.md)
* [调试](api/other/set-enable-debug.md) * [调试](api/other/set-enable-debug.md)
* [获取第三方平台数据](api/other/get-extconfig.md) * [获取第三方平台数据](api/other/get-extconfig.md)
* [广告](api/other/advertisement.md) * [广告](api/other/advertisement.md)
<li></li> <li></li>
<div class="contact-box"> <div class="contact-box">
...@@ -145,43 +146,44 @@ ...@@ -145,43 +146,44 @@
<div class="contact-item"> <div class="contact-item">
<img src="//img-cdn-qiniu.dcloud.net.cn/uniapp/doc/qq@2x.png" width="20" height="20"/> <img src="//img-cdn-qiniu.dcloud.net.cn/uniapp/doc/qq@2x.png" width="20" height="20"/>
<div class="contact-smg"> <div class="contact-smg">
<div>官方QQ交流群</div> <div>官方QQ交流群</div>
<div>群26:147867597 &nbsp;<a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=28a1a9a3e8f1866ee6a5f2b1caba05039e30d3ae1461e64b2ec31c095fcab951">点此加入</a></div> <div>群26:147867597 &nbsp;<a target="_blank" href="//shang.qq.com/wpa/qunwpa?id
<div>群35:713420817(2000人已满)</div> =28a1a9a3e8f1866ee6a5f2b1caba05039e30d3ae1461e64b2ec31c095fcab951">点此加入</a></div>
<div>群34:530305531(2000人已满)</div> <div>群35:713420817(2000人已满)</div>
<div>群33:498071674(2000人已满)</div> <div>群34:530305531(2000人已满)</div>
<div>群32:166188631(500人已满)</div> <div>群33:498071674(2000人已满)</div>
<div>群31:567471669(500人已满)</div> <div>群32:166188631(500人已满)</div>
<div>群30:371046920(500人已满)</div> <div>群31:567471669(500人已满)</div>
<div>群29:202965481(500人已满)</div> <div>群30:371046920(500人已满)</div>
<div>群28:166188776(2000人已满 </div> <div>群29:202965481(500人已满)</div>
<div>群27:811363410(2000人已满 </div> <div>群28:166188776(2000人已满 </div>
<!-- <div>群26:147867597(2000人已满)</div> --> <div>群27:811363410(2000人已满 </div>
<div>群25:165297000(500人已满)</div> <!-- <div>群26:147867597(2000人已满)</div> -->
<div>群24:672494800(500人已满)</div> <div>群25:165297000(500人已满)</div>
<div>群23:599958679(500人已满)</div> <div>群24:672494800(500人已满)</div>
<div>群22:687186952(1000人已满)</div> <div>群23:599958679(500人已满)</div>
<div>群21:717019120(2000人已满)</div> <div>群22:687186952(1000人已满)</div>
<div>群20:165796402(500人已满)</div> <div>群21:717019120(2000人已满)</div>
<div>群19:165657124(1000人已满)</div> <div>群20:165796402(500人已满)</div>
<div>群18:698592271(500人已满)</div> <div>群19:165657124(1000人已满)</div>
<div>群17:951348804(1000人已满)</div> <div>群18:698592271(500人已满)</div>
<div>群16:719211033(1000人已满)</div> <div>群17:951348804(1000人已满)</div>
<div>群15:516984120(500人已满)</div> <div>群16:719211033(1000人已满)</div>
<div>群14:465953250(500人已满)</div> <div>群15:516984120(500人已满)</div>
<div>群13:699478442(500人已满)</div> <div>群14:465953250(500人已满)</div>
<div>群12:884860657(500人已满)</div> <div>群13:699478442(500人已满)</div>
<div>群11:296811328(1000人已满)</div> <div>群12:884860657(500人已满)</div>
<div>群10:959059626(2000人已满)</div> <div>群11:296811328(1000人已满)</div>
<div>群9:775128777(500人已满)</div> <div>群10:959059626(2000人已满)</div>
<div>群8:695442854(500人已满)</div> <div>群9:775128777(500人已满)</div>
<div>群7:942061423(500人已满)</div> <div>群8:695442854(500人已满)</div>
<div>群6:697264024(2000人已满)</div> <div>群7:942061423(500人已满)</div>
<div>群5:731951419(500人已满)</div> <div>群6:697264024(2000人已满)</div>
<div>群4:942702595(1000人已满)</div> <div>群5:731951419(500人已满)</div>
<div>群3:773794803(1000人已满) </div> <div>群4:942702595(1000人已满)</div>
<div>群2:901474938(1000人已满) </div> <div>群3:773794803(1000人已满) </div>
<div>群1:531031261(1000人已满)</div> <div>群2:901474938(1000人已满) </div>
<div>群1:531031261(1000人已满)</div>
</div> </div>
</div> </div>
<div class="contact-item"> <div class="contact-item">
...@@ -191,4 +193,4 @@ ...@@ -191,4 +193,4 @@
<img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/weixin.jpg" width="90" height="90"/> <img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/weixin.jpg" width="90" height="90"/>
</div> </div>
</div> </div>
</div> </div>
\ No newline at end of file
#### uni.hideKeyboard() #### uni.hideKeyboard()
隐藏软键盘 隐藏软键盘
隐藏已经显示的软键盘,如果软键盘没有显示则不做任何操作。
**平台差异说明** **平台差异说明**
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序| |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|QQ小程序|
|:-:|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|√|√|√|√|x|√| |√|√|√|√|x|√|√|
隐藏已经显示的软键盘,如果软键盘没有显示则不做任何操作。
#### uni.onKeyboardHeightChange(CALLBACK)
监听键盘高度变化
**平台差异说明**
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|QQ小程序|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|HBuilderX 2.2.3+|x|基础库2.7+|x|x|x|√|
**CALLBACK 返回参数**
|参数|类型|说明|
|:-|:-|:-|
|height|Number|键盘高度|
**示例代码**
```js
uni.onKeyboardHeightChange(res => {
console.log(res.height)
})
```
### uni.chooseImage(OBJECT) ### uni.chooseImage(OBJECT)
从本地相册选择图片或使用相机拍照。另外选择和上传非图像、视频文件参考:[https://ask.dcloud.net.cn/article/35547](https://ask.dcloud.net.cn/article/35547) 从本地相册选择图片或使用相机拍照。
另外选择和上传非图像、视频文件参考:[https://ask.dcloud.net.cn/article/35547](https://ask.dcloud.net.cn/article/35547)
App端如需要更丰富的相机拍照API(如直接调用前置摄像头),参考[plus.camera](https://www.html5plus.org/doc/zh_cn/camera.html)
**OBJECT 参数说明** **OBJECT 参数说明**
...@@ -55,7 +59,7 @@ uni.chooseImage({ ...@@ -55,7 +59,7 @@ uni.chooseImage({
|current|String/Number|详见下方说明|详见下方说明|| |current|String/Number|详见下方说明|详见下方说明||
|urls|Array&lt;String&gt;|是|需要预览的图片链接列表|| |urls|Array&lt;String&gt;|是|需要预览的图片链接列表||
|indicator|String|否|图片指示器样式,可取值:"default" - 底部圆点指示器; "number" - 顶部数字指示器; "none" - 不显示指示器。|5+App| |indicator|String|否|图片指示器样式,可取值:"default" - 底部圆点指示器; "number" - 顶部数字指示器; "none" - 不显示指示器。|5+App|
|loop|Boolean|否|是否可循环预览,默认值为 false|5+App| |loop|Boolean|否|是否可循环预览,默认值为 false|5+App|
|longPressActions|Object|否|长按图片显示操作菜单,如不填默认为**保存相册**,1.9.5 起支持。|5+App| |longPressActions|Object|否|长按图片显示操作菜单,如不填默认为**保存相册**,1.9.5 起支持。|5+App|
|success|Function|否|接口调用成功的回调函数|| |success|Function|否|接口调用成功的回调函数||
|fail|Function|否|接口调用失败的回调函数|| |fail|Function|否|接口调用失败的回调函数||
...@@ -78,47 +82,47 @@ current 为当前显示图片的链接/索引值,不填或填写的值无效 ...@@ -78,47 +82,47 @@ current 为当前显示图片的链接/索引值,不填或填写的值无效
- 传 B2 的链接,预览的结果是 B1,前一张是 A,下一张是 C。 - 传 B2 的链接,预览的结果是 B1,前一张是 A,下一张是 C。
- 传 B2 的索引值 3,预览的结果是 B2,前一张是 C,下一张是 D。此时在微信/百度/头条小程序平台,最终传入的 urls 是 `[A, C, B2, D]`,过滤掉了与 B2 重复的 B1。 - 传 B2 的索引值 3,预览的结果是 B2,前一张是 C,下一张是 D。此时在微信/百度/头条小程序平台,最终传入的 urls 是 `[A, C, B2, D]`,过滤掉了与 B2 重复的 B1。
**longPressActions 参数说明** **longPressActions 参数说明**
|参数|类型|必填|说明| |参数|类型|必填|说明|
|:-|:-|:-|:-| |:-|:-|:-|:-|
|itemList|Array&lt;String&gt;|是|按钮的文字数组| |itemList|Array&lt;String&gt;|是|按钮的文字数组|
|itemColor|String|否|按钮的文字颜色,字符串格式,默认为"#000000"| |itemColor|String|否|按钮的文字颜色,字符串格式,默认为"#000000"|
|success|Function|否|接口调用成功的回调函数,详见返回参数说明| |success|Function|否|接口调用成功的回调函数,详见返回参数说明|
|fail|Function|否|接口调用失败的回调函数| |fail|Function|否|接口调用失败的回调函数|
|complete|Function|否|接口调用结束的回调函数(调用成功、失败都会执行)| |complete|Function|否|接口调用结束的回调函数(调用成功、失败都会执行)|
**success 返回参数说明** **success 返回参数说明**
|参数|类型|说明| |参数|类型|说明|
|:-|:-|:-| |:-|:-|:-|
|index|Number|用户长按图片的索引值| |index|Number|用户长按图片的索引值|
|tapIndex|Number|用户点击按钮列表的索引值| |tapIndex|Number|用户点击按钮列表的索引值|
**示例** **示例**
```javascript ```javascript
// 从相册选择6张图 // 从相册选择6张图
uni.chooseImage({ uni.chooseImage({
count: 6, count: 6,
sizeType: ['original', 'compressed'], sizeType: ['original', 'compressed'],
sourceType: ['album'], sourceType: ['album'],
success: function(res) { success: function(res) {
// 预览图片 // 预览图片
uni.previewImage({ uni.previewImage({
urls: res.tempFilePaths, urls: res.tempFilePaths,
longPressActions: { longPressActions: {
itemList: ['发送给朋友', '保存图片', '收藏'], itemList: ['发送给朋友', '保存图片', '收藏'],
success: function(data) { success: function(data) {
console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片'); console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');
}, },
fail: function(err) { fail: function(err) {
console.log(err.errMsg); console.log(err.errMsg);
} }
} }
}); });
} }
}); });
``` ```
...@@ -221,54 +225,54 @@ uni.chooseImage({ ...@@ -221,54 +225,54 @@ uni.chooseImage({
}); });
} }
}); });
``` ```
# uni.compressImage(OBJECT) # uni.compressImage(OBJECT)
压缩图片接口,可选压缩质量 压缩图片接口,可选压缩质量
**平台差异说明** **平台差异说明**
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序 |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序
|:-:|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|
|1.9.7+ [自定义组件编译模式](https://ask.dcloud.net.cn/article/35843)|x|√|√|x|x| |1.9.7+ [自定义组件编译模式](https://ask.dcloud.net.cn/article/35843)|x|√|√|x|x|
**OBJECT 参数说明** **OBJECT 参数说明**
| 属性 | 类型 | 默认值 | 必填 | 说明 | | 属性 | 类型 | 默认值 | 必填 | 说明 |
| :- | :- | :- | :- | :- | | :- | :- | :- | :- | :- |
| src | String | | 是 | 图片路径,图片的路径,可以是相对路径、临时文件路径、存储文件路径 | | src | String | | 是 | 图片路径,图片的路径,可以是相对路径、临时文件路径、存储文件路径 |
| quality | Number | 80 | 否 | 压缩质量,范围0~100,数值越小,质量越低,压缩率越高(仅对jpg有效) | | quality | Number | 80 | 否 | 压缩质量,范围0~100,数值越小,质量越低,压缩率越高(仅对jpg有效) |
| success | Function | | 否 | 接口调用成功的回调函数 | | success | Function | | 否 | 接口调用成功的回调函数 |
| fail | Function | | 否 | 接口调用失败的回调函数 | | fail | Function | | 否 | 接口调用失败的回调函数 |
| complete | Function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) | | complete | Function | | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
**success 返回参数说明** **success 返回参数说明**
| 属性 | 类型 | 说明 | | 属性 | 类型 | 说明 |
| :- | :- | :- | | :- | :- | :- |
| tempFilePath | String | 压缩后图片的临时文件路径 | | tempFilePath | String | 压缩后图片的临时文件路径 |
**示例代码:** **示例代码:**
```js ```js
uni.compressImage({ uni.compressImage({
src: '/static/logo.jpg', src: '/static/logo.jpg',
quality: 80, quality: 80,
success: res => { success: res => {
console.log(res.tempFilePath) console.log(res.tempFilePath)
} }
}) })
``` ```
# wx.chooseMessageFile(OBJECT) # wx.chooseMessageFile(OBJECT)
从客户端会话选择文件。 从客户端会话选择文件。
**平台差异说明** **平台差异说明**
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序| |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|
|:-:|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|
|x|x|√|x|x|x| |x|x|√|x|x|x|
...@@ -47,15 +47,17 @@ var socketTask = uni.connectSocket({ ...@@ -47,15 +47,17 @@ var socketTask = uni.connectSocket({
如果没有传入 success / fail / complete 参数,则会返回封装后的 Promise 对象:[Promise 封装](/api/README?id=promise-%E5%B0%81%E8%A3%85) 如果没有传入 success / fail / complete 参数,则会返回封装后的 Promise 对象:[Promise 封装](/api/README?id=promise-%E5%B0%81%E8%A3%85)
**注意** **注意事项**
- 网络请求的 ``超时时间`` 可以统一在 ``manifest.json`` 中配置 [networkTimeout](/collocation/manifest?id=networktimeout)
- 网络请求的 ``超时时间`` 可以统一在 ``manifest.json`` 中配置 [networkTimeout](/collocation/manifest?id=networktimeout)
自定义组件模式下是基于 `weex``v8` 引擎运行,所有 `vue` 页面的 `js` 都是在同一个 `weex``js` 环境中运行。目前 `weex` 限制一个 `js` 环境中只支持一个 `websocket` 连接,所以导致所有 `vue` 页面只能使用一个 `websocket` 连接。 - 目前不支持 ``ArrayBuffer`` 类型的数据收发,可以使用 [plus-websocket](http://ext.dcloud.net.cn/plugin?id=647) 插件替代。
- 自定义组件模式下是基于 `weex``v8` 引擎运行,所有 `vue` 页面的 `js` 都是在同一个 `weex``js` 环境中运行。目前 `weex` 限制一个 `js` 环境中只支持一个 `websocket` 连接,所以导致所有 `vue` 页面只能使用一个 `websocket` 连接。
**临时解决方案:** **临时解决方案:**
- 回退使用非自定义组件模式(不推荐) - 回退使用非自定义组件模式(不推荐)
- 多个websocket在独立的nvue页面中使用 - 多个 websocket 在独立的 nvue 页面中使用
- 使用 [plus-websocket](http://ext.dcloud.net.cn/plugin?id=647) 插件替代
后续我们会修改 `weex` 的限制,以支持多个 `websocket` 连接 后续我们会修改 `weex` 的限制,以支持多个 `websocket` 连接
......
...@@ -16,12 +16,13 @@ ...@@ -16,12 +16,13 @@
**示例** **示例**
```javascript ```javascript
//在起始页面跳转到test.vue页面并传递参数
uni.navigateTo({ uni.navigateTo({
url: 'test?id=1&name=uniapp' url: 'test?id=1&name=uniapp'
}); });
``` ```
```javascript ```javascript
// test.vue // 在test.vue页面接受参数
export default { export default {
onLoad: function (option) { //option为object类型,会序列化上个页面传递的参数 onLoad: function (option) { //option为object类型,会序列化上个页面传递的参数
console.log(option.id); //打印出上个页面传递的参数。 console.log(option.id); //打印出上个页面传递的参数。
...@@ -30,11 +31,20 @@ export default { ...@@ -30,11 +31,20 @@ export default {
} }
``` ```
url有长度限制,太长的字符串会传递失败,可使用[窗体通信](https://uniapp.dcloud.io/collocation/frame/communication)[全局变量](https://ask.dcloud.net.cn/article/35021),或`encodeURIComponent`等多种方式解决,如下为`encodeURIComponent`示例。
```html
<navigator :url="'/pages/test/test?item='+ encodeURIComponent(JSON.stringify(item))"></navigator>
```
```javascript
// 在test.vue页面接受参数
onLoad: function (option) {
const item = JSON.parse(decodeURIComponent(option.item));
}
```
**注意:** **注意:**
* 页面跳转路径有层级限制,不能无限制跳转新页面 * 页面跳转路径有层级限制,不能无限制跳转新页面
* 跳转到 tabBar 页面只能使用 switchTab 跳转 * 跳转到 tabBar 页面只能使用 switchTab 跳转
* ```App.vue``` 的onlaunch里进行页面跳转,如遇白屏报错,请参考[https://ask.dcloud.net.cn/article/35942](https://ask.dcloud.net.cn/article/35942)
* 路由API的目标页面必须是在pages.json里注册的vue页面。如果想打开web url,在App平台可以使用 [plus.runtime.openURL](http://www.html5plus.org/doc/zh_cn/runtime.html#plus.runtime.openURL)或web-view组件;H5平台使用 window.open;小程序平台使用web-view组件(url需在小程序的联网白名单中)。在hello uni-app中有个组件ulink.vue已对多端进行封装,可参考。 * 路由API的目标页面必须是在pages.json里注册的vue页面。如果想打开web url,在App平台可以使用 [plus.runtime.openURL](http://www.html5plus.org/doc/zh_cn/runtime.html#plus.runtime.openURL)或web-view组件;H5平台使用 window.open;小程序平台使用web-view组件(url需在小程序的联网白名单中)。在hello uni-app中有个组件ulink.vue已对多端进行封装,可参考。
#### uni.redirectTo(OBJECT) #### uni.redirectTo(OBJECT)
......
...@@ -55,5 +55,5 @@ uni.getClipboardData({ ...@@ -55,5 +55,5 @@ uni.getClipboardData({
#### **注意** #### **注意**
- 设置剪贴板内容后,小程序平台会自动弹出轻提示。App平台默认与小程序保持一致策略。如不希望在App平台弹出提示,可使用Native.js自行操作剪贴板,[http://ask.dcloud.net.cn/question/2034](http://ask.dcloud.net.cn/question/2034) - 设置剪贴板内容后,小程序平台会自动弹出轻提示。App平台默认与小程序保持一致策略。如不希望在App平台弹出提示,可使用Native.js自行操作剪贴板,插件市场有封装好的示例[https://ext.dcloud.net.cn/plugin?id=712](https://ext.dcloud.net.cn/plugin?id=712)
- H5的复制粘贴,可去插件市场搜索[剪贴板](https://ext.dcloud.net.cn/search?q=%E5%89%AA%E8%B4%B4%E6%9D%BF) - H5的复制粘贴,可去插件市场搜索[剪贴板](https://ext.dcloud.net.cn/search?q=%E5%89%AA%E8%B4%B4%E6%9D%BF)
\ No newline at end of file
### uni.vibrate(OBJECT)
使手机发生振动。
**OBJECT 参数说明**
|参数名|类型|必填|说明|
|:-|:-|:-|:-|
|success|Function|否|接口调用成功的回调|
|fail|Function|否|接口调用失败的回调函数|
|complete|Function|否|接口调用结束的回调函数(调用成功、失败都会执行)|
**示例**
```javascript
uni.vibrate({
success: function () {
console.log('success');
}
});
```
### uni.vibrateLong(OBJECT) ### uni.vibrateLong(OBJECT)
使手机发生较长时间的振动(400ms)。 使手机发生较长时间的振动(400ms)。
...@@ -42,4 +63,5 @@ uni.vibrateShort({ ...@@ -42,4 +63,5 @@ uni.vibrateShort({
**注意** **注意**
- iOS上只有长震动,没有短震动 - iOS上只有长震动,没有短震动
- iOS上需要手机设置“打开响铃时震动”或“静音时震动”,否则无法震动 - iOS上需要手机设置“打开响铃时震动”或“静音时震动”,否则无法震动
\ No newline at end of file - vibrate只适用于钉钉小程序、支付宝小程序
\ No newline at end of file
...@@ -6,9 +6,11 @@ ...@@ -6,9 +6,11 @@
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序| |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|
|:-:|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|
|√|HBuilderX 2.0.4+|√|√|√|√| |√|HBuilderX 2.0.4+|√|√|√|√|
**注意: export 方法每次调用后会清掉之前的动画操作** **注意:**
- export 方法每次调用后会清掉之前的动画操作
- nvue 暂不支持
**OBJECT参数说明:** **OBJECT参数说明:**
......
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
|backgroundColor|String||否|窗口的背景色,必须为十六进制颜色值| |backgroundColor|String||否|窗口的背景色,必须为十六进制颜色值|
|backgroundColorTop|String||否|顶部窗口的背景色,必须为十六进制颜色值,仅 iOS 支持| |backgroundColorTop|String||否|顶部窗口的背景色,必须为十六进制颜色值,仅 iOS 支持|
|backgroundColorBottom|String||否|底部窗口的背景色,必须为十六进制颜色值,仅 iOS 支持| |backgroundColorBottom|String||否|底部窗口的背景色,必须为十六进制颜色值,仅 iOS 支持|
|success|Funtion||否|接口调用成功的回调函数| |success|Function||否|接口调用成功的回调函数|
|fail|Funtion||否|接口调用失败的回调函数| |fail|Function||否|接口调用失败的回调函数|
|complete|Funtion||否|接口调用结束的回调函数(调用成功、失败都会执行)| |complete|Function||否|接口调用结束的回调函数(调用成功、失败都会执行)|
**代码示例** **代码示例**
...@@ -42,11 +42,11 @@ uni.setBackgroundColor({ ...@@ -42,11 +42,11 @@ uni.setBackgroundColor({
**参数说明** **参数说明**
|属性|类型|必填|说明| |属性|类型|必填|说明|
|:-|:-|:-|:-|:-| |:-|:-|:-|:-|
|textStyle|String|是|下拉背景字体、loading 图的样式,值为:dark、light| |textStyle|String|是|下拉背景字体、loading 图的样式,值为:dark、light|
|success|Funtion|否|接口调用成功的回调函数| |success|Function|否|接口调用成功的回调函数|
|fail|Funtion|否|接口调用失败的回调函数| |fail|Function|否|接口调用失败的回调函数|
|complete|Funtion|否|接口调用结束的回调函数(调用成功、失败都会执行)| |complete|Function|否|接口调用结束的回调函数(调用成功、失败都会执行)|
**代码示例** **代码示例**
...@@ -54,4 +54,4 @@ uni.setBackgroundColor({ ...@@ -54,4 +54,4 @@ uni.setBackgroundColor({
uni.setBackgroundTextStyle({ uni.setBackgroundTextStyle({
textStyle: 'dark' // 下拉背景字体、loading 图的样式为dark textStyle: 'dark' // 下拉背景字体、loading 图的样式为dark
}) })
``` ```
\ No newline at end of file
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序| |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|
|:-:|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|
|√|√|√|x|√|x| |√|√|√||√|x|
**OBJECT参数说明:** **OBJECT参数说明:**
...@@ -39,7 +39,7 @@ uni.setTabBarItem({ ...@@ -39,7 +39,7 @@ uni.setTabBarItem({
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序| |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|
|:-:|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|
|√|√|√|x|√|x| |√|√|√||√|x|
**OBJECT参数说明:** **OBJECT参数说明:**
...@@ -72,7 +72,7 @@ uni.setTabBarStyle({ ...@@ -72,7 +72,7 @@ uni.setTabBarStyle({
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序| |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|
|:-:|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|
|√|√|√|x|√|x| |√|√|√||√|x|
**OBJECT参数说明:** **OBJECT参数说明:**
...@@ -91,7 +91,7 @@ uni.setTabBarStyle({ ...@@ -91,7 +91,7 @@ uni.setTabBarStyle({
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序| |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|
|:-:|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|
|√|√|√|x|√|x| |√|√|√||√|x|
**OBJECT参数说明:** **OBJECT参数说明:**
...@@ -109,7 +109,7 @@ uni.setTabBarStyle({ ...@@ -109,7 +109,7 @@ uni.setTabBarStyle({
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序| |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|
|:-:|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|
|√|√|√|x|√|x| |√|√|√||√|x|
**OBJECT参数说明:** **OBJECT参数说明:**
...@@ -137,7 +137,7 @@ uni.setTabBarBadge({ ...@@ -137,7 +137,7 @@ uni.setTabBarBadge({
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序| |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|
|:-:|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|
|√|√|√|x|√|x| |√|√|√||√|x|
**OBJECT参数说明:** **OBJECT参数说明:**
...@@ -155,7 +155,7 @@ uni.setTabBarBadge({ ...@@ -155,7 +155,7 @@ uni.setTabBarBadge({
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序| |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|
|:-:|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|
|√|√|√|x|√|x| |√|√|√||√|x|
**OBJECT参数说明:** **OBJECT参数说明:**
...@@ -173,7 +173,7 @@ uni.setTabBarBadge({ ...@@ -173,7 +173,7 @@ uni.setTabBarBadge({
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序| |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|
|:-:|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|
|√|√|√|x|√|x| |√|√|√||√|x|
**OBJECT参数说明:** **OBJECT参数说明:**
......
...@@ -24,7 +24,7 @@ uni-app已经有几十万开发者,创建了几十万个项目,是开发者 ...@@ -24,7 +24,7 @@ uni-app已经有几十万开发者,创建了几十万个项目,是开发者
<span style="margin-top:15px;">App及H5的通用快码</span> <span style="margin-top:15px;">App及H5的通用快码</span>
</a> </a>
</div> </div>
<!--
<a href="//m3w.cn/__uni__fad3fd9" target="_blank" class="clear-style"><b>图片App模版:</b></a>使用uni-app开发的图片App模版,包含单列图、双列图,图片分类,图片轮播、预览、下载,图片分享、收藏,设置桌面背景图等功能。本项目源码在HBuilderX中新建项目可获得。 <a href="//m3w.cn/__uni__fad3fd9" target="_blank" class="clear-style"><b>图片App模版:</b></a>使用uni-app开发的图片App模版,包含单列图、双列图,图片分类,图片轮播、预览、下载,图片分享、收藏,设置桌面背景图等功能。本项目源码在HBuilderX中新建项目可获得。
<div style="display:flex;justify-content: space-around;"> <div style="display:flex;justify-content: space-around;">
<a href="//m3w.cn/__uni__fad3fd9" target="_blank" class="clear-style barcode-view"> <a href="//m3w.cn/__uni__fad3fd9" target="_blank" class="clear-style barcode-view">
...@@ -32,10 +32,11 @@ uni-app已经有几十万开发者,创建了几十万个项目,是开发者 ...@@ -32,10 +32,11 @@ uni-app已经有几十万开发者,创建了几十万个项目,是开发者
<span style="margin-top:15px;">App及H5的通用快码</span> <span style="margin-top:15px;">App及H5的通用快码</span>
</a> </a>
</div> </div>
-->
### 第三方开发者案例 ### 第三方开发者案例
<a href="https://media.kunming-railway.cn/" target="_blank" class="clear-style"><b>CSDN:</b></a> 专业 IT 技术社区,致力于为中国软件开发者提供知识传播、在线学习、职业发展等全生命周期服务。 <a href="https://www.csdn.net/" target="_blank" class="clear-style"><b>CSDN:</b></a> 专业 IT 技术社区,致力于为中国软件开发者提供知识传播、在线学习、职业发展等全生命周期服务。
<div style="display:flex;justify-content: space-around;"> <div style="display:flex;justify-content: space-around;">
<a href="javascript:;" target="_blank" class="clear-style barcode-view"> <a href="javascript:;" target="_blank" class="clear-style barcode-view">
<img src="https://img-cdn-qiniu.dcloud.net.cn/doc/csdn/csdn.png" width="200"/> <img src="https://img-cdn-qiniu.dcloud.net.cn/doc/csdn/csdn.png" width="200"/>
...@@ -43,9 +44,13 @@ uni-app已经有几十万开发者,创建了几十万个项目,是开发者 ...@@ -43,9 +44,13 @@ uni-app已经有几十万开发者,创建了几十万个项目,是开发者
</a> </a>
</div> </div>
<a href="https://media.kunming-railway.cn/" target="_blank" class="clear-style"><b>开源中国:</b></a> 开源中国(oschina)百度小程序,提供最新的开源软件资讯。 <a href="https://www.oschina.net/" target="_blank" class="clear-style"><b>开源中国:</b></a> 中文开源技术交流社区,提供最新的开源软件资讯。
<div style="display:flex;justify-content: space-around;"> <div style="display:flex;justify-content: space-around;">
<a href="javascript:;" target="_blank" class="clear-style barcode-view"> <a href="javascript:;" target="_blank" class="clear-style barcode-view">
<img src="http://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/oschina_weixin.jpg" width="200"/>
<span style="margin-top:15px;">微信小程序码</span>
</a>
<a href="javascript:;" target="_blank" class="clear-style barcode-view">
<img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/onchina.png" width="200"/> <img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/onchina.png" width="200"/>
<span style="margin-top:15px;">百度小程序码</span> <span style="margin-top:15px;">百度小程序码</span>
</a> </a>
...@@ -89,8 +94,37 @@ uni-app已经有几十万开发者,创建了几十万个项目,是开发者 ...@@ -89,8 +94,37 @@ uni-app已经有几十万开发者,创建了几十万个项目,是开发者
<img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/cyb-baidu.png" width="200"/> <img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/cyb-baidu.png" width="200"/>
<span style="margin-top:15px;">百度小程序码</span> <span style="margin-top:15px;">百度小程序码</span>
</a> </a>
<a href="https://www.cyb520.com/" target="_blank" class="clear-style barcode-view">
<img src="https://img.cyb520.com/faceImg/2019/08/17/130C1F3F-2E93-A55D-D6B2-074BEBE1902F.png/a120" width="200"/>
<span style="margin-top:15px;">QQ小程序码</span>
</a>
<a href="https://www.cyb520.com/" target="_blank" class="clear-style barcode-view">
<img src="https://img.cyb520.com/faceImg/2019/08/17/404C2595-2B08-D471-1317-6D5375F195C5.png/a120" width="200"/>
<span style="margin-top:15px;">头条/抖音小程序码</span>
</a>
</div>
<b>垃圾分类:</b>垃圾分一分,环境美十分。参与垃圾分类,保护地球家园,共创美好世界。(作者:怎么会这样)
<div style="display:flex;justify-content: space-around;">
<a href="#" class="clear-style barcode-view">
<img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/wastesep-mp-weixin.png" width="200"/>
<span style="margin-top:15px;">微信小程序码</span>
</a>
<a href="#" class="clear-style barcode-view">
<img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/wastesep-mp-qq.png" width="200"/>
<span style="margin-top:15px;">QQ小程序码</span>
</a>
<a href="#" class="clear-style barcode-view">
<img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/wastesep-mp-douyin.png" width="200"/>
<span style="margin-top:15px;">抖音小程序码</span>
</a>
<a href="#" class="clear-style barcode-view">
<img src="https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/wastesep-mp-toutiao.png" width="200"/>
<span style="margin-top:15px;">头条小程序码</span>
</a>
</div> </div>
<!-- <a href="//m3w.cn/__uni__4c6db6e" target="_blank" class="clear-style"><b>UniApp视频教程:</b></a>视频教育App,帮助开发者学习了解uni-app、h5+、mui等DCloud产品。开发者枫桥。 <!-- <a href="//m3w.cn/__uni__4c6db6e" target="_blank" class="clear-style"><b>UniApp视频教程:</b></a>视频教育App,帮助开发者学习了解uni-app、h5+、mui等DCloud产品。开发者枫桥。
<div style="display:flex;justify-content: space-around;"> <div style="display:flex;justify-content: space-around;">
<a href="//m3w.cn/__uni__4c6db6e" target="_blank" class="clear-style barcode-view"> <a href="//m3w.cn/__uni__4c6db6e" target="_blank" class="clear-style barcode-view">
...@@ -140,6 +174,8 @@ uni-app已经有几十万开发者,创建了几十万个项目,是开发者 ...@@ -140,6 +174,8 @@ uni-app已经有几十万开发者,创建了几十万个项目,是开发者
**蓝鲸鱼旧物回收:** 微信、支付宝搜索“蓝鲸鱼旧物回收” **蓝鲸鱼旧物回收:** 微信、支付宝搜索“蓝鲸鱼旧物回收”
**锦衣盒:** 专注男士形象打造,全新的智能化购物模式,解决男士购衣困扰。微信小程序中搜索“锦衣盒”,头条/抖音小程序二维码[点此](http://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/case-jinyihe-toutiao.png)
**ADR之声:** 航空工业信息中心App。[Android](https://m3w.cn/__uni__937cb89) **ADR之声:** 航空工业信息中心App。[Android](https://m3w.cn/__uni__937cb89)
**机场行:** 中国航信以机场为核心为旅客提供智能全行程服务应用。微信小程序搜索“机场行”,[H5](http://airporttravel.travelsky.com/weixin/) **机场行:** 中国航信以机场为核心为旅客提供智能全行程服务应用。微信小程序搜索“机场行”,[H5](http://airporttravel.travelsky.com/weixin/)
...@@ -156,6 +192,8 @@ uni-app已经有几十万开发者,创建了几十万个项目,是开发者 ...@@ -156,6 +192,8 @@ uni-app已经有几十万开发者,创建了几十万个项目,是开发者
**江苏公安网上政工慰问:**[H5](https://jxt.jsga.gov.cn:10006/app/njqxgzzs/zgww/#/) **江苏公安网上政工慰问:**[H5](https://jxt.jsga.gov.cn:10006/app/njqxgzzs/zgww/#/)
**杭州智安通:*[H5](https://hzjjzat.citydo.com.cn/vehicle-test)
**深圳福田区爱福田:**[H5](https://ifutian.szft.gov.cn/masterSecond/) **深圳福田区爱福田:**[H5](https://ifutian.szft.gov.cn/masterSecond/)
**广州市南沙区企业综合服务平台:**[H5](https://qiye.gzns.gov.cn/m/#/) **广州市南沙区企业综合服务平台:**[H5](https://qiye.gzns.gov.cn/m/#/)
......
...@@ -87,6 +87,21 @@ export default { ...@@ -87,6 +87,21 @@ export default {
} }
``` ```
### 组件生命周期
``uni-app`` 组件支持如下页面生命周期函数:
|函数名|说明|平台差异说明|最低版本|
|:-|:-|:-|:-|
|beforeCreate|在实例初始化之后被调用。[详见](https://cn.vuejs.org/v2/api/#beforeCreate)|||
|created|在实例创建完成后被立即调用。[详见](https://cn.vuejs.org/v2/api/#created)|||
|beforeMount|在挂载开始之前被调用。[详见](https://cn.vuejs.org/v2/api/#beforeMount)|||
|mounted|挂载到实例上去之后调用。[详见](https://cn.vuejs.org/v2/api/#mounted) 注意:此处并不能确定子组件被全部挂载,如果需要子组件完全挂载之后在执行操作可以使用```$nextTick```[Vue官方文档](https://cn.vuejs.org/v2/api/#Vue-nextTick)|||
|beforeUpdate|数据更新时调用,发生在虚拟 DOM 打补丁之前。[详见](https://cn.vuejs.org/v2/api/#beforeUpdate)|仅H5平台支持||
|updated|由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。[详见](https://cn.vuejs.org/v2/api/#updated)|仅H5平台支持||
|beforeDestroy|实例销毁之前调用。在这一步,实例仍然完全可用。[详见](https://cn.vuejs.org/v2/api/#beforeDestroy)|||
|destroyed|Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。[详见](https://cn.vuejs.org/v2/api/#destroyed)|||
**注意** **注意**
- nvue 页面支持的生命周期参考:[nvue 生命周期介绍](/use-weex?id=生命周期) - nvue 页面支持的生命周期参考:[nvue 生命周期介绍](/use-weex?id=生命周期)
\ No newline at end of file
...@@ -325,7 +325,8 @@ Tips:`uni-app` 中 `manifest.json->h5->devServer` 实际上对应 `webpack` ...@@ -325,7 +325,8 @@ Tips:`uni-app` 中 `manifest.json->h5->devServer` 实际上对应 `webpack`
|属性|类型|说明| |属性|类型|说明|
|:-|:-|:-| |:-|:-|:-|
|appid|String|头条小程序的 AppID,登录 [https://developer.toutiao.com/](https://developer.toutiao.com/) 申请| |appid|String|头条小程序的 AppID,登录 [https://developer.toutiao.com/](https://developer.toutiao.com/) 申请|
|setting|Object|头条小程序项目设置,参考[头条小程序项目设置](/collocation/manifest?id=mp-toutiao-setting)| |setting|Object|头条小程序项目设置,参考[头条小程序项目设置](/collocation/manifest?id=mp-toutiao-setting)|
|usingComponents|Boolean| 是否启用自定义组件模式,`v2.0+`,默认为false,[编译模式区别详情](https://ask.dcloud.net.cn/article/35843)|
#### 头条小程序项目设置@mp-toutiao-setting #### 头条小程序项目设置@mp-toutiao-setting
...@@ -340,7 +341,8 @@ Tips:`uni-app` 中 `manifest.json->h5->devServer` 实际上对应 `webpack` ...@@ -340,7 +341,8 @@ Tips:`uni-app` 中 `manifest.json->h5->devServer` 实际上对应 `webpack`
|属性|类型|说明| |属性|类型|说明|
|:-|:-|:-| |:-|:-|:-|
|appid|String|qq 小程序的 AppID,登录 [https://q.qq.com](https://q.qq.com) 申请| |appid|String|qq 小程序的 AppID,登录 [https://q.qq.com](https://q.qq.com) 申请|
|usingComponents|Boolean| 是否启用自定义组件模式,`v2.0+`,默认为false,[编译模式区别详情](https://ask.dcloud.net.cn/article/35843)。mp-qq只支持自定义组件模式|
### 完整 manifest.json ### 完整 manifest.json
......
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
|属性|类型|默认值|描述|平台差异说明| |属性|类型|默认值|描述|平台差异说明|
|:-|:-|:-|:-|| |:-|:-|:-|:-||
|navigationBarBackgroundColor|HexColor|#000000|导航栏背景颜色(同状态栏背景色)|| |navigationBarBackgroundColor|HexColor|#F7F7F7|导航栏背景颜色(同状态栏背景色)|APP与H5为#F7F7F7,小程序平台请参考相应小程序文档||
|navigationBarTextStyle|String|white|导航栏标题颜色及状态栏前景颜色,仅支持 black/white|| |navigationBarTextStyle|String|white|导航栏标题颜色及状态栏前景颜色,仅支持 black/white||
|navigationBarTitleText|String||导航栏标题文字内容|| |navigationBarTitleText|String||导航栏标题文字内容||
|navigationStyle|String|default|导航栏样式,仅支持 default/custom。custom即取消默认的原生导航栏,需看[使用注意](/collocation/pages?id=/customnav)|微信小程序 7.0+、百度小程序、H5、App(2.0.3+)| |navigationStyle|String|default|导航栏样式,仅支持 default/custom。custom即取消默认的原生导航栏,需看[使用注意](/collocation/pages?id=/customnav)|微信小程序 7.0+、百度小程序、H5、App(2.0.3+)|
...@@ -210,7 +210,7 @@ ...@@ -210,7 +210,7 @@
- 前端组件在渲染速度上不如原生导航栏,原生导航可以在动画期间渲染,保证动画期间不白屏,但使用前端导航栏,在新窗体进入的动画期间可能会整页白屏,越低端的手机越明显。 - 前端组件在渲染速度上不如原生导航栏,原生导航可以在动画期间渲染,保证动画期间不白屏,但使用前端导航栏,在新窗体进入的动画期间可能会整页白屏,越低端的手机越明显。
- 以上讨论的是前端自定义导航栏,但在App侧,原生导航栏也提供了比小程序导航更丰富的自定义性 - 以上讨论的是前端自定义导航栏,但在App侧,原生导航栏也提供了比小程序导航更丰富的自定义性
* titleNView:给原生导航栏提供更多配置,包括自定义按钮、滚动渐变效果、搜索框等,详见[titleNView](/collocation/pages?id=app-titleNView) * titleNView:给原生导航栏提供更多配置,包括自定义按钮、滚动渐变效果、搜索框等,详见[titleNView](/collocation/pages?id=app-titleNView)
* sunNView:使用nvue原生渲染,所有布局自己开发,具备一切自定义灵活度。详见[subNVue](/collocation/pages?id=app-subNVues) * subNView:使用nvue原生渲染,所有布局自己开发,具备一切自定义灵活度。详见[subNVue](/collocation/pages?id=app-subNVues)
- 页面禁用原生导航栏后,想要改变状态栏的前景字体样式,仍可设置页面的 navigationBarTextStyle 属性(只能设置为 black或white)。如果想单独设置状态栏颜色,App端可使用[plus.navigator.setStatusBarStyle](http://www.html5plus.org/doc/zh_cn/navigator.html#plus.navigator.setStatusBarStyle)设置。注意部分低端Android手机(4.4)自身不支持设置状态栏前景色。 - 页面禁用原生导航栏后,想要改变状态栏的前景字体样式,仍可设置页面的 navigationBarTextStyle 属性(只能设置为 black或white)。如果想单独设置状态栏颜色,App端可使用[plus.navigator.setStatusBarStyle](http://www.html5plus.org/doc/zh_cn/navigator.html#plus.navigator.setStatusBarStyle)设置。注意部分低端Android手机(4.4)自身不支持设置状态栏前景色。
鉴于以上问题,在原生导航能解决业务需求的情况下,尽量使用原生导航。甚至有时需要牺牲一些不是很重要的需求。在App和H5下,uni-app提供了灵活的处理方案:[titleNView](/collocation/pages?id=app-titleNView)[subNVue](/collocation/pages?id=app-subNVues)、或整页使用nvue。但在小程序下,因为其自身的限制,没有太好的方案。有必要的话,也可以用条件编译分端处理。 鉴于以上问题,在原生导航能解决业务需求的情况下,尽量使用原生导航。甚至有时需要牺牲一些不是很重要的需求。在App和H5下,uni-app提供了灵活的处理方案:[titleNView](/collocation/pages?id=app-titleNView)[subNVue](/collocation/pages?id=app-subNVues)、或整页使用nvue。但在小程序下,因为其自身的限制,没有太好的方案。有必要的话,也可以用条件编译分端处理。
......
vue.config.js 是一个可选的配置文件,如果项目的根目录中存在这个文件,那么它会被自动加载,具体规范参考:[vue-config.js](https://cli.vuejs.org/zh/config/#vue-config-js) vue.config.js 是一个可选的配置文件,如果项目的根目录中存在这个文件,那么它会被自动加载,一般用于配置 webpack 等编译选项,具体规范参考:[vue-config.js](https://cli.vuejs.org/zh/config/#vue-config-js)
**支持情况** **支持情况**
* CLI 工程 * CLI 工程
* HBuilderX 2.1.5 及以上版本 * HBuilderX 2.1.5 及以上版本
**注意事项** **注意事项**
部分配置项会被编译配置覆盖,例如: 部分配置项会被编译配置覆盖,例如:
* publicPath 不支持,如果需要配置,请在 manifest.json->h5->router->base 中配置,参考文档:[h5-router](collocation/manifest?id=h5-router) * publicPath 不支持,如果需要配置,请在 manifest.json->h5->router->base 中配置,参考文档:[h5-router](collocation/manifest?id=h5-router)
* outputDir 不支持 * outputDir 不支持
* assetsDir 固定 static * assetsDir 固定 static
* pages 不支持 * pages 不支持
* runtimeCompiler 固定 false * runtimeCompiler 固定 false
* productionSourceMap 固定 false * productionSourceMap 固定 false
* css.extract H5 平台固定 false,其他平台固定 true * css.extract H5 平台固定 false,其他平台固定 true
* parallel 固定 false * parallel 固定 false
**使用示例** **使用示例**
**自定义静态资源目录** **自定义静态资源目录**
```js ```js
const path = require('path') const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin') const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = { module.exports = {
configureWebpack: { configureWebpack: {
plugins: [ plugins: [
new CopyWebpackPlugin([ new CopyWebpackPlugin([
{ {
from: path.join(__dirname, 'src/images'), from: path.join(__dirname, 'src/images'),
to: path.join(__dirname, 'dist', process.env.NODE_ENV === 'production' ? 'build' : 'dev', process.env.UNI_PLATFORM, 'images') to: path.join(__dirname, 'dist', process.env.NODE_ENV === 'production' ? 'build' : 'dev', process.env.UNI_PLATFORM, 'images')
} }
]) ])
] ]
} }
} }
``` ```
**注入全局依赖** **注入全局依赖**
```js ```js
const webpack = require('webpack') const webpack = require('webpack')
module.exports = { module.exports = {
configureWebpack: { configureWebpack: {
plugins: [ plugins: [
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
'localStorage': ['mp-storage', 'localStorage'], 'localStorage': ['mp-storage', 'localStorage'],
'window.localStorage': ['mp-storage', 'localStorage'] 'window.localStorage': ['mp-storage', 'localStorage']
}) })
] ]
} }
} }
``` ```
...@@ -44,8 +44,12 @@ ...@@ -44,8 +44,12 @@
* [official-account](component/official-account.md) * [official-account](component/official-account.md)
* [open-data](component/open-data.md) * [open-data](component/open-data.md)
* App nvue专用组件 * App nvue专用组件
* [barcode](component/barcode.md) * [barcode](component/barcode.md)
* [recycle-list](component/recycle-list.md) * [list](component/list.md)
* [cell](component/cell.md)
* [recycle-list](component/recycle-list.md)
* [waterfall](component/waterfall.md)
* [refresh](component/refresh.md)
* 扩展组件(uni ui) * 扩展组件(uni ui)
* [uni-ui整体介绍](component/README?id=uniui) * [uni-ui整体介绍](component/README?id=uniui)
* [Badge 数字角标](https://ext.dcloud.net.cn/plugin?id=21) * [Badge 数字角标](https://ext.dcloud.net.cn/plugin?id=21)
......
...@@ -48,21 +48,22 @@ ...@@ -48,21 +48,22 @@
|:-|:-|:-| |:-|:-|:-|
|feedback|打开“意见反馈”页面,用户可提交反馈内容并上传日志|5+App、微信小程序| |feedback|打开“意见反馈”页面,用户可提交反馈内容并上传日志|5+App、微信小程序|
|share|触发用户转发|微信小程序、百度小程序、支付宝小程序、头条小程序| |share|触发用户转发|微信小程序、百度小程序、支付宝小程序、头条小程序|
|getUserInfo|获取用户信息,可以从@getuserinfo回调中获取到用户信息,包括手机号、头像、昵称等信息|微信小程序、百度小程序| |getUserInfo|获取用户信息,可以从@getuserinfo回调中获取到用户信息,包括手机号、头像、昵称等信息|微信小程序、百度小程序|
| contact | 打开客服会话,如果用户在会话中点击消息卡片后返回应用,可以从 @contact 回调中获得具体信息 |微信小程序| | contact | 打开客服会话,如果用户在会话中点击消息卡片后返回应用,可以从 @contact 回调中获得具体信息 |微信小程序|
| getPhoneNumber | 获取用户手机号,可以从@getphonenumber回调中获取到用户信息|微信小程序、百度小程序、头条小程序 | | getPhoneNumber | 获取用户手机号,可以从@getphonenumber回调中获取到用户信息|微信小程序、百度小程序、头条小程序 |
| launchApp | 打开APP,可以通过app-parameter属性设定向APP传的参数|微信小程序| | launchApp | 打开APP,可以通过app-parameter属性设定向APP传的参数|微信小程序|
| openSetting | 打开授权设置页 |微信小程序、百度小程序| | openSetting | 打开授权设置页 |微信小程序、百度小程序|
| getAuthorize | 支持小程序授权 | 支付宝小程序 | | getAuthorize | 支持小程序授权 | 支付宝小程序 |
| contactShare | 分享到通讯录好友 | 支付宝小程序 | | contactShare | 分享到通讯录好友 | 支付宝小程序 |
| lifestyle | 关注生活号 | 支付宝小程序 | | lifestyle | 关注生活号 | 支付宝小程序 |
**注意** **注意**
- 在小程序中,开发者可以登录 [小程序管理后台](https://mp.weixin.qq.com/) 后进入左侧菜单“客服反馈”页面获取反馈内容。 - 在小程序中,开发者可以登录 [小程序管理后台](https://mp.weixin.qq.com/) 后进入左侧菜单“客服反馈”页面获取反馈内容。
- 在 App 中,开发者登录 [DCloud开发者中心](https://dev.dcloud.net.cn/) 后点击应用名称,进入左侧菜单“用户反馈”页面获取反馈内容。 - 在 App 中,开发者登录 [DCloud开发者中心](https://dev.dcloud.net.cn/) 后点击应用名称,进入左侧菜单“用户反馈”页面获取反馈内容。
- 点击 share 分享按钮时会触发 [onShareAppMessage](/api/plugins/share) - 点击 share 分享按钮时会触发 [onShareAppMessage](/api/plugins/share)
- 支付宝小程序平台,获取用户手机号时,建议先通过条件编译的方式,调用支付宝原生API,[参考](https://docs.alipay.com/mini/api/getphonenumber)
**示例** **示例**
......
...@@ -15,12 +15,12 @@ ...@@ -15,12 +15,12 @@
|@longtap|EventHandle||手指长按 500ms 之后触发,触发了长按事件后进行移动不会触发屏幕的滚动|头条小程序不支持| |@longtap|EventHandle||手指长按 500ms 之后触发,触发了长按事件后进行移动不会触发屏幕的滚动|头条小程序不支持|
|@error|EventHandle||当发生错误时触发 error 事件,detail = {errMsg: 'something wrong'}|头条小程序不支持| |@error|EventHandle||当发生错误时触发 error 事件,detail = {errMsg: 'something wrong'}|头条小程序不支持|
**注:** **注意事项:**
1. canvas 标签默认宽度 300px、高度 225px * canvas 标签默认宽度 300px、高度 225px,动态修改 canvas 大小后需要重新绘制
2. 同一页面中的 canvas-id 不可重复,如果使用一个已经出现过的 canvas-id,该 canvas 标签对应的画布将被隐藏并不再正常工作。 * 同一页面中的 canvas-id 不可重复,如果使用一个已经出现过的 canvas-id,该 canvas 标签对应的画布将被隐藏并不再正常工作。
3. canvas在微信、百度小程序中为原生组件,层级高于前端组件,请勿内嵌在 scroll-view、swiper、picker-view、movable-view 中使用。解决 canvas 层级过高无法覆盖,[参考](/component/native-component)。canvas在App端vue页面不是原生组件,目前App端nvue还不支持canvas组件 * canvas 在微信小程序、百度小程序中为原生组件,层级高于前端组件,请勿内嵌在 scroll-view、swiper、picker-view、movable-view 中使用。解决 canvas 层级过高无法覆盖,参考 [native-component](/component/native-component)
- App-nvue 暂不支持 canvas 组件 * canvas 在App端 vue 页面不是原生组件,目前App端 nvue 还不支持 canvas 组件。
**示例:** **示例:**
...@@ -70,4 +70,4 @@ export default { ...@@ -70,4 +70,4 @@ export default {
canvas的常用用途有图表和图片处理,在uni-app插件市场有大量基于canvas的插件,可搜索 [图表](https://ext.dcloud.net.cn/search?q=图表)[头像裁剪](https://ext.dcloud.net.cn/search?q=头像裁剪)[海报](https://ext.dcloud.net.cn/search?q=海报)[二维码](https://ext.dcloud.net.cn/search?q=%E4%BA%8C%E7%BB%B4%E7%A0%81) canvas的常用用途有图表和图片处理,在uni-app插件市场有大量基于canvas的插件,可搜索 [图表](https://ext.dcloud.net.cn/search?q=图表)[头像裁剪](https://ext.dcloud.net.cn/search?q=头像裁剪)[海报](https://ext.dcloud.net.cn/search?q=海报)[二维码](https://ext.dcloud.net.cn/search?q=%E4%BA%8C%E7%BB%B4%E7%A0%81)
关于图表,H5端流行的echart报表因为涉及大量dom操作,无法跨端使用,而wx-chart在跨端和更新方面都不足,推荐使用[uChart组件](https://ext.dcloud.net.cn/plugin?id=271)如仍然坚持使用原版echart,可在web-view组件中内嵌html来使用 关于图表,H5端流行的echart报表因为涉及大量dom操作,无法跨端使用,而wx-chart在跨端和更新方面都不足,推荐使用[uChart组件](https://ext.dcloud.net.cn/plugin?id=271)但由于小程序和App在跟手操作和js操作帧动画方面性能不如web,如果这方面的需求,建议在web-view组件中使用html内嵌原版echart
#### cell
app端nvue专用组件。
`<cell>` Cell 必须以一级子组件的形式存在于 `list recycler waterfall` 中。
#### 子组件
Cell 支持添加任意类型的组件作为自己的子组件,但是请不要再内部添加滚动容器了。
#### 属性
- keep-scroll-position boolean. 控制当 Cell 被添加到列表中时,列表的滚动位置是否要保持不变。
- insert-animation string, cell 的插入动画。当前只支持 `none``default`
- delete-animation string, cell 的删除动画。当前只支持 `none``default`
- recycle boolean, 默认值 true。这个属性控制这个 Cell 的 view 和子 views 是否在列表滚动时进行回收,在 iOS 上通常必须指定为 true (因为默认为 true,所以一般不需要写这个属性),如果设置为 false,列表滚动时,页面会占用非常高的内存。Android上默认是true,设置为false可以防止Image和Text上数据重新绑定。
#### 样式
- 通用样式.
> TIP
> - 不要指定 `<cell>` 的 `flex` 值。Cell 的宽度是由它的父容器决定的,你也不需要指定它的高度。
> - Cell 的排版的位置是由父容器控制的,所以一般不要为其指定 `margin` 样式
#### 事件
- 通用事件.
...@@ -4,9 +4,11 @@ ...@@ -4,9 +4,11 @@
**平台差异说明** **平台差异说明**
|5+App|H5|微信小程序|支付宝小程序|百度小程序| |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|QQ小程序|
|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|√|x|√|√|√| |√|√|√|√|√|√|√|
**Tips**
* 由于 icon 组件各端表现存在差异,可以通过使用 [字体图标](/frame?id=字体图标) 的方式来弥补各端差异。 * 由于 icon 组件各端表现存在差异,可以通过使用 [字体图标](/frame?id=字体图标) 的方式来弥补各端差异。
...@@ -22,8 +24,7 @@ ...@@ -22,8 +24,7 @@
|平台|type 有效值| |平台|type 有效值|
|:-:|:-:| |:-:|:-:|
|5+App|success, success_no_circle, info, warn, waiting, cancel, download, search, clear| |5+App、H5、微信小程序、QQ小程序|success, success_no_circle, info, warn, waiting, cancel, download, search, clear|
|微信小程序|success, success_no_circle, info, warn, waiting, cancel, download, search, clear|
|支付宝小程序|info, warn, waiting, cancel, download, search, clear, success, success_no_circle,loading| |支付宝小程序|info, warn, waiting, cancel, download, search, clear, success, success_no_circle,loading|
|百度小程序|success, info, warn, waiting, success_no_circle, clear, search, personal, setting, top, close, cancel, download, checkboxSelected, radioSelected, radioUnselect| |百度小程序|success, info, warn, waiting, success_no_circle, clear, search, personal, setting, top, close, cancel, download, checkboxSelected, radioSelected, radioUnselect|
......
...@@ -21,9 +21,9 @@ ...@@ -21,9 +21,9 @@
|cursor|Number||指定focus时的光标位置|| |cursor|Number||指定focus时的光标位置||
|selection-start|Number|-1|光标起始位置,自动聚集时有效,需与selection-end搭配使用|| |selection-start|Number|-1|光标起始位置,自动聚集时有效,需与selection-end搭配使用||
|selection-end|Number|-1|光标结束位置,自动聚集时有效,需与selection-start搭配使用|| |selection-end|Number|-1|光标结束位置,自动聚集时有效,需与selection-start搭配使用||
|adjust-position|Boolean|true|键盘弹起时,是否自动上推页面|5+App、微信小程序、百度小程序、QQ小程序| |adjust-position|Boolean|true|键盘弹起时,是否自动上推页面|5+App(softinputMode 为 adjustResize 时无效)、微信小程序、百度小程序、QQ小程序|
|@input|EventHandle||当键盘输入时,触发input事件,event.detail = {value}|差异见下方 Tips| |@input|EventHandle||当键盘输入时,触发input事件,event.detail = {value}|差异见下方 Tips|
|@focus|EventHandle||输入框聚焦时触发,event.detail = { value, height },height 为键盘高度|仅微信小程序、5+App(HBuilderX 2.0+ [nvue uni-app模式](http://ask.dcloud.net.cn/article/36074)) 、QQ小程序支持 height| |@focus|EventHandle||输入框聚焦时触发,event.detail = { value, height },height 为键盘高度|仅微信小程序、5+App(HBuilderX 2.2.3) 、QQ小程序支持 height|
|@blur|EventHandle||输入框失去焦点时触发,event.detail = {value: value}|| |@blur|EventHandle||输入框失去焦点时触发,event.detail = {value: value}||
|@confirm|EventHandle||点击完成按钮时触发,event.detail = {value: value}|&nbsp;| |@confirm|EventHandle||点击完成按钮时触发,event.detail = {value: value}|&nbsp;|
...@@ -99,34 +99,16 @@ this.$mp.page.$getAppWebview().setStyle({ ...@@ -99,34 +99,16 @@ this.$mp.page.$getAppWebview().setStyle({
#### 关于软键盘弹出的逻辑说明 #### 关于软键盘弹出的逻辑说明
App平台,软键盘弹出有adjustResize|adjustPan 两种模式 App平台软键盘弹出有 adjustResize|adjustPan 两种模式,默认为 adjustPan 模式,小程序平台只支持 adjustPan 模式,H5平台因不同浏览器而异
- adjustResize:软键盘弹出时,webview窗体高度挤压。屏幕高度=webview窗体高度+软键盘高度 - adjustResize:软键盘弹出时,webview窗体高度挤压。屏幕高度=webview窗体高度+软键盘高度
- adjustPan:软键盘弹出时,webview窗体高度不变,但窗体上推,以保证输入框不被软键盘盖住 - adjustPan:软键盘弹出时,webview窗体高度不变,但窗体上推,以保证输入框不被软键盘盖住
除了App平台,其他平台只支持adjustPan模式。App平台两种模式都支持,具体如下: 配置方式,在 pages.json 中配置 style
- Android:默认为adjustResize。配置修改只能在manifest中修改,全局生效。如果改为adjustPan,无法顺利上推窗体,底部的input会被软键盘盖住
- iOS平台:默认为adjustPan。配置可以在manifest中全局修改,也可以单独页面设置style。没有类似Android的局限。
如下为全局或页面的配置方式:
- 在manifest中配置
```json ```json
"app-plus": { "app-plus": {
"softinput": { "softinputMode": "adjustResize"
"mode": "adjustResize|adjustPan" // 软键盘弹出模式 }
}
}
```
- 如需要单个页面配置,则在pages.json中配置
```json
{
"path": "pages/component/input/input",
"style": {
"app-plus":{
"softinputMode": "adjustResize" //仅iOS支持单个页面配置
}
}
}
``` ```
App端开发聊天类应用时,目前推荐改为adjustResize模式。在hello uni-app的模板-聊天中有详细示例。 App端开发聊天类应用时,目前推荐改为adjustResize模式。在hello uni-app的模板-聊天中有详细示例。
......
#### list
app端nvue专用组件。
`<list>` 组件是提供垂直列表功能的核心组件,拥有平滑的滚动和高效的内存管理,非常适合用于长列表的展示。最简单的使用方法是在 `<list>` 标签内使用一组由简单数组循环生成的 `<cell>` 标签填充。
```
<template>
<list>
<cell v-for="num in lists">
<text>{{num}}</text>
</cell>
</list>
</template>
<script>
export default {
data () {
return {
lists: ['A', 'B', 'C', 'D', 'E']
}
}
}
</script>
```
> **注意**
> - 不允许相同方向的 `<list>` 或者 `<scroll-view>` 互相嵌套,换句话说就是嵌套的 `<list>` / `<scroll-view>` 必须是不同的方向。
> - `<list>` 需要显式的设置其宽高,可使用 position: absolute; 定位或 width、height 设置其宽高值。
#### 子组件
`<list>` 的子组件只能包括以下四种组件或是 fix 定位的组件,其他形式的组件将不能被正确渲染。
- `<cell>`<br>
用于定义列表中的子列表项,类似于 HTML 中的 ul 之于 li。`<list>` 会对 `<cell>` 进行高效的内存回收以达到更好的性能。
- `<header>`<br>`<header>` 到达屏幕顶部时,吸附在屏幕顶部。
- `<refresh>`<br>用于给列表添加下拉刷新的功能。
- `<loading>`<br>
`<loading>` 用法与特性和 `<refresh>` 类似,用于给列表添加上拉加载更多的功能。
#### 属性
|属性名|说明|类型|默认值|
|:-|:-|:-|:-|
|show-scrollbar|控制是否出现滚动条|boolean|true|
|loadmoreoffset|触发 loadmore 事件所需要的垂直偏移距离(设备屏幕底部与 list 底部之间的距离),建议手动设置此值,设置大于0的值即可|number|0|
|offset-accuracy|控制 onscroll 事件触发的频率:表示两次onscroll事件之间列表至少滚动了10px。注意,将该值设置为较小的数值会提高滚动事件采样的精度,但同时也会降低页面的性能|number|10|
|pagingEnabled|是否按分页模式线上List,默认值false|boolean|true/false|
|scrollable|是否运行List关系|boolean|true/false|
`loadmoreoffset` 示意图:
<img src="https://img-cdn-qiniu.dcloud.net.cn/app-nvue-component-list.png" />
#### 事件
- `loadmore` 事件
如果列表滚动到底部将会立即触发这个事件,你可以在这个事件的处理函数中加载下一页的列表项。 如果未触发,请检查是否设置了loadmoreoffset的值,建议此值设置大于0
- `scroll` 事件
列表发生滚动时将会触发该事件,事件的默认抽样率为 10px,即列表每滚动 10px 触发一次,可通过属性 offset-accuracy 设置抽样率。
事件中的 event 对象属性:
- `contentSize {Object}`:列表的内容尺寸
- `width {number}`:列表内容宽度
- `height {number}`:列表内容高度
- `contentOffset {Object}`:列表的偏移尺寸
- `x {number}`:x轴上的偏移量
- `y {number}`:y轴上的偏移量
- `isDragging {boolean}`: 用户是否正在拖动列表
...@@ -8,9 +8,9 @@ ...@@ -8,9 +8,9 @@
|5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序| |5+App|H5|微信小程序|支付宝小程序|百度小程序|头条小程序|
|:-:|:-:|:-:|:-:|:-:|:-:| |:-:|:-:|:-:|:-:|:-:|:-:|
|x|x|√|x|√|x| |x(见下)|x|√|x|√|x|
- 5+App的实时音视频播放,不是使用 live-player,而是直接使用 video 组件。 - App的实时音视频播放,不是使用 live-player,而是直接使用 video 组件。
- H5 下可用 video 播放符合 HTML5 规范的流媒体,rtmp 等非 HTML5 标准的流媒体格式,仅在部分支持 flash 的国内手机浏览器上可播放。在 pc 浏览器上,需要安装 flash 插件才能播放 rtmp 等格式。 - H5 下可用 video 播放符合 HTML5 规范的流媒体,rtmp 等非 HTML5 标准的流媒体格式,仅在部分支持 flash 的国内手机浏览器上可播放。在 pc 浏览器上,需要安装 flash 插件才能播放 rtmp 等格式。
...@@ -106,4 +106,4 @@ export default { ...@@ -106,4 +106,4 @@ export default {
} }
} }
} }
``` ```
\ No newline at end of file
...@@ -5,9 +5,9 @@ ...@@ -5,9 +5,9 @@
各平台开发方式暂未统一,使用时需注意用[条件编译](https://uniapp.dcloud.io/platform)调用不同平台的代码。 各平台开发方式暂未统一,使用时需注意用[条件编译](https://uniapp.dcloud.io/platform)调用不同平台的代码。
- 微信小程序:[规范文档](https://developers.weixin.qq.com/miniprogram/dev/component/live-pusher.html) - 微信小程序:[规范文档](https://developers.weixin.qq.com/miniprogram/dev/component/live-pusher.html)
- App平台:[业务指南](https://ask.dcloud.net.cn/article/13416)[规范文档](http://www.html5plus.org/doc/zh_cn/video.html#plus.video.LivePusher) - App平台:nvue文件下也支持live-pusher组件,功能API与微信相同。如果是vue文件,则需要单独编写条件编译代码,使用plus.video.LivePusher,[业务指南](https://ask.dcloud.net.cn/article/13416)[规范文档](http://www.html5plus.org/doc/zh_cn/video.html#plus.video.LivePusher)
**注意** **注意**
* live-pusher 是原生组件,层级高于前端组件,请勿在 scroll-view、swiper、picker-view、movable-view 中使用 * live-pusher 是原生组件,在小程序端层级高于前端组件,请勿在 scroll-view、swiper、picker-view、movable-view 中使用,需使用cover-view覆盖。在App端的nvue文件中,live-pusher没有这类限制。
* 解决 live-pusher 层级过高无法覆盖,[参考](/component/native-component) * App平台:使用 `<live-pusher/>` 组件,打包 App 时必须勾选 manifest.json->App 模块权限配置->LivePusher(直播推流) 模块。
\ No newline at end of file
...@@ -174,11 +174,12 @@ map 组件相关操作的 JS API:[uni.createMapContext](api/location/map?id=cr ...@@ -174,11 +174,12 @@ map 组件相关操作的 JS API:[uni.createMapContext](api/location/map?id=cr
**注意事项** **注意事项**
- 小程序和 App 中,`<map>` 组件是由引擎创建的原生组件,它的层级是最高的,不能通过 z-index 控制层级。在`<map>`上绘制内容,可使用组件自带的marker、controls等属性,也可以使用`<cover-view>`组件。App端还可以使用plus.nativeObj.view 或 subNVue 绘制原生内容。[详见](/component/native-component) - 小程序和 App的vue文件 中,`<map>` 组件是由引擎创建的原生组件,它的层级是最高的,不能通过 z-index 控制层级。在`<map>`上绘制内容,可使用组件自带的marker、controls等属性,也可以使用`<cover-view>`组件。App端还可以使用plus.nativeObj.view 或 subNVue 绘制原生内容,[参考](/component/native-component)。另外App端nvue文件不存在层级问题。
- App端nvue文件的map和小程序拉齐度更高。vue里的map则与plus.map一致,和小程序的地图略有差异。
- 小程序和 App 中,请勿在 scroll-view、swiper、picker-view、movable-view 中使用 `<map>` 组件。 - 小程序和 App 中,请勿在 scroll-view、swiper、picker-view、movable-view 中使用 `<map>` 组件。
- 小程序和 App 中,css 动画对 `<map>` 组件无效。 - 小程序和 App 中,css 动画对 `<map>` 组件无效。
- map 组件使用的经纬度是国测局坐标,调用 uni.getLocation 接口需要指定 type 为 gcj02。 - map 组件使用的经纬度是国测局坐标,调用 uni.getLocation 接口需要指定 type 为 gcj02。
- `<map>` 组件在不同平台的底层引擎是不同的:H5、微信小程序为腾讯地图;App、支付宝小程序为高德地图;百度小程序端为百度地图。App端也可以使用百度地图,在manifest的源码视图中配置,具体[参考](http://ask.dcloud.net.cn/article/29) - `<map>` 组件在不同平台的底层引擎是不同的:H5、微信小程序为腾讯地图;App、支付宝小程序为高德地图;百度小程序端为百度地图。App端vue页面也可以使用百度地图,在manifest中配置,但nvue页面只支持高德地图。
- map 组件默认的api是参考微信小程序的,如果觉得不够用,可以用plus.map,可以通过`$getAppMap`获取原生地图对象,[详见](https://uniapp.dcloud.io/api/location/map) - map 组件默认的api是参考微信小程序的,如果觉得不够用,可以用plus.map,可以通过`$getAppMap`获取原生地图对象,[详见](https://uniapp.dcloud.io/api/location/map)
- H5 端获取定位信息,需要部署在 **https** 服务上,本地预览(localhost)仍然可以使用 http 协议。 - H5 端获取定位信息,需要部署在 **https** 服务上,本地预览(localhost)仍然可以使用 http 协议。
- 无 GPS 模块的 PC 设备使用 Chrome 浏览器的时候,位置信息是连接谷歌服务器获取的,国内用户可能获取位置信息失败。 - 无 GPS 模块的 PC 设备使用 Chrome 浏览器的时候,位置信息是连接谷歌服务器获取的,国内用户可能获取位置信息失败。
......
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
|reLaunch|对应 uni.reLaunch 的功能|头条小程序不支持| |reLaunch|对应 uni.reLaunch 的功能|头条小程序不支持|
|navigateBack|对应 uni.navigateBack 的功能|&nbsp;| |navigateBack|对应 uni.navigateBack 的功能|&nbsp;|
**注意** **注意**
- navigator-hover 默认为 {background-color: rgba(0, 0, 0, 0.1); opacity: 0.7;}, ``<navigator>`` 的子节点背景色应为透明色。** - navigator-hover 默认为 {background-color: rgba(0, 0, 0, 0.1); opacity: 0.7;}, ``<navigator>`` 的子节点背景色应为透明色。**
- app-nvue 平台暂不支持 `<navigator>` - app-nvue 平台暂不支持 `<navigator>`
**示例** **示例**
...@@ -49,5 +49,26 @@ ...@@ -49,5 +49,26 @@
</template> </template>
``` ```
```javascript
// navigate.vue页面接受参数
export default {
onLoad: function (option) { //option为object类型,会序列化上个页面传递的参数
console.log(option.id); //打印出上个页面传递的参数。
console.log(option.name); //打印出上个页面传递的参数。
}
}
```
url有长度限制,太长的字符串会传递失败,可使用[窗体通信](https://uniapp.dcloud.io/collocation/frame/communication)[全局变量](https://ask.dcloud.net.cn/article/35021),或`encodeURIComponent`等多种方式解决,如下为`encodeURIComponent`示例。
```html
<navigator :url="'/pages/navigate/navigate?item='+ encodeURIComponent(JSON.stringify(item))"></navigator>
```
```javascript
// navigate.vue页面接受参数
onLoad: function (option) {
const item = JSON.parse(decodeURIComponent(option.item));
}
```
**注意** **注意**
- 跳转tabbar页面,必须设置open-type="switchTab" - 跳转tabbar页面,必须设置open-type="switchTab"
\ No newline at end of file
#### refresh
app端nvue专用组件。
`<refresh>` 为容器提供下拉刷新功能。
> 注意
> - `<refresh>` 是 `<scroll-view>`、`<list>`、`<waterfall>` 的子组件,只能在被它们包含时才能被正确渲染。
```
<scroll-view>
<refresh>
<text>Refreshing...</text>
</refresh>
<div v-for="num in lists">
<text>{{num}}</text>
</div>
</scroll-view>
```
#### 子组件
- 诸如 `<text>``<image>` 之类的任何组件,都可以放到 `<loading>` 进行渲染。
- 特殊子组件 `<loading-indicator>`: 只能作为 `<refresh>``<loading>` 的子组件使用,拥有默认的动画效果实现。
```
<refresh>
<text>Refreshing</text>
<loading-indicator></loading-indicator>
</refresh>
```
#### 属性
`display`
控制 `<refresh>` 组件显示、隐藏。`display` 的设置必须成对出现,即设置 `display="show"`, 必须有对应的 `display="hide"`。可选值为 `show / hide`,默认值为 `show`
#### 事件
- refresh 事件:当 `<scroll-view>``<list>``<waterfall>` 被下拉完成时触发。
- pullingdown 事件:当 `<scroll-view>``<list>``<waterfall>` 被下拉时触发。 可以从 `event` 参数对象中获取以下数据:
- `dy`: 前后两次回调滑动距离的差值
- `pullingDistance`: 下拉的距离
- `viewHeight`: refresh 组件高度
- `type`: “pullingdown” 常数字符串
```
<refresh @refresh="onrefresh" @pullingdown="onpullingdown" :display="refreshing ? 'show' : 'hide'">
<text>Refreshing ...</text>
<loading-indicator></loading-indicator>
</refresh>
```
...@@ -139,7 +139,7 @@ export default { ...@@ -139,7 +139,7 @@ export default {
* 其他端无法全屏后自行绘制内容 * 其他端无法全屏后自行绘制内容
- 如何实现抖音、映客等全屏视频垂直滑动切换效果? - 如何实现抖音、映客等全屏视频垂直滑动切换效果?
* 微信基础库 2.4.0 和app端nvue 2.1.5 以上,可通过在垂直的swiper中内嵌video来实现。原生导航栏设置为custom,视频长宽设为手机屏幕大小,通过cover-view覆盖视频内容。 * 微信基础库 2.4.0 和 app端nvue 2.1.5 以上,可通过在垂直的swiper中内嵌video来实现。原生导航栏设置为custom,视频长宽设为手机屏幕大小,通过cover-view覆盖视频内容。插件市场有相关[示例](https://ext.dcloud.net.cn/search?q=%E6%8A%96%E9%9F%B3)
- `<video/>` 组件在非H5端是原生组件,层级高于普通前端组件,覆盖其需要使用[cover-view](https://uniapp.dcloud.io/component/cover-view?id=cover-view)组件或plus.nativeObj.view、subNVue。微信基础库 2.4.0 起已支持 video 组件的同层渲染,也就是video在非全屏时,可以被前端元素通过调节zindex来遮挡,但video全屏时,仍需要cover-view覆盖。 - `<video/>` 组件在非H5端是原生组件,层级高于普通前端组件,覆盖其需要使用[cover-view](https://uniapp.dcloud.io/component/cover-view?id=cover-view)组件或plus.nativeObj.view、subNVue。微信基础库 2.4.0 起已支持 video 组件的同层渲染,也就是video在非全屏时,可以被前端元素通过调节zindex来遮挡,但video全屏时,仍需要cover-view覆盖。
- 除微信基础库 2.4.0 和app端nvue页面 2.1.5 以上,其他情况下非H5的video不能放入scroll-view和swiper。注意参考 [原生组件使用限制](/component/native-component) - 除微信基础库 2.4.0 和app端nvue页面 2.1.5 以上,其他情况下非H5的video不能放入scroll-view和swiper。注意参考 [原生组件使用限制](/component/native-component)
......
#### waterfall
app端nvue专用组件。
`<waterfall>` 组件是提供瀑布流布局的核心组件。瀑布流,又称瀑布流式布局是比较流行的一种页面布局,视觉表现为参差不齐的多栏布局。随着页面滚动条向下滚动,这种布局还可以不断加载数据块并附加至当前尾部。
```
<template>
<waterfall column-count="2" column-width="auto">
<cell v-for="num in lists" >
<text>{{num}}</text>
</cell>
</waterfall>
</template>
<script>
export default {
data () {
return {
lists: ['A', 'B', 'C', 'D', 'E']
}
}
}
</script>
<style></style>
```
#### 子组件
`<list>` 组件一样, `<waterfall>` 组件的子组件只能包括以下四种组件或是 fix 定位的组件,其他形式的组件将不能被正确渲染。
- `<cell>`:用于定义列表中的子列表项,类似于 HTML 中的 ul 之于 li。`<waterfall>` 会对 `<cell>` 进行高效的内存回收以达到更好的性能。
- `<header>`:当 `<header>` 到达屏幕顶部时,吸附在屏幕顶部。
- `<refresh>`:用于给列表添加下拉刷新的功能。
- `<loading>``<loading>` 用法与特性和 `<refresh>` 类似,用于给列表添加上拉加载更多的功能。
<img src="https://img-cdn-qiniu.dcloud.net.cn/app-nvue-component-waterfall-01.png" />
#### 属性
- show-scrollbar : `[可选]` 可选值为 true/ false,默认值为 true。控制是否出现滚动条。
- column-count: `[可选]`描述瀑布流的列数
- auto: 意味着列数是被其他属性所决定的(比如 column-width)
- `<integer>`: 最佳列数,column-width 和 column-count 都指定非0值, 则 column-count 代表最大列数。
- column-width : `[可选]`描述瀑布流每一列的列宽
- `auto`: 意味着列宽是被其他属性所决定的(比如 column-count)
- `<length>`: 最佳列宽,实际的列宽可能会更宽(需要填充剩余的空间), 或者更窄(如果剩余空间比列宽还要小)。 该值必须大于0
- column-gap: [可选]列与列的间隙. 如果指定了 `normal` ,则对应 32.
- left-gap: [可选]左边cell和列表的间隙. 如果未指定 ,则对应 `0`
- right-gap: [可选]右边cell和列表的间隙. 如果未指定,则对应 `0`
<img src="https://img-cdn-qiniu.dcloud.net.cn/app-nvue-component-waterfall-02.png" />
其他支持的属性参见 `<list>` 组件属性部分
#### 事件
支持所有通用事件:
- click:用于监听点击事件。(例如:一般绑定于子组件之上触发跳转)。
- longpress:用于监听长按事件(一般绑定于子组件之上例如:长按可删除)。
- appear:用于监听子组件出现事件(一般绑定于子组件之上例如:监听最后一个元素出现,加载新的数据)
- disappear:用于监听子组件滑出屏幕事件(一般绑定于子组件之上)
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
**原生控件层级过高无法覆盖的解决方案:**[https://uniapp.dcloud.io/component/native-component](https://uniapp.dcloud.io/component/native-component) **原生控件层级过高无法覆盖的解决方案:**[https://uniapp.dcloud.io/component/native-component](https://uniapp.dcloud.io/component/native-component)
**uni-app 各环节(HBuilderX、cli、自定义基座、本地sdk、云打包引擎)版本兼容性说明:**[https://ask.dcloud.net.cn/article/35845](https://ask.dcloud.net.cn/article/35845) **uni-app 各环节(HBuilderX、cli、自定义基座、本地sdk、云打包引擎)版本兼容性说明:**[https://ask.dcloud.net.cn/article/35845](https://ask.dcloud.net.cn/article/35845)
**uni-app 中选择和上传非图像、视频文件:**[https://ask.dcloud.net.cn/article/35547](https://ask.dcloud.net.cn/article/35547) **uni-app 中选择和上传非图像、视频文件:**[https://ask.dcloud.net.cn/article/35547](https://ask.dcloud.net.cn/article/35547)
**国际化/多语言/i18n方案:**[https://ask.dcloud.net.cn/article/35872](https://ask.dcloud.net.cn/article/35872) **国际化/多语言/i18n方案:**[https://ask.dcloud.net.cn/article/35872](https://ask.dcloud.net.cn/article/35872)
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
**uni-app App资源热更新:** [https://ask.dcloud.net.cn/article/35667](https://ask.dcloud.net.cn/article/35667) **uni-app App资源热更新:** [https://ask.dcloud.net.cn/article/35667](https://ask.dcloud.net.cn/article/35667)
**App初期启动的引导轮播:**因为是App专用,为了更好的性能,推荐使用nvue制作。也可以参考插件市场已经封装的插件[https://ext.dcloud.net.cn/plugin?id=192](https://ext.dcloud.net.cn/plugin?id=192) **App初期启动的引导轮播:** 因为是App专用,为了更好的性能,推荐使用nvue制作。参考插件市场已经封装的插件[https://ext.dcloud.net.cn/plugin?id=676](https://ext.dcloud.net.cn/plugin?id=676)
**App全面屏底部安全区适配:**[https://ask.dcloud.net.cn/article/35564](https://ask.dcloud.net.cn/article/35564) **App全面屏底部安全区适配:**[https://ask.dcloud.net.cn/article/35564](https://ask.dcloud.net.cn/article/35564)
**App权限状态判断及引导:**[https://ext.dcloud.net.cn/plugin?id=594](https://ext.dcloud.net.cn/plugin?id=594) **App权限状态判断及引导:**[https://ext.dcloud.net.cn/plugin?id=594](https://ext.dcloud.net.cn/plugin?id=594)
......
...@@ -172,6 +172,10 @@ if(process.env.NODE_ENV === 'development'){ ...@@ -172,6 +172,10 @@ if(process.env.NODE_ENV === 'development'){
} }
``` ```
如果你需要自定义更多环境,比如测试环境:
- 假设只需要对单一平台配置,可以 package.json 中配置,在HBuilderX的运行和发行菜单里会多一个出来。[https://uniapp.dcloud.io/collocation/package](https://uniapp.dcloud.io/collocation/package)
- 如果是针对所有平台配置,可以在 vue-config.js 中配置。[https://uniapp.dcloud.io/collocation/vue-config](https://uniapp.dcloud.io/collocation/vue-config)
**快捷代码块** **快捷代码块**
HBuilderX 中敲入代码块 `uEnvDev`、`uEnvProd` 可以快速生成对应 `development`、`production` 的运行环境判定代码。 HBuilderX 中敲入代码块 `uEnvDev`、`uEnvProd` 可以快速生成对应 `development`、`production` 的运行环境判定代码。
...@@ -238,10 +242,10 @@ nvue还不支持百分比单位。 ...@@ -238,10 +242,10 @@ nvue还不支持百分比单位。
App端,在 pages.json 里的 titleNView 或页面里写的 plus api 中涉及的单位,只支持 px。**注意此时不支持 rpx** App端,在 pages.json 里的 titleNView 或页面里写的 plus api 中涉及的单位,只支持 px。**注意此时不支持 rpx**
nvue中,uni-app 模式([nvue 不同编译模式介绍](https://ask.dcloud.net.cn/article/36074))可以使用 px 、rpx,表现与 vue 中一致。weex 模式目前遵循weex的单位,它的单位比较特殊: nvue中,uni-app 模式([nvue 不同编译模式介绍](https://ask.dcloud.net.cn/article/36074))可以使用 px 、rpx,表现与 vue 中一致。weex 模式目前遵循weex的单位,它的单位比较特殊:
- px:,以750宽的屏幕为基准动态计算的长度单位,与 vue 页面中的 rpx 理念相同。(一定要注意 weex 模式的 px,和 vue 里的 px 逻辑不一样。) - px:,以750宽的屏幕为基准动态计算的长度单位,与 vue 页面中的 rpx 理念相同。(一定要注意 weex 模式的 px,和 vue 里的 px 逻辑不一样。)
- wx:与设备屏幕宽度无关的长度单位,与 vue 页面中的 px 理念相同 - wx:与设备屏幕宽度无关的长度单位,与 vue 页面中的 px 理念相同
下面对 `rpx` 详细说明: 下面对 `rpx` 详细说明:
...@@ -909,10 +913,197 @@ slide-view.vue ...@@ -909,10 +913,197 @@ slide-view.vue
详细的小程序转uni-app语法差异可参考文档[https://ask.dcloud.net.cn/article/35786](https://ask.dcloud.net.cn/article/35786)。 详细的小程序转uni-app语法差异可参考文档[https://ask.dcloud.net.cn/article/35786](https://ask.dcloud.net.cn/article/35786)。
## WXS
WXS是微信小程序的一套脚本语言,[规范详见](https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxs/)。
uni-app可以将wxs代码编译到微信小程序、QQ小程序、5+APP上(`HBuilderX 2.2.4-alpha`及以上版本)
与wxs类似,百度小程序提供了Filter、阿里小程序提供了SJS,uni-app也支持使用这些功能,并将它们编译到百度和阿里的小程序端。不过它们的功能还不如wxs强大。此外头条系小程序自身不支持类似功能。
**wxs示例**
以下是一些使用 WXS 的简单示例,要完整了解 WXS 语法,请参考[WXS 语法参考](https://developers.weixin.qq.com/miniprogram/dev/reference/wxs/)。本示例使用wxs响应touchmove事件,减少视图层与逻辑层通信,使滑动更加丝滑。
```html
<template>
<view>
<view class="area">
<view @touchstart="test.touchstart" @touchmove="test.touchmove" class="movable">{{test.msg}}</view>
</view>
</view>
</template>
<wxs module="test">
var startX = 0
var startY = 0
var lastLeft = 50; var lastTop = 50
function touchstart(event, ins) {
console.log("touchstart")
var touch = event.touches[0] || event.changedTouches[0]
startX = touch.pageX
startY = touch.pageY
}
function touchmove(event, ins) {
var touch = event.touches[0] || event.changedTouches[0]
var pageX = touch.pageX
var pageY = touch.pageY
var left = pageX - startX + lastLeft
var top = pageY - startY + lastTop
startX = pageX
startY = pageY
lastLeft = left
lastTop = top
ins.selectComponent('.movable').setStyle({
left: left + 'px',
top: top + 'px'
})
return false
}
module.exports = {
msg: 'Hello',
touchstart: touchstart,
touchmove: touchmove
}
</wxs>
<script>
export default {
data() {
return {
}
},
methods: {
}
}
</script>
<style>
.area{
position: absolute;
width: 100%;
height: 100%;
}
.movable{
position: absolute;
width: 100px;
height: 100px;
left: 50px;
top: 50px;
color: white;
text-align: center;
line-height: 100px;
background-color: red;
}
</style>
```
支付宝小程序,百度小程序官方暂未支持事件响应,不过也可以使用对应的SJS、Filter过滤器实现一些数据处理的操作,以下代码展示了一个时间格式化的小功能
index.vue
```html
<template>
<view>
<view>
{{timestr}} 是
</view>
<view>
{{utils.friendlyDate(timestamp)}}
</view>
</view>
</template>
<filter module="utils" src="./utils.filter.js"></filter>
<import-sjs module="utils" src="./utils.sjs" />
<script>
export default {
data() {
return {
timestr: '2019/08/22 10:10:10',
timestamp: 0
}
},
created() {
this.timestamp = new Date(this.timestr).getTime()
},
methods: {
}
}
</script>
```
utils.sjs 与 utils.filter.js
```js
export default {
friendlyDate: (timestamp) => {
var formats = {
'year': '%n% 年前',
'month': '%n% 月前',
'day': '%n% 天前',
'hour': '%n% 小时前',
'minute': '%n% 分钟前',
'second': '%n% 秒前',
};
var now = Date.now();
var seconds = Math.floor((now - parseInt(timestamp)) / 1000);
var minutes = Math.floor(seconds / 60);
var hours = Math.floor(minutes / 60);
var days = Math.floor(hours / 24);
var months = Math.floor(days / 30);
var years = Math.floor(months / 12);
var diffType = '';
var diffValue = 0;
if (years > 0) {
diffType = 'year';
diffValue = years;
} else {
if (months > 0) {
diffType = 'month';
diffValue = months;
} else {
if (days > 0) {
diffType = 'day';
diffValue = days;
} else {
if (hours > 0) {
diffType = 'hour';
diffValue = hours;
} else {
if (minutes > 0) {
diffType = 'minute';
diffValue = minutes;
} else {
diffType = 'second';
diffValue = seconds === 0 ? (seconds = 1) : seconds;
}
}
}
}
}
return formats[diffType].replace('%n%', diffValue);
}
}
```
**注意**
- **重要**编写wxs、sjs、filter.js 内容时必须遵循相应语法规范
- 目前各个小程序正在完善相关规范,可能会有较大改动,请务必仔细阅读相应平台的文档
- 支付宝小程序请使用sjs规范,[详见](https://docs.alipay.com/mini/framework/sjs)
- 支付宝小程序sjs只能定义在.sjs 文件中。然后使用```<import-sjs>```标签引入
- 支付宝小程序import-sjs的标签属性```name```、```from```被统一为了```module```、```src```以便后续实现多平台统一写法
- 百度小程序中请使用Filter规范,[详见](https://smartprogram.baidu.com/docs/develop/framework/view_filter/)
- 百度小程序Filter只能导出function函数
- 暂不支持在 wxs、sjs、filter.js 中调用其他同类型文件
- wxs、filter.js既能内联使用又可以外部引入,sjs只能外部引入
- mp-qq 目前对内联的 wxs 支持不好,部分写法会导致编译出错
## 致谢 ## 致谢
```uni-app```的设计使用了 ```vue + 自定义组件``` 的模式;开发者使用```Vue```语法,了解```uni-app```的组件,就可以开发跨端App;感谢```Vue```团队! ```uni-app```的设计使用了 ```vue + 自定义组件``` 的模式;开发者使用```Vue```语法,了解```uni-app```的组件,就可以开发跨端App;感谢```Vue```团队!
为了照顾开发者的已有学习积累,```uni-app```的组件和api设计,基本参考了微信小程序,学过微信小程序开发,了解```vue```,就能直接上手```uni-app```;感谢微信小程序团队! 为了照顾开发者的已有学习积累,```uni-app```的组件和api设计,基本参考了微信小程序,学过微信小程序开发,了解```vue```,就能直接上手```uni-app```;感谢微信小程序团队!
```uni-app``` 在小程序端,曾引用[mpvue](http://mpvue.com/)[Megalo](https://megalojs.org/),感谢美团点评技术团队、网易考拉团队的贡献! ```uni-app``` 在小程序端,学习参考了[mpvue](https://mpvue.com/)[Megalo](https://megalojs.org/),感谢美团点评技术团队、网易考拉团队!
\ No newline at end of file
...@@ -56,14 +56,14 @@ H5没有原生组件概念问题,非H5端有原生组件并引发了原生组 ...@@ -56,14 +56,14 @@ H5没有原生组件概念问题,非H5端有原生组件并引发了原生组
title: 'Hello' title: 'Hello'
} }
``` ```
3. 在微信小程序端,```uni-app``` 将数据绑定功能委托给```Vue```,开发者需按```Vue 2.0```的写法实现数据绑定,不支持微信小程序的数据绑定写法,故如下写法不支持: 3. 在微信小程序端,```uni-app``` 将数据绑定功能委托给```Vue```,开发者需按```Vue 2.0```的写法实现数据绑定,不支持微信小程序的数据绑定写法,故如下写法不支持:
```javascript ```javascript
<view id="item-{{id}}"></view> <view id="item-{{id}}"></view>
``` ```
需修改为: 需修改为:
```javascript ```javascript
<view v-bind:id="'item-' + id "></view> <view v-bind:id="'item-' + id "></view>
``` ```
### 区别于传统 web 开发的注意 ### 区别于传统 web 开发的注意
...@@ -87,9 +87,9 @@ H5没有原生组件概念问题,非H5端有原生组件并引发了原生组 ...@@ -87,9 +87,9 @@ H5没有原生组件概念问题,非H5端有原生组件并引发了原生组
- 每个要显示的页面,都要放到pages目录下,新建一个页面所在的目录,然后放同名目录的vue文件,比如project/pages/lista/lista.vue,并且在pages.json里配置。这与小程序的策略相同。 - 每个要显示的页面,都要放到pages目录下,新建一个页面所在的目录,然后放同名目录的vue文件,比如project/pages/lista/lista.vue,并且在pages.json里配置。这与小程序的策略相同。
- 自定义组件,放到component目录 - 自定义组件,放到component目录
- 静态资源如图片,固定放到static目录下。这是webpack、mpvue的规则 - 静态资源如图片,固定放到static目录下。这是webpack、mpvue的规则
5. 数据绑定方式的注意 5. 数据绑定方式的注意
- ```uni-app``` 基于```Vue 2.0```实现,开发者需注意Vue 1.0 -> 2.0 的使用差异,详见[从 Vue 1.x 迁移](https://cn.vuejs.org/v2/guide/migration.html) - ```uni-app``` 基于```Vue 2.0```实现,开发者需注意Vue 1.0 -> 2.0 的使用差异,详见[从 Vue 1.x 迁移](https://cn.vuejs.org/v2/guide/migration.html)
- -
6. 每个页面支持使用原生title,首页支持使用原生底部tab,这些是要在pages.json里配置,这些并不是vue页面的一部分。当然vue里的js api也可以动态修改原生title 6. 每个页面支持使用原生title,首页支持使用原生底部tab,这些是要在pages.json里配置,这些并不是vue页面的一部分。当然vue里的js api也可以动态修改原生title
6. 虽然使用vue,但在app和小程序里,不是spa而是mpa 6. 虽然使用vue,但在app和小程序里,不是spa而是mpa
7. 位置坐标系统一为国测局坐标系gcj02,这种坐标系可以被多端支持。老版5+的百度定位和百度地图使用的是百度私有坐标系bd09ll,这种坐标系需要转换。新版uni-app里的百度地图已经默认改为gcj02。高德地图不受影响,一直是gcj02 7. 位置坐标系统一为国测局坐标系gcj02,这种坐标系可以被多端支持。老版5+的百度定位和百度地图使用的是百度私有坐标系bd09ll,这种坐标系需要转换。新版uni-app里的百度地图已经默认改为gcj02。高德地图不受影响,一直是gcj02
...@@ -98,14 +98,14 @@ H5没有原生组件概念问题,非H5端有原生组件并引发了原生组 ...@@ -98,14 +98,14 @@ H5没有原生组件概念问题,非H5端有原生组件并引发了原生组
* H5 发布到服务器注意: * H5 发布到服务器注意:
1. 配置发行后的路径(发行在网站根目录可不配置),比如发行网站路径是 www.xxx.com/html5,在 ``manifest.json`` 文件内编辑 h5 节点,router 下增加 base 属性为 html5 1. 配置发行后的路径(发行在网站根目录可不配置),比如发行网站路径是 www.xxx.com/html5,在 ``manifest.json`` 文件内编辑 h5 节点,router 下增加 base 属性为 html5
<div> <div>
<img src="https://img-cdn-qiniu.dcloud.net.cn/uploads/article/20181116/6ab94f68e109bb07e4f422c95a2c9015.png" width="500"> <img src="https://img-cdn-qiniu.dcloud.net.cn/uploads/article/20181116/6ab94f68e109bb07e4f422c95a2c9015.png" width="500">
</div> </div>
2. 点击菜单 发行-> H5 2. 点击菜单 发行-> H5
3. 在当下项目下的 ``unpackage/dist/build/h5`` 目录找到出的资源,部署服务器(或者使用本地服务器预览) 3. 在当下项目下的 ``unpackage/dist/build/h5`` 目录找到出的资源,部署服务器(或者使用本地服务器预览)
* 引用第三方 js 的方式: * 引用第三方 js 的方式:
1. 通过 npm 引入(通过条件编译,只有是 h5 平台才 import 相应的库) 1. 通过 npm 引入(通过条件编译,只有是 h5 平台才 import 相应的库)
2.``manifest.json`` 文件编辑 h5 节点的 template 属性,填写 html 模版路径,在 html 模版里面可以使用 script 的方式引入三方的 js,如下示例是加了百度统计的 html 模板部分代码,模版全部代码可参考:[自定义模板](/collocation/manifest?id=h5-template) 2.``manifest.json`` 文件编辑 h5 节点的 template 属性,填写 html 模版路径,在 html 模版里面可以使用 script 的方式引入三方的 js,如下示例是加了百度统计的 html 模板部分代码,模版全部代码可参考:[自定义模板](/collocation/manifest?id=h5-template)
``` ```
... ...
...@@ -186,4 +186,4 @@ H5没有原生组件概念问题,非H5端有原生组件并引发了原生组 ...@@ -186,4 +186,4 @@ H5没有原生组件概念问题,非H5端有原生组件并引发了原生组
* ``map`` 组件在开发工具上预览效果不对,但是手机上是对的。 * ``map`` 组件在开发工具上预览效果不对,但是手机上是对的。
* ``getSystemInfo`` 获取到的 ``windowHeight`` 在模拟器中值不正确,真机预览是正确的。 * ``getSystemInfo`` 获取到的 ``windowHeight`` 在模拟器中值不正确,真机预览是正确的。
* ``v-if````v-for`` 不可在同一标签下同时使用。 * ``v-if````v-for`` 不可在同一标签下同时使用。
* 页面中引入自定义组件时,渲染的结果中外层会有一个 ``template`` 标签,这会导致部分选择器对应的样式匹配不上。 * 页面中引入自定义组件时,渲染的结果中外层会有一个 ``template`` 标签,这会导致部分选择器对应的样式匹配不上。
\ No newline at end of file
...@@ -218,6 +218,8 @@ npm run build:%PLATFORM% ...@@ -218,6 +218,8 @@ npm run build:%PLATFORM%
|mp-toutiao|头条小程序| |mp-toutiao|头条小程序|
|mp-qq|qq 小程序| |mp-qq|qq 小程序|
可以自定义更多条件编译平台,比如钉钉小程序,参考[package.json文档](https://uniapp.dcloud.io/collocation/package)
**其他:** **其他:**
* dev 模式编译出的各平台代码存放于根目录下的 ``/dist/dev/``目录,打开各平台开发工具选择对应平台目录即可进行预览(h5 平台不会在此目录,存在于缓存中); * dev 模式编译出的各平台代码存放于根目录下的 ``/dist/dev/``目录,打开各平台开发工具选择对应平台目录即可进行预览(h5 平台不会在此目录,存在于缓存中);
...@@ -237,10 +239,10 @@ npm run build:%PLATFORM% ...@@ -237,10 +239,10 @@ npm run build:%PLATFORM%
* ``cli``版如果想安装less、scss、ts等编译器,需自己手动npm安装。在HBuilderX的插件管理界面安装无效,那个只作用于HBuilderX创建的项目。 * ``cli``版如果想安装less、scss、ts等编译器,需自己手动npm安装。在HBuilderX的插件管理界面安装无效,那个只作用于HBuilderX创建的项目。
#### 开发工具的区别 #### 开发工具的区别
* ``cli``创建的项目,内置了d.ts,同其他常规npm库一样,可在vscode、webstorm等支持d.ts的开发工具里正常开发并有语法提示。 * ``cli``创建的项目,内置了d.ts,同其他常规npm库一样,可在[vscode](https://ask.dcloud.net.cn/article/36286)[webstorm](https://ask.dcloud.net.cn/article/36307)等支持d.ts的开发工具里正常开发并有语法提示。
* 使用HBuilderX创建的项目不带d.ts,拖到其他工具里不会有代码提示。此时可以在项目下执行 ``npm i @types/uni-app -D``,来补充d.ts * 使用HBuilderX创建的项目不带d.ts,此时可以在项目下执行 ``npm i @types/uni-app -D``,来补充d.ts
* 但vscode等其他开发工具,在vue或uni-app领域,开发效率比不过HBuilderX。详见:[https://ask.dcloud.net.cn/article/35451](https://ask.dcloud.net.cn/article/35451) * 但vscode等其他开发工具,在vue或uni-app领域,开发效率比不过HBuilderX。详见:[https://ask.dcloud.net.cn/article/35451](https://ask.dcloud.net.cn/article/35451)
* 发布App时,仍然需要使用HBuilderX。其他开发工具无法发布App,但可以发布H5、各种小程序。 * 发布App时,仍然需要使用HBuilderX。其他开发工具无法发布App,但可以发布H5、各种小程序。如需开发App,可以先在HBuilderX里运行起来,然后在其他编辑器里修改保存代码,代码修改后会自动同步到手机基座。
* 如果使用``cli``创建项目,那下载HBuilderX时只需下载10M的标准版即可。因为编译器已经安装到项目下了。 * 如果使用``cli``创建项目,那下载HBuilderX时只需下载10M的标准版即可。因为编译器已经安装到项目下了。
*`cli` 使用有疑问,欢迎扫码加入 uni-app 微信交流群讨论: *`cli` 使用有疑问,欢迎扫码加入 uni-app 微信交流群讨论:
<br/><img src="http://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/wx-barcode.png" width="250"/> <br/><img src="http://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/wx-barcode.png" width="250"/>
此差异已折叠。
...@@ -10,14 +10,43 @@ ...@@ -10,14 +10,43 @@
如果你已经是 weex 的开发者,具有 weex 的填坑能力,那么 nvue 是你的更优选择,能切实提升你的开发效率,降低成本。 如果你已经是 weex 的开发者,具有 weex 的填坑能力,那么 nvue 是你的更优选择,能切实提升你的开发效率,降低成本。
如果你不开发App,那么你不太需要nvue。
如果你是web前端,不熟悉 weex,那么建议你仍然以使用 vue 为主,在App端某些 vue 表现不佳的场景下使用 nvue 作为强化补充: 如果你是web前端,不熟悉 weex,那么建议你仍然以使用 vue 为主,在App端某些 vue 表现不佳的场景下使用 nvue 作为强化补充:
- 左右拖动的长列表。在webview里,通过swiper+scroll-view实现左右拖动的长列表,前端模拟下拉刷新,这套方案的性能不好。此时推荐使用nvue,比如新建uni-app项目时的新闻示例模板,就是首页采用了nvue - 左右拖动的长列表。在webview里,通过swiper+scroll-view实现左右拖动的长列表,前端模拟下拉刷新,这套方案的性能不好。此时推荐使用nvue,比如新建uni-app项目时的新闻示例模板,就是首页采用了nvue
- 为了解决 vue 页面的原生控件层级问题和原生导航栏的灵活自定义问题,uni-app 还提供了 subnvue 方案,将一个非全屏的 nvue 页面覆盖到 vue 页面上,[详见](https://ask.dcloud.net.cn/article/35948) - 如需要将软键盘右下角按钮文字改为“发送”,则需要使用nvue
- 前端控件无法覆盖原生控件的问题。在nvue下,都是原生控件,覆盖map、video等不需要cover-view(如需要发布到小程序,仍然推荐写cover-view)
- 同样因为层级问题得到解决,nvue可以实现video内嵌到swiper中,以实现抖音式视频滑动切换,例子见[插件市场](https://ext.dcloud.net.cn/plugin?id=664);nvue的视频全屏后,仍然可以通过cover-view实现内容覆盖,比如增加文字标题、分享按钮。
- nvue下有live-pusher组件,和小程序对齐。而vue页面下使用直播,需在条件编译里单独调用plus.video的API。
- nvue下的map组件,小程序对齐。而vue页面的map组件有一些差异。
- App端实现粘性布局,比如滚动吸顶,则nvue才能保证高性能,例子见[插件市场](https://ext.dcloud.net.cn/plugin?id=715)
此外,App端,vue页面上也可以覆盖subnvue(一种非全屏的nvue页面覆盖在webview上),以解决App上的原生控件层级问题。[详见](https://ask.dcloud.net.cn/article/35948)
## 项目渲染模式
uni-app在App端,支持vue页面和nvue页面混搭、互相跳转。也支持纯nvue项目。
在manifest.json源码视图的`"app-plus"`下配置`"renderer":"native"`,即代表App端启用纯原生渲染模式。此时pages.json注册的vue页面将被忽略,vue组件中的代码也需覆盖nvue规范,并会被原生渲染。
启动纯原生渲染,可以减少App端的包体积、加快App启动速度。因为webview渲染模式的相关模块将被移除。
如果不指定该值,默认是不启动纯原生渲染的。
```json
// manifest.json
{
// ...
/* App平台特有配置 */
"app-plus": {
"renderer": "native", //App端纯原生渲染模式
}
}
```
## 编译模式差异 ## nvue页面编译模式差异
uni-app 深度改进了 weex,提供了2种编译模式,一种是常规的 weex 组件模式,即编写`<div>`。另一种是 uni-app 组件模式,即编写`<view>`。后者更提供了编译为小程序和H5的能力。 uni-app 深度改进了 weex,提供了2种编译模式,一种是常规的 weex 组件模式,即编写`<div>`。另一种是 uni-app 组件模式,即编写`<view>`。后者更提供了编译为小程序和H5的能力,实现了全端输出
也可以理解为uni-app做了一个原生渲染的小程序引擎。 也可以理解为uni-app做了一个原生渲染的小程序引擎。
...@@ -31,7 +60,7 @@ uni-app 深度改进了 weex,提供了2种编译模式,一种是常规的 we ...@@ -31,7 +60,7 @@ uni-app 深度改进了 weex,提供了2种编译模式,一种是常规的 we
|全局样式 |手动引入 |app.vue的样式即为全局样式 | |全局样式 |手动引入 |app.vue的样式即为全局样式 |
|页面滚动 |必须给页面套<list>或<scroller>组件 |默认支持页面滚动 | |页面滚动 |必须给页面套<list>或<scroller>组件 |默认支持页面滚动 |
修改2种编译模式的在 manifest.json 中,`manifest.json` -> `app-plus` -> `nvueCompiler` 切换编译模式。 在 manifest.json 中修改2种编译模式,`manifest.json` -> `app-plus` -> `nvueCompiler` 切换编译模式。
`nvueCompiler` 有两个值: `nvueCompiler` 有两个值:
- weex - weex
...@@ -50,21 +79,19 @@ uni-app 深度改进了 weex,提供了2种编译模式,一种是常规的 we ...@@ -50,21 +79,19 @@ uni-app 深度改进了 weex,提供了2种编译模式,一种是常规的 we
``` ```
* 如果没有在manifest里明确配置,默认是weex模式。这是为了向下兼容。 * 如果没有在manifest里明确配置,默认是weex模式。这是为了向下兼容。
* 当前uni-app编译模式组件还不够完整,详细列表见 [https://ask.dcloud.net.cn/article/36074](https://ask.dcloud.net.cn/article/36074),但已经可满足常用场景。比如左右拖动的长列表场景推荐使用uni-app编译模式的nvue,其他页面仍然可使用 vue 页面。新建uni-app项目选模板`新闻/资讯模板`,这是一个nvue页面可编译到全平台的示例。
## 快速上手 ## 快速上手
### 1. 新建 nvue 页面 ### 1. 新建 nvue 页面
``uni-app`` 项目中,选中文件或文件夹,鼠标右击选择新建 ``nvue`` 文件输入文件名创建。 HBuilderX的 ``uni-app`` 项目中,新建页面,弹出界面右上角可以选择是建立vue页面还是nvue页面,或者2个同时建。
不管是vue页面还是nvue页面,都需要在pages.json中注册。 不管是vue页面还是nvue页面,都需要在pages.json中注册。如果在HBuilderX中新建页面是会自动注册的,如果使用其他编辑器,则需要自行在pages.json里注册。
如果一个页面路由下同时有vue页面和nvue页面,那么在App端,会优先使用nvue页面。 如果一个页面路由下同时有vue页面和nvue页面,即出现同名的vue和nvue文件。那么在App端,会优先使用nvue页面,同名的vue文件将不会被编译到App端。而在非App端,会优先使用vue页面。
在非app端,只有uni-app编译模式的nvue才会编译。 如果不同名,只有nvue页面,则在非app端,只有uni-app编译模式的nvue文件才会编译。
![](https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/created-nvue.png)
### 2. 开发 nvue 页面 ### 2. 开发 nvue 页面
...@@ -118,7 +145,7 @@ uni-app 深度改进了 weex,提供了2种编译模式,一种是常规的 we ...@@ -118,7 +145,7 @@ uni-app 深度改进了 weex,提供了2种编译模式,一种是常规的 we
### 3. 调试 nvue 页面 ### 3. 调试 nvue 页面
HBuilderX内置了更好用的weex/uni-app调试工具,[详见](https://uniapp.dcloud.io/snippet?id=%e5%85%b3%e4%ba%8e-app-%e7%9a%84%e8%b0%83%e8%af%95) HBuilderX内置了更好用的weex/uni-app调试工具,包括审查界面元素、看log、debug打断点,[详见](https://uniapp.dcloud.io/snippet?id=%e5%85%b3%e4%ba%8e-app-%e7%9a%84%e8%b0%83%e8%af%95)
## 生命周期 ## 生命周期
...@@ -343,6 +370,7 @@ Tis: ...@@ -343,6 +370,7 @@ Tis:
* 使用方式可参考 [BindingX 快速开始](https://alibaba.github.io/bindingx/guide/cn_guide_start),demo示例可参考 [BindingX 示例](https://alibaba.github.io/bindingx/demos)``vue`` 的相关示例,将实验田里的 ``vue`` 代码拷贝到 ``nvue`` 文件里即可。 * 使用方式可参考 [BindingX 快速开始](https://alibaba.github.io/bindingx/guide/cn_guide_start),demo示例可参考 [BindingX 示例](https://alibaba.github.io/bindingx/demos)``vue`` 的相关示例,将实验田里的 ``vue`` 代码拷贝到 ``nvue`` 文件里即可。
* 若引入 weex-bindingx 时发现不生效,检查项目路径,路径不能含有中文。 * 若引入 weex-bindingx 时发现不生效,检查项目路径,路径不能含有中文。
* 使用npm时如果命令行报错,需要注意看命令行的提示
**代码示例** **代码示例**
...@@ -556,152 +584,152 @@ App.vue ...@@ -556,152 +584,152 @@ App.vue
``` ```
## nvue 里可使用的 uni-app API ## nvue 里可使用的 uni-app API
`nvue` 支持大部分 uni-app API ,下面只列举目前还不支持的 API 。 `nvue` 支持大部分 uni-app API ,下面只列举目前还不支持的 API 。
**地图** **地图**
|API|说明| |API|说明|
|:-|:-| |:-|:-|
|uni.createMapContext()|创建并返回 map 上下文| |uni.createMapContext()|创建并返回 map 上下文|
**视频** **视频**
|API|说明| |API|说明|
|:-|:-| |:-|:-|
|uni.createVideoContext()|创建并返回 video 上下文| |uni.createVideoContext()|创建并返回 video 上下文|
**直播推流** **直播推流**
|API|说明| |API|说明|
|:-|:-| |:-|:-|
|uni.createLivePusherContext()|创建并返回 livePusher 上下文| |uni.createLivePusherContext()|创建并返回 livePusher 上下文|
**动画** **动画**
|API|说明| |API|说明|
|:-|:-| |:-|:-|
|uni.createAnimation()|创建一个动画实例| |uni.createAnimation()|创建一个动画实例|
**滚动** **滚动**
|API|说明| |API|说明|
|:-|:-| |:-|:-|
|uni.pageScrollTo()|将页面滚动到目标位置| |uni.pageScrollTo()|将页面滚动到目标位置|
**绘画** **绘画**
|API|说明| |API|说明|
|:-|:-| |:-|:-|
|uni.createCanvasContext()|创建 canvas 绘图上下文| |uni.createCanvasContext()|创建 canvas 绘图上下文|
|uni.canvasToTempFilePath()|把当前画布指定区域的内容导出生成指定大小的图片,并返回文件路径| |uni.canvasToTempFilePath()|把当前画布指定区域的内容导出生成指定大小的图片,并返回文件路径|
|uni.canvasGetImageData()|返回一个数组,用来描述 canvas 区域隐含的像素数据| |uni.canvasGetImageData()|返回一个数组,用来描述 canvas 区域隐含的像素数据|
|uni.canvasPutImageData()|将像素数据绘制到画布的方法| |uni.canvasPutImageData()|将像素数据绘制到画布的方法|
**下拉刷新** **下拉刷新**
|API|说明| |API|说明|
|:-|:-| |:-|:-|
|uni.onPullDownRefresh()|监听该页面用户下拉刷新事件| |uni.onPullDownRefresh()|监听该页面用户下拉刷新事件|
|uni.startPullDownRefresh()|开始下拉刷新| |uni.startPullDownRefresh()|开始下拉刷新|
|uni.stopPullDownRefresh()|停止当前页面下拉刷新| |uni.stopPullDownRefresh()|停止当前页面下拉刷新|
**节点信息** **节点信息**
|API|说明| |API|说明|
|:-|:-| |:-|:-|
|uni.createSelectorQuery()|返回一个 SelectorQuery 对象实例| |uni.createSelectorQuery()|返回一个 SelectorQuery 对象实例|
**节点布局交互** **节点布局交互**
|API|说明| |API|说明|
|:-|:-| |:-|:-|
|uni.createIntersectionObserver()|创建并返回一个 IntersectionObserver 对象实例| |uni.createIntersectionObserver()|创建并返回一个 IntersectionObserver 对象实例|
#### nvue的新增API #### nvue的新增API
为了解决nvue的weex编译模式不支持uni-app生命周期的问题,`在nvue` 里新增了几个特殊的 API。如果是uni-app编译模式,无需使用这些API: 为了解决nvue的weex编译模式不支持uni-app生命周期的问题,`在nvue` 里新增了几个特殊的 API。如果是uni-app编译模式,无需使用这些API:
##### uni.onNavigationBarButtonTap(CALLBACK)@onNavigationBarButtonTap ##### uni.onNavigationBarButtonTap(CALLBACK)@onNavigationBarButtonTap
监听原生标题栏按钮点击事件。 监听原生标题栏按钮点击事件。
CALLBACK 参数说明: CALLBACK 参数说明:
|属性|类型|说明| |属性|类型|说明|
|---|---|---| |---|---|---|
|index|Number|原生标题栏按钮数组的下标| |index|Number|原生标题栏按钮数组的下标|
**代码示例** **代码示例**
```javascript ```javascript
export default { export default {
created() { created() {
uni.onNavigationBarButtonTap((e) => { uni.onNavigationBarButtonTap((e) => {
console.log("监听到原生标题栏按钮点击事件"); console.log("监听到原生标题栏按钮点击事件");
console.log(e); console.log(e);
}) })
} }
} }
``` ```
##### uni.onNavigationBarSearchInputChanged(CALLBACK) ##### uni.onNavigationBarSearchInputChanged(CALLBACK)
监听原生标题栏搜索输入框输入内容变化事件。 监听原生标题栏搜索输入框输入内容变化事件。
CALLBACK 参数说明: CALLBACK 参数说明:
|属性|类型|说明| |属性|类型|说明|
|---|---|---| |---|---|---|
|text|String|搜索输入框输入内容| |text|String|搜索输入框输入内容|
**代码示例** **代码示例**
```javascript ```javascript
export default { export default {
created() { created() {
uni.onNavigationBarSearchInputChanged((e) => { uni.onNavigationBarSearchInputChanged((e) => {
console.log("输入内容:"+ e.text); console.log("输入内容:"+ e.text);
}) })
} }
} }
``` ```
##### uni.onNavigationBarSearchInputConfirmed() ##### uni.onNavigationBarSearchInputConfirmed()
监听原生标题栏搜索输入框搜索事件,用户点击软键盘上的“搜索”按钮时触发。 监听原生标题栏搜索输入框搜索事件,用户点击软键盘上的“搜索”按钮时触发。
**代码示例** **代码示例**
```javascript ```javascript
export default { export default {
created() { created() {
uni.onNavigationBarSearchInputConfirmed(() => { uni.onNavigationBarSearchInputConfirmed(() => {
console.log("用户点击软键盘搜索"); console.log("用户点击软键盘搜索");
}) })
} }
} }
``` ```
##### uni.onNavigationBarSearchInputClicked() ##### uni.onNavigationBarSearchInputClicked()
监听原生标题栏搜索输入框点击事件。 监听原生标题栏搜索输入框点击事件。
**代码示例** **代码示例**
```javascript ```javascript
export default { export default {
created() { created() {
uni.onNavigationBarSearchInputClicked(() => { uni.onNavigationBarSearchInputClicked(() => {
console.log("点击输入框"); console.log("点击输入框");
}) })
} }
} }
``` ```
## nvue开发与vue开发的常见区别 ## nvue开发与vue开发的常见区别
基于原生引擎的渲染,虽然还是前端技术栈,但和web开发肯定是有区别的。 基于原生引擎的渲染,虽然还是前端技术栈,但和web开发肯定是有区别的。
...@@ -710,11 +738,11 @@ export default { ...@@ -710,11 +738,11 @@ export default {
但仍然还有一些区别需要注意: 但仍然还有一些区别需要注意:
- nvue 页面只能使用 flex 布局,不支持其他布局方式。需要注意的是 weex 的 flex 默认为竖向排列,即 ``flex-direction: column``,这与 html 的 flex 默认为横向排列不同。在 nvue 编译为 uni-app模式时,纠正了这个问题,flex 方向默认改为横向排列。 - nvue 页面只能使用 flex 布局,不支持其他布局方式。
- weex 下,页面内容高过屏幕高度并不会自动滚动,它没有页面滚动的概念,只有区域滚动,要滚得内容需要套在<scroller>组件下。在 nvue 编译为 uni-app模式时,纠正了这个问题,页面内容过高会自动滚动。 - weex 下,页面内容高过屏幕高度并不会自动滚动,它没有页面滚动的概念,只有区域滚动,要滚得内容需要套在<scroller>组件下。在 nvue 编译为 uni-app模式时,纠正了这个问题,页面内容过高会自动滚动。
- weex 下,px是与屏幕宽度相关的动态单位,750px代表成屏幕宽度100%,它的静态单位是wx。在 nvue 编译为 uni-app模式时,纠正了这个问题,rpx是与屏幕宽度相关的动态单位,px是静态单位。 - weex 下,px是与屏幕宽度相关的动态单位,750px代表成屏幕宽度100%,它的静态单位是wx。在 nvue 编译为 uni-app模式时,纠正了这个问题,rpx是与屏幕宽度相关的动态单位,px是静态单位。
- 页面开发前,首先想清楚这个页面的纵向内容有什么,哪些是要滚动的,然后每个纵向内容的横轴排布有什么,按 flex 布局设计好界面。 - 页面开发前,首先想清楚这个页面的纵向内容有什么,哪些是要滚动的,然后每个纵向内容的横轴排布有什么,按 flex 布局设计好界面。
- 文字内容,必须、只能在<text>组件下。不能在<div>的text里写文字。 - 文字内容,必须、只能在<text>组件下。不能在<div><view>的text区域里直接写文字。
- 支持的css有限,不过并不影响布局出你需要的界面,flex还是非常强大的。[详见](https://weex.apache.org/zh/docs/styles/common-styles.html#%E7%9B%92%E6%A8%A1%E5%9E%8B) - 支持的css有限,不过并不影响布局出你需要的界面,flex还是非常强大的。[详见](https://weex.apache.org/zh/docs/styles/common-styles.html#%E7%9B%92%E6%A8%A1%E5%9E%8B)
- class 进行绑定时只支持数组语法。 - class 进行绑定时只支持数组语法。
...@@ -732,5 +760,4 @@ export default { ...@@ -732,5 +760,4 @@ export default {
- nvue 切换横竖屏时可能导致样式出现问题,建议有 nvue 的页面锁定手机方向。 - nvue 切换横竖屏时可能导致样式出现问题,建议有 nvue 的页面锁定手机方向。
- 不能在 style 中引入字体文件,nvue 中字体图标的使用参考:[weex 加载自定义字体](https://weex.apache.org/zh/docs/modules/dom.html#addrule) - 不能在 style 中引入字体文件,nvue 中字体图标的使用参考:[weex 加载自定义字体](https://weex.apache.org/zh/docs/modules/dom.html#addrule)
- 目前不支持在 nvue 页面使用 typescript/ts。 - 目前不支持在 nvue 页面使用 typescript/ts。
- HBuilderX 1.9.8以前,nvue 不支持运行在Android三方模拟器上。HBuilderX 2.1以前,nvue不支持less等css预编译器。 - nvue 页面 ``titleNview`` 设为 ``false``时,想要模拟状态栏,可以参考:[https://ask.dcloud.net.cn/article/35111](https://ask.dcloud.net.cn/article/35111)
- nvue 页面 ``titleNview`` 设为 ``false``时,想要模拟状态栏,可以参考:[https://ask.dcloud.net.cn/article/35111](https://ask.dcloud.net.cn/article/35111)
\ No newline at end of file
...@@ -11,12 +11,6 @@ ...@@ -11,12 +11,6 @@
详见Vue官方文档:[生命周期钩子](https://cn.vuejs.org/v2/api/#%E9%80%89%E9%A1%B9-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90) 详见Vue官方文档:[生命周期钩子](https://cn.vuejs.org/v2/api/#%E9%80%89%E9%A1%B9-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90)
**注意**
* 不要在选项属性或回调上使用箭头函数,比如 ``created: () => console.log(this.a)````vm.$watch('a', newValue => this.myMethod())``。因为箭头函数是和父级上下文绑定在一起的,``this`` 不会是如你做预期的 ``Vue`` 实例,且 ``this.a````this.myMethod`` 也会是未定义的。
* 建议使用 `uni-app``onReady`代替 `vue``mounted`
* 建议使用 `uni-app``onLoad` 代替 `vue``created`
## 模板语法 ## 模板语法
......
module.exports = {
globals: {
__DEV__: true
},
coverageDirectory: 'coverage',
coverageReporters: ['html', 'lcov', 'text'],
collectCoverageFrom: ['packages/*/src/**/*.js'],
moduleFileExtensions: ['js', 'json'],
moduleNameMapper: {
'^@dcloudio/(.*?)$': '<rootDir>/packages/$1/src'
},
rootDir: __dirname,
testMatch: ['<rootDir>/packages/**/__tests__/**/*spec.(t|j)s']
}
{
"npmClient": "yarn",
"useWorkspaces": false,
"packages": [
"packages/*"
],
"publishConfig": {
"access": "public"
},
"command": {
"publish": {
"message": "chore(release): publish %s"
}
},
"version": "1.0.0-alpha-22120190814002"
}
const base = [
'base64ToArrayBuffer',
'arrayBufferToBase64',
'addInterceptor',
'removeInterceptor'
]
const network = [
'request',
'uploadFile',
'downloadFile',
'connectSocket',
'onSocketOpen',
'onSocketError',
'sendSocketMessage',
'onSocketMessage',
'closeSocket',
'onSocketClose'
]
const route = [
'navigateTo',
'redirectTo',
'reLaunch',
'switchTab',
'navigateBack'
]
const storage = [
'setStorage',
'setStorageSync',
'getStorage',
'getStorageSync',
'getStorageInfo',
'getStorageInfoSync',
'removeStorage',
'removeStorageSync',
'clearStorage',
'clearStorageSync'
]
const location = [
'getLocation',
'chooseLocation',
'openLocation',
'createMapContext'
]
const media = [
'chooseImage',
'previewImage',
'getImageInfo',
'saveImageToPhotosAlbum',
'compressImage',
'getRecorderManager',
'getBackgroundAudioManager',
'createInnerAudioContext',
'chooseVideo',
'saveVideoToPhotosAlbum',
'createVideoContext',
'createCameraContext',
'createLivePlayerContext'
]
const device = [
'getSystemInfo',
'getSystemInfoSync',
'canIUse',
'onMemoryWarning',
'getNetworkType',
'onNetworkStatusChange',
'onAccelerometerChange',
'startAccelerometer',
'stopAccelerometer',
'onCompassChange',
'startCompass',
'stopCompass',
'onGyroscopeChange',
'startGyroscope',
'stopGyroscope',
'makePhoneCall',
'scanCode',
'setClipboardData',
'getClipboardData',
'setScreenBrightness',
'getScreenBrightness',
'setKeepScreenOn',
'onUserCaptureScreen',
'vibrateLong',
'vibrateShort',
'addPhoneContact',
'openBluetoothAdapter',
'startBluetoothDevicesDiscovery',
'onBluetoothDeviceFound',
'stopBluetoothDevicesDiscovery',
'onBluetoothAdapterStateChange',
'getConnectedBluetoothDevices',
'getBluetoothDevices',
'getBluetoothAdapterState',
'closeBluetoothAdapter',
'writeBLECharacteristicValue',
'readBLECharacteristicValue',
'onBLEConnectionStateChange',
'onBLECharacteristicValueChange',
'notifyBLECharacteristicValueChange',
'getBLEDeviceServices',
'getBLEDeviceCharacteristics',
'createBLEConnection',
'closeBLEConnection',
'onBeaconServiceChange',
'onBeaconUpdate',
'getBeacons',
'startBeaconDiscovery',
'stopBeaconDiscovery'
]
const keyboard = [
'hideKeyboard',
'onKeyboardHeightChange'
]
const ui = [
'showToast',
'hideToast',
'showLoading',
'hideLoading',
'showModal',
'showActionSheet',
'setNavigationBarTitle',
'setNavigationBarColor',
'showNavigationBarLoading',
'hideNavigationBarLoading',
'setTabBarItem',
'setTabBarStyle',
'hideTabBar',
'showTabBar',
'setTabBarBadge',
'removeTabBarBadge',
'showTabBarRedDot',
'hideTabBarRedDot',
'setBackgroundColor',
'setBackgroundTextStyle',
'createAnimation',
'pageScrollTo',
'onWindowResize',
'offWindowResize',
'loadFontFace',
'startPullDownRefresh',
'stopPullDownRefresh',
'createSelectorQuery',
'createIntersectionObserver'
]
const event = [
'$emit',
'$on',
'$once',
'$off'
]
const file = [
'saveFile',
'getSavedFileList',
'getSavedFileInfo',
'removeSavedFile',
'getFileInfo',
'openDocument',
'getFileSystemManager'
]
const canvas = [
'createOffscreenCanvas',
'createCanvasContext',
'canvasToTempFilePath',
'canvasPutImageData',
'canvasGetImageData'
]
const third = [
'getProvider',
'login',
'checkSession',
'getUserInfo',
'share',
'showShareMenu',
'hideShareMenu',
'requestPayment',
'subscribePush',
'unsubscribePush',
'onPush',
'offPush',
'requireNativePlugin',
'upx2px'
]
const apis = [
...base,
...network,
...route,
...storage,
...location,
...media,
...device,
...keyboard,
...ui,
...event,
...file,
...canvas,
...third
]
module.exports = apis
const path = require('path')
const isWin = /^win/.test(process.platform)
const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path)
function resolve(...args) {
return normalizePath(path.resolve.apply(path, [__dirname, ...args]))
}
const srcPath = resolve('../../src/')
const protocolPath = resolve('../../src/core/helpers/protocol')
const coreApiPath = resolve('../../src/core/service/api')
const platformApiPath = resolve('../../src/platforms/' + process.env.UNI_PLATFORM + '/service/api')
const apis = require('../apis')
process.UNI_SERVICE_API_MANIFEST = Object.create(null)
process.UNI_SERVICE_API_PROTOCOL = Object.create(null)
function parseProtocolExport({
file,
exports
}) {
const filepath = file.replace(srcPath, '')
exports.forEach(exportName => {
if (process.UNI_SERVICE_API_PROTOCOL[exportName]) {
console.warn(`API[${exportName}] 冲突:`)
console.warn(process.UNI_SERVICE_API_PROTOCOL[exportName])
console.warn(filepath)
} else {
process.UNI_SERVICE_API_PROTOCOL[exportName] = filepath
}
})
}
function parseApiExport({
file,
methods,
exports,
isPlatform
}) {
const deps = []
methods && methods.forEach(method => {
deps.push(['', method])
})
const filepath = file.replace(srcPath, '')
exports.forEach(exportName => {
if (process.UNI_SERVICE_API_MANIFEST[exportName]) {
console.warn('\n')
console.warn(`API[${exportName}] 冲突:`)
console.warn(process.UNI_SERVICE_API_MANIFEST[exportName][0])
console.warn(filepath)
if (isPlatform) { // 优先使用 platform
process.UNI_SERVICE_API_MANIFEST[exportName] = [filepath, deps]
console.warn(`优先使用` + filepath)
}
} else {
process.UNI_SERVICE_API_MANIFEST[exportName] = [filepath, deps]
}
})
}
function parseExports(node, t, file) {
if (t.isFunctionDeclaration(node)) {
return [node.id.name]
} else if (
t.isVariableDeclaration(node) &&
node.declarations.length === 1
) {
return [node.declarations[0].id.name]
} else if (Array.isArray(node) && node.length) {
return node.map(specifier => {
return specifier.exported.name
})
} else {
console.warn('\n')
console.warn(`${file} 解析 export 失败`, node)
}
}
module.exports = function({
types: t
}) {
return {
visitor: {
Program: {
enter(path, state) {
state.file.opts.file = normalizePath(state.file.opts.filename)
state.file.opts.isCore = state.file.opts.file.indexOf(coreApiPath) === 0
state.file.opts.isPlatform = state.file.opts.file.indexOf(platformApiPath) === 0
state.file.opts.isProtocol = state.file.opts.file.indexOf(protocolPath) === 0
},
exit(path, state) {
const {
exports,
isProtocol
} = state.file.opts
if (exports && exports.length) {
if (isProtocol) {
parseProtocolExport(state.file.opts)
} else {
parseApiExport(state.file.opts)
}
}
}
},
ExportNamedDeclaration(path, state) {
const {
file,
isCore,
isPlatform,
isProtocol
} = state.file.opts
if (isCore || isPlatform || isProtocol) {
const exports = parseExports(path.node.declaration || path.node.specifiers, t, file)
if (Array.isArray(exports)) {
(state.file.opts.exports || (state.file.opts.exports = [])).push(...exports)
}
}
},
CallExpression(path, state) {
const {
file,
isCore,
isPlatform
} = state.file.opts
if (
isCore &&
path.node.callee.name === 'invokeMethod'
) {
(state.file.opts.methods || (state.file.opts.methods = new Set())).add(path.node.arguments[0].value)
}
}
}
}
}
...@@ -17,7 +17,7 @@ const { ...@@ -17,7 +17,7 @@ const {
default: uni, default: uni,
getApp, getApp,
getCurrentPages getCurrentPages
} = require('uni-service') } = require('uni-platform/service/index')
global.uni = uni global.uni = uni
......
[{
"name": "base",
"title": "基础",
"apiList": {
"uni.getSystemInfo": true,
"uni.getSystemInfoSync": true,
"uni.canIUse": true,
"uni.upx2px": true,
"uni.navigateTo": true,
"uni.redirectTo": true,
"uni.switchTab": true,
"uni.reLaunch": true,
"uni.navigateBack": true
}
}, {
"name": "network",
"title": "网络",
"apiList": {
"uni.request": true,
"uni.connectSocket": true,
"uni.sendSocketMessage": true,
"uni.closeSocket": true,
"uni.onSocketOpen": true,
"uni.onSocketError": true,
"uni.onSocketMessage": true,
"uni.onSocketClose": true,
"uni.downloadFile": true,
"uni.uploadFile": true
}
}, {
"name": "storage",
"title": "数据缓存",
"apiList": {
"uni.setStorage": true,
"uni.setStorageSync": true,
"uni.getStorage": true,
"uni.getStorageSync": true,
"uni.removeStorage": true,
"uni.removeStorageSync": true,
"uni.clearStorage": true,
"uni.clearStorageSync": true,
"uni.getStorageInfo": true,
"uni.getStorageInfoSync": true
}
}, {
"name": "location",
"title": "位置",
"apiList": {
"uni.getLocation": true,
"uni.openLocation": true,
"uni.chooseLocation": true
}
}, {
"name": "media",
"title": "媒体",
"apiList": {
"uni.chooseImage": true,
"uni.previewImage": true,
"uni.getImageInfo": true,
"uni.saveImageToPhotosAlbum": true,
"uni.compressImage": true,
"uni.getRecorderManager": true,
"uni.getBackgroundAudioManager": true,
"uni.createInnerAudioContext": true,
"uni.chooseVideo": true,
"uni.saveVideoToPhotosAlbum": true,
"uni.createVideoContext": true,
"uni.createCameraContext": true,
"uni.createLivePlayerContext": true
}
}, {
"name": "device",
"title": "设备",
"apiList": {
"uni.onMemoryWarning": true,
"uni.getNetworkType": true,
"uni.onNetworkStatusChange": true,
"uni.onAccelerometerChange": true,
"uni.startAccelerometer": true,
"uni.stopAccelerometer": true,
"uni.onCompassChange": true,
"uni.startCompass": true,
"uni.stopCompass": true,
"uni.onGyroscopeChange": true,
"uni.startGyroscope": true,
"uni.stopGyroscope": true,
"uni.makePhoneCall": true,
"uni.scanCode": true,
"uni.setClipboardData": true,
"uni.getClipboardData": true,
"uni.setScreenBrightness": true,
"uni.getScreenBrightness": true,
"uni.setKeepScreenOn": true,
"uni.onUserCaptureScreen": true,
"uni.vibrateLong": true,
"uni.vibrateShort": true,
"uni.addPhoneContact": true,
"uni.openBluetoothAdapter": true,
"uni.startBluetoothDevicesDiscovery": true,
"uni.onBluetoothDeviceFound": true,
"uni.stopBluetoothDevicesDiscovery": true,
"uni.onBluetoothAdapterStateChange": true,
"uni.getConnectedBluetoothDevices": true,
"uni.getBluetoothDevices": true,
"uni.getBluetoothAdapterState": true,
"uni.closeBluetoothAdapter": true,
"uni.writeBLECharacteristicValue": true,
"uni.readBLECharacteristicValue": true,
"uni.onBLEConnectionStateChange": true,
"uni.onBLECharacteristicValueChange": true,
"uni.notifyBLECharacteristicValueChange": true,
"uni.getBLEDeviceServices": true,
"uni.getBLEDeviceCharacteristics": true,
"uni.createBLEConnection": true,
"uni.closeBLEConnection": true,
"uni.onBeaconServiceChange": true,
"uni.onBeaconUpdate": true,
"uni.getBeacons": true,
"uni.startBeaconDiscovery": true,
"uni.stopBeaconDiscovery": true
}
}, {
"name": "ui",
"title": "界面",
"apiList": {
"uni.showToast": true,
"uni.hideToast": true,
"uni.showLoading": true,
"uni.hideLoading": true,
"uni.showModal": true,
"uni.showActionSheet": true,
"uni.setNavigationBarTitle": true,
"uni.setNavigationBarColor": true,
"uni.showNavigationBarLoading": true,
"uni.hideNavigationBarLoading": true,
"uni.setTabBarItem": true,
"uni.setTabBarStyle": true,
"uni.hideTabBar": true,
"uni.showTabBar": true,
"uni.setTabBarBadge": true,
"uni.removeTabBarBadge": true,
"uni.showTabBarRedDot": true,
"uni.hideTabBarRedDot": true,
"uni.setBackgroundColor": true,
"uni.setBackgroundTextStyle": true,
"uni.createAnimation": true,
"uni.pageScrollTo": true,
"uni.onWindowResize": true,
"uni.offWindowResize": true,
"uni.loadFontFace": true,
"uni.startPullDownRefresh": true,
"uni.stopPullDownRefresh": true,
"uni.createSelectorQuery": true,
"uni.createIntersectionObserver": true,
"uni.hideKeyboard": true,
"uni.onKeyboardHeightChange": true
}
}, {
"name": "event",
"title": "页面通讯",
"apiList": {
"uni.$emit": true,
"uni.$on": true,
"uni.$once": true,
"uni.$off": true
}
}, {
"name": "file",
"title": "文件",
"apiList": {
"uni.saveFile": true,
"uni.getSavedFileList": true,
"uni.getSavedFileInfo": true,
"uni.removeSavedFile": true,
"uni.getFileInfo": true,
"uni.openDocument": true,
"uni.getFileSystemManager": true
}
}, {
"name": "canvas",
"title": "绘画",
"apiList": {
"uni.createOffscreenCanvas": true,
"uni.createCanvasContext": true,
"uni.canvasToTempFilePath": true,
"uni.canvasPutImageData": true,
"uni.canvasGetImageData": true
}
}, {
"name": "third",
"title": "第三方服务",
"apiList": {
"uni.getProvider": true,
"uni.login": true,
"uni.checkSession": true,
"uni.getUserInfo": true,
"uni.share": true,
"uni.showShareMenu": true,
"uni.hideShareMenu": true,
"uni.requestPayment": true,
"uni.subscribePush": true,
"uni.unsubscribePush": true,
"uni.onPush": true,
"uni.offPush": true,
"uni.requireNativePlugin": true,
"uni.base64ToArrayBuffer": true,
"uni.arrayBufferToBase64": true
}
}]
# rollup-plugin-require-context
rollup plugin for resovling webpack require-context.
## usage
```javascript
import requireContext from 'rollup-plugin-require-context';
export default {
input: 'main.js',
output: {
file: 'bundle.js',
format: 'iife'
},
plugins: [
requireContext()
]
};
```
{
"name": "rollup-plugin-require-context",
"version": "1.0.0",
"description": "rollup-plugin for webpack requrie-context",
"main": "src/index.js",
"scripts": {
"brk": "node --inspect-brk example/run.js",
"example": "rollup -c example/rollup.config.js",
"test:dev": "jest --watchAll"
},
"repository": {
"type": "git",
"url": "git+https://github.com/elcarim5efil/rollup-plugin-require-context.git"
},
"keywords": [
"rollup",
"plugin",
"require-context",
"webpack-context"
],
"author": "elcarim5efil",
"license": "MIT",
"bugs": {
"url": "https://github.com/elcarim5efil/rollup-plugin-require-context/issues"
},
"homepage": "https://github.com/elcarim5efil/rollup-plugin-require-context#readme",
"dependencies": {
"acorn": "^6.1.1",
"acorn-dynamic-import": "^4.0.0",
"acorn-walk": "^6.1.1",
"rollup-pluginutils": "^2.5.0"
},
"devDependencies": {
"jest": "^24.5.0",
"rollup": "^1.7.4",
"rollup-plugin-virtual": "^1.0.1"
}
}
const Path = require('path')
const { parse } = require('acorn')
const walk = require('acorn-walk')
function stripHeadAndTailChar (str) {
return str.substring(1, str.length - 1)
}
function extract (code) {
return new Promise((resolve, reject) => {
const ast = parse(code, {
sourceType: 'module'
})
const res = []
walk.simple(ast, {
CallExpression (node) {
const {
start,
end,
callee,
arguments: argNodes
} = node
let args = []
if (
callee.type === 'MemberExpression' &&
callee.object.name === 'require' &&
callee.property.name === 'context'
) {
args = argNodes.map(a => a.value)
res.push({
start,
end,
args
})
}
}
})
resolve(res)
})
}
module.exports = async function extractArgs (code, baseDirname) {
const data = await extract(code)
return data.map(r => {
const { start, end, args } = r
const [
rawDirname = '',
rawRecursive,
rawRegexp
] = args
const dirname = Path.join(baseDirname, rawDirname)
const recursive = rawRecursive
const regexp = rawRegexp
return {
dirname,
recursive,
regexp,
start,
end
}
})
}
const Path = require('path')
const extractArgs = require('./extract-args')
const resolveRequireModules = require('./resolve-reqquire-modules')
const resolveRequireCode = require('./resolve-require-code')
module.exports = async function gernerateRequireContextCode (id, code) {
const currentCodeDirname = Path.dirname(id)
const data = await extractArgs(code, currentCodeDirname)
let head = ''
const body = data.reduceRight((res, r) => {
const {
start, end,
dirname, recursive, regexp
} = r
const modules = resolveRequireModules(dirname, recursive, regexp)
const moduleCode = resolveRequireCode(dirname, modules)
const {
importCode,
requireFnCode
} = moduleCode
head += importCode
res = [
res.slice(0, start),
requireFnCode,
res.slice(end)
].join('')
return res
}, code)
return [
head,
body
].join('\n')
}
module.exports = function hasRequireContext (code) {
return /require\.context/g.test(code)
}
const fs = require('fs')
const Path = require('path')
function readDirRecursive (dir) {
return fs.statSync(dir).isDirectory()
? Array.prototype.concat(
...fs.readdirSync(dir).map(f => readDirRecursive(Path.join(dir, f)))
)
: dir
}
function readDir (dir, recursive) {
const isDirectory = fs.statSync(dir).isDirectory()
if (recursive) {
return readDirRecursive(dir)
} else if (isDirectory) {
const files = fs.readdirSync(dir)
if (files) {
return files.map(file => Path.resolve(dir, file))
}
} else {
return [ dir ]
}
}
module.exports = function resolveRequireModules (baseDirname = './', recursive = false, regexp = /^\.\//) {
let files = readDir(baseDirname, recursive)
if (!Array.isArray(files)) {
files = [files]
}
files = files.map(file => {
const fileAbsolutePath = `./${Path.relative(baseDirname, file)}`
return fileAbsolutePath
})
return files.filter(file => regexp.test(file.replace(/\\/g, '/')))
}
const Path = require('path')
let uid = 0
function getUID () {
return uid++
}
function genImportCode (name, path) {
return `import * as ${name} from '${path}';\n`
}
function genPropsCode (key, value) {
return `'${key}': ${value},\n`
}
module.exports = function genRequireCode (baseDirname, modules) {
const uid = getUID()
let importCode = ''
let moduleProps = ''
modules.forEach((file, index) => {
const moduleName = `require_context_module_${uid}_${index}`
const moduleAbsolutePath = Path.resolve(baseDirname, file).replace(/\\/g, '/')
importCode += genImportCode(moduleName, moduleAbsolutePath)
moduleProps += genPropsCode(file, moduleName)
})
const requireFnCode = (`
(function() {
var map = {
${moduleProps}
};
var req = function req(key) {
return map[key] || (function() { throw new Error("Cannot find module '" + key + "'.") }());
}
req.keys = function() {
return Object.keys(map);
}
return req;
})()
`)
return {
importCode,
requireFnCode
}
}
const _ = require('rollup-pluginutils')
const hasRequireContext = require('./helper/has-require-context')
const gernerateRequireContextCode = require('./helper/generate-require-context-code')
module.exports = function plugin (options = {}) {
const filter = _.createFilter(options.include || ['**/*.js'], options.exclude || 'node_modules/**')
return {
name: 'require_content',
async transform (code, id) {
if (!filter(id) || !hasRequireContext(code)) {
return
}
code = await gernerateRequireContextCode(id, code)
return code
}
}
}
{ {
"name": "uniapp-js-framework", "name": "uniapp-js-framework",
"version": "0.0.1", "version": "0.0.1",
"scripts": { "scripts": {
"lint": "eslint --fix --config package.json --ext .js --ext .vue --ignore-path .eslintignore build src", "lint": "eslint --fix --config package.json --ext .js --ext .vue --ignore-path .eslintignore build src",
"dev:h5": "npm run lint && cross-env NODE_ENV=production UNI_WATCH=true UNI_PLATFORM=h5 node build/build.js", "lint:cli": "eslint --fix --config package.json --ignore-path .eslintignore packages/uni-cli-shared packages/uni-template-compiler \"packages/vue-cli-*/**/*.js\" \"packages/webpack-uni-*/**/*.js\"",
"build:h5": "npm run lint && cross-env NODE_ENV=production UNI_WATCH=false UNI_PLATFORM=h5 node build/build.js", "dev:h5": "npm run lint && cross-env NODE_ENV=production UNI_WATCH=true UNI_PLATFORM=h5 node build/build.js",
"build:app-plus": "cross-env UNI_PLATFORM=app-plus rollup -c build/rollup.config.js", "build:h5": "npm run lint && cross-env NODE_ENV=production UNI_WATCH=false UNI_PLATFORM=h5 node build/build.js",
"build:service:legacy": "npm run lint && rollup -c build/rollup.config.service.js", "build:app-plus": "cross-env UNI_PLATFORM=app-plus rollup -c build/rollup.config.mp.js",
"build:mp-qq": "cross-env UNI_PLATFORM=mp-qq rollup -c build/rollup.config.js", "build:app:all": "npm run lint && npm run build:app:nvue && npm run build:app:legacy",
"build:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin rollup -c build/rollup.config.js", "build:app:nvue": "cross-env UNI_PLATFORM=app-plus-nvue rollup -c build/rollup.config.app.js",
"build:mp-baidu": "cross-env UNI_PLATFORM=mp-baidu rollup -c build/rollup.config.js", "build:app:legacy": "cross-env UNI_PLATFORM=app-plus-nvue UNI_SERVICE=legacy rollup -c build/rollup.config.app.js",
"build:mp-alipay": "cross-env UNI_PLATFORM=mp-alipay rollup -c build/rollup.config.js", "build:mp-qq": "cross-env UNI_PLATFORM=mp-qq rollup -c build/rollup.config.mp.js",
"build:mp-toutiao": "cross-env UNI_PLATFORM=mp-toutiao rollup -c build/rollup.config.js", "build:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin rollup -c build/rollup.config.mp.js",
"build:runtime": "npm run lint && npm run build:mp-weixin && npm run build:mp-qq && npm run build:mp-alipay && npm run build:mp-baidu && npm run build:mp-toutiao && npm run build:app-plus", "build:mp-baidu": "cross-env UNI_PLATFORM=mp-baidu rollup -c build/rollup.config.mp.js",
"test:unit": "cross-env NODE_ENV=test UNI_PLATFORM=h5 mocha-webpack --require tests/unit/setup.js --webpack-config build/webpack.config.test.js tests/unit/**/*.spec.js" "build:mp-alipay": "cross-env UNI_PLATFORM=mp-alipay rollup -c build/rollup.config.mp.js",
"build:mp-toutiao": "cross-env UNI_PLATFORM=mp-toutiao rollup -c build/rollup.config.mp.js",
"build:runtime": "npm run lint && npm run build:mp-weixin && npm run build:mp-qq && npm run build:mp-alipay && npm run build:mp-baidu && npm run build:mp-toutiao && npm run build:app-plus",
"build:stat": "npm run lint && rollup -c build/rollup.config.stat.js",
"test:cli": "cross-env NODE_ENV=test jest",
"test:unit": "cross-env NODE_ENV=test UNI_PLATFORM=h5 mocha-webpack --require tests/unit/setup.js --webpack-config build/webpack.config.test.js tests/unit/**/*.spec.js",
"release": "npm run lint:cli && lerna publish --force-publish=*",
"release:alpha": "npm run lint:cli && lerna publish --force-publish=* --npm-tag=alpha"
},
"dependencies": {
"base64-arraybuffer": "^0.2.0",
"intersection-observer": "^0.7.0"
},
"private": true,
"devDependencies": {
"@types/html5plus": "^1.0.0",
"@vue/cli-plugin-babel": "^3.4.1",
"@vue/cli-plugin-eslint": "^3.4.1",
"@vue/cli-plugin-unit-mocha": "^3.4.1",
"@vue/cli-service": "^3.4.1",
"@vue/test-utils": "^1.0.0-beta.25",
"babel-eslint": "^10.0.1",
"babylon": "^6.18.0",
"browserslist": "^4.4.2",
"caniuse-lite": "^1.0.30000940",
"chai": "^4.1.2",
"copy": "^0.3.2",
"cross-env": "^5.2.0",
"del": "^5.0.0",
"eslint": "^5.5.0",
"eslint-config-standard": "^12.0.0",
"eslint-loader": "^2.1.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-promise": "^4.0.0",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^4.7.1",
"jest": "^24.9.0",
"jsdom": "^13.0.0",
"jsdom-global": "^3.0.2",
"jsonfile": "^5.0.0",
"rollup": "^1.17.0",
"rollup-plugin-alias": "^1.4.0",
"rollup-plugin-commonjs": "^10.0.1",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-replace": "^2.1.0",
"strip-json-comments": "^2.0.1",
"vue": "^2.6.8",
"vue-router": "^3.0.1",
"vue-template-compiler": "^2.6.8",
"webpack": "^4.18.0",
"webpack-bundle-analyzer": "^3.0.3",
"webpack-virtual-modules": "^0.1.10"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
}, },
"dependencies": { "extends": [
"base64-arraybuffer": "^0.2.0", "plugin:vue/recommended",
"intersection-observer": "^0.7.0" "standard"
}, ],
"private": true, "globals": {
"devDependencies": { "App": true,
"@vue/cli-plugin-babel": "^3.4.1", "Page": true,
"@vue/cli-plugin-eslint": "^3.4.1", "Component": true,
"@vue/cli-plugin-unit-mocha": "^3.4.1", "Behavior": true,
"@vue/cli-service": "^3.4.1", "getApp": true,
"@vue/test-utils": "^1.0.0-beta.25", "getCurrentPages": true,
"babel-eslint": "^10.0.1", "plus": true,
"babylon": "^6.18.0", "uni": true,
"browserslist": "^4.4.2", "Vue": true,
"caniuse-lite": "^1.0.30000940", "wx": true,
"chai": "^4.1.2", "my": true,
"copy": "^0.3.2", "swan": true,
"cross-env": "^5.2.0", "weex": true,
"del": "^5.0.0", "__id__": true,
"eslint": "^5.5.0", "__uniConfig": true,
"eslint-config-standard": "^12.0.0", "__uniRoutes": true,
"eslint-loader": "^2.1.0", "__registerPage": true,
"eslint-plugin-import": "^2.14.0", "UniViewJSBridge": true,
"eslint-plugin-node": "^7.0.1", "UniServiceJSBridge": true,
"eslint-plugin-promise": "^4.0.0", "__PLATFORM__": true,
"eslint-plugin-standard": "^4.0.0", "__VERSION__": true,
"eslint-plugin-vue": "^4.7.1", "__GLOBAL__": true,
"jsdom": "^13.0.0", "__PLATFORM_TITLE__": true,
"jsdom-global": "^3.0.2", "__PLATFORM_PREFIX__": true,
"jsonfile": "^5.0.0", "it": true,
"rollup": "^0.67.4", "describe": true,
"rollup-plugin-alias": "^1.4.0", "expect": true
"rollup-plugin-replace": "^2.1.0",
"strip-json-comments": "^2.0.1",
"vue": "^2.6.8",
"vue-router": "^3.0.1",
"vue-template-compiler": "^2.6.8",
"webpack": "^4.18.0",
"webpack-bundle-analyzer": "^3.3.2",
"webpack-virtual-modules": "^0.1.10"
}, },
"eslintConfig": { "rules": {
"root": true, "no-tabs": 0,
"env": { "standard/no-callback-literal": 0
"node": true
},
"extends": [
"plugin:vue/recommended",
"standard"
],
"globals": {
"App": true,
"Page": true,
"Component": true,
"Behavior": true,
"getApp": true,
"getCurrentPages": true,
"plus": true,
"uni": true,
"Vue": true,
"wx": true,
"my": true,
"swan": true,
"__uniConfig": true,
"__uniRoutes": true,
"UniViewJSBridge": true,
"UniServiceJSBridge": true,
"__PLATFORM__": true,
"__VERSION__": true,
"__GLOBAL__": true,
"__PLATFORM_TITLE__": true,
"__PLATFORM_PREFIX__": true
},
"rules": {
"no-tabs": 0,
"standard/no-callback-literal": 0
},
"parserOptions": {
"parser": "babel-eslint"
}
}, },
"browserslist": [ "parserOptions": {
"last 3 versions", "parser": "babel-eslint"
"Android >= 4.1", }
"ios >= 8" },
], "browserslist": [
"license": "Apache-2.0", "last 3 versions",
"main": "index.js", "Android >= 4.1",
"description": "", "ios >= 8"
"author": "" ],
"license": "Apache-2.0",
"main": "index.js",
"description": "",
"author": ""
} }
{ {
"name": "@dcloudio/uni-app-plus-nvue", "name": "@dcloudio/uni-app-plus-nvue",
"version": "0.0.1", "version": "1.0.0-alpha-22120190814002",
"description": "uni-app app-plus-nvue", "description": "uni-app app-plus-nvue",
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"author": "fxy060608", "author": "fxy060608",
"license": "Apache-2.0" "license": "Apache-2.0",
"gitHead": "08ea04b669e93f0db3acb2dfa38138298edd5789"
} }
...@@ -231,7 +231,7 @@ const promiseInterceptor = { ...@@ -231,7 +231,7 @@ const promiseInterceptor = {
}; };
const SYNC_API_RE = const SYNC_API_RE =
/^\$|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; /^\$|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/;
const CONTEXT_API_RE = /^create|Manager$/; const CONTEXT_API_RE = /^create|Manager$/;
...@@ -258,8 +258,8 @@ function handlePromise (promise) { ...@@ -258,8 +258,8 @@ function handlePromise (promise) {
function shouldPromise (name) { function shouldPromise (name) {
if ( if (
isContextApi(name) || isContextApi(name) ||
isSyncApi(name) || isSyncApi(name) ||
isCallbackApi(name) isCallbackApi(name)
) { ) {
return false return false
} }
...@@ -491,8 +491,6 @@ function $emit () { ...@@ -491,8 +491,6 @@ function $emit () {
return apply(getEmitter(), '$emit', [...arguments]) return apply(getEmitter(), '$emit', [...arguments])
} }
var eventApi = /*#__PURE__*/Object.freeze({ var eventApi = /*#__PURE__*/Object.freeze({
$on: $on, $on: $on,
$off: $off, $off: $off,
...@@ -653,8 +651,8 @@ function hasHook (hook, vueOptions) { ...@@ -653,8 +651,8 @@ function hasHook (hook, vueOptions) {
return true return true
} }
if (vueOptions.super && if (vueOptions.super &&
vueOptions.super.options && vueOptions.super.options &&
Array.isArray(vueOptions.super.options[hook])) { Array.isArray(vueOptions.super.options[hook])) {
return true return true
} }
return false return false
...@@ -679,14 +677,14 @@ function initHooks (mpOptions, hooks, vueOptions) { ...@@ -679,14 +677,14 @@ function initHooks (mpOptions, hooks, vueOptions) {
}); });
} }
function initVueComponent (Vue$$1, vueOptions) { function initVueComponent (Vue, vueOptions) {
vueOptions = vueOptions.default || vueOptions; vueOptions = vueOptions.default || vueOptions;
let VueComponent; let VueComponent;
if (isFn(vueOptions)) { if (isFn(vueOptions)) {
VueComponent = vueOptions; VueComponent = vueOptions;
vueOptions = VueComponent.extendOptions; vueOptions = VueComponent.extendOptions;
} else { } else {
VueComponent = Vue$$1.extend(vueOptions); VueComponent = Vue.extend(vueOptions);
} }
return [VueComponent, vueOptions] return [VueComponent, vueOptions]
} }
...@@ -853,7 +851,7 @@ function initProperties (props, isBehavior = false, file = '') { ...@@ -853,7 +851,7 @@ function initProperties (props, isBehavior = false, file = '') {
value = value(); value = value();
} }
opts.type = parsePropType(key, opts.type, value, file); opts.type = parsePropType(key, opts.type);
properties[key] = { properties[key] = {
type: PROP_TYPES.indexOf(opts.type) !== -1 ? opts.type : null, type: PROP_TYPES.indexOf(opts.type) !== -1 ? opts.type : null,
...@@ -861,7 +859,7 @@ function initProperties (props, isBehavior = false, file = '') { ...@@ -861,7 +859,7 @@ function initProperties (props, isBehavior = false, file = '') {
observer: createObserver(key) observer: createObserver(key)
}; };
} else { // content:String } else { // content:String
const type = parsePropType(key, opts, null, file); const type = parsePropType(key, opts);
properties[key] = { properties[key] = {
type: PROP_TYPES.indexOf(type) !== -1 ? type : null, type: PROP_TYPES.indexOf(type) !== -1 ? type : null,
observer: createObserver(key) observer: createObserver(key)
...@@ -936,16 +934,16 @@ function processEventExtra (vm, extra, event) { ...@@ -936,16 +934,16 @@ function processEventExtra (vm, extra, event) {
if (Array.isArray(extra) && extra.length) { if (Array.isArray(extra) && extra.length) {
/** /**
*[ *[
* ['data.items', 'data.id', item.data.id], * ['data.items', 'data.id', item.data.id],
* ['metas', 'id', meta.id] * ['metas', 'id', meta.id]
*], *],
*[ *[
* ['data.items', 'data.id', item.data.id], * ['data.items', 'data.id', item.data.id],
* ['metas', 'id', meta.id] * ['metas', 'id', meta.id]
*], *],
*'test' *'test'
*/ */
extra.forEach((dataPath, index) => { extra.forEach((dataPath, index) => {
if (typeof dataPath === 'string') { if (typeof dataPath === 'string') {
if (!dataPath) { // model,prop.sync if (!dataPath) { // model,prop.sync
...@@ -981,8 +979,8 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam ...@@ -981,8 +979,8 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam
let isCustomMPEvent = false; // wxcomponent 组件,传递原始 event 对象 let isCustomMPEvent = false; // wxcomponent 组件,传递原始 event 对象
if (isCustom) { // 自定义事件 if (isCustom) { // 自定义事件
isCustomMPEvent = event.currentTarget && isCustomMPEvent = event.currentTarget &&
event.currentTarget.dataset && event.currentTarget.dataset &&
event.currentTarget.dataset.comType === 'wx'; event.currentTarget.dataset.comType === 'wx';
if (!args.length) { // 无参数,直接传入 event 或 detail 数组 if (!args.length) { // 无参数,直接传入 event 或 detail 数组
if (isCustomMPEvent) { if (isCustomMPEvent) {
return [event] return [event]
...@@ -1024,30 +1022,33 @@ const CUSTOM = '^'; ...@@ -1024,30 +1022,33 @@ const CUSTOM = '^';
function isMatchEventType (eventType, optType) { function isMatchEventType (eventType, optType) {
return (eventType === optType) || return (eventType === optType) ||
( (
optType === 'regionchange' && optType === 'regionchange' &&
( (
eventType === 'begin' || eventType === 'begin' ||
eventType === 'end' eventType === 'end'
) )
) )
} }
function handleEvent (event) { function handleEvent (event) {
event = wrapper$2(event); event = wrapper$2(event);
// [['tap',[['handle',[1,2,a]],['handle1',[1,2,a]]]]] // [['tap',[['handle',[1,2,a]],['handle1',[1,2,a]]]]]
const dataset = (event.currentTarget || event.target).dataset; const dataset = (event.currentTarget || event.target).dataset;
if (!dataset) { if (!dataset) {
return console.warn(`事件信息不存在`) return console.warn(`事件信息不存在`)
} }
const eventOpts = dataset.eventOpts || dataset['event-opts'];// 支付宝 web-view 组件 dataset 非驼峰 const eventOpts = dataset.eventOpts || dataset['event-opts']; // 支付宝 web-view 组件 dataset 非驼峰
if (!eventOpts) { if (!eventOpts) {
return console.warn(`事件信息不存在`) return console.warn(`事件信息不存在`)
} }
// [['handle',[1,2,a]],['handle1',[1,2,a]]] // [['handle',[1,2,a]],['handle1',[1,2,a]]]
const eventType = event.type; const eventType = event.type;
const ret = [];
eventOpts.forEach(eventOpt => { eventOpts.forEach(eventOpt => {
let type = eventOpt[0]; let type = eventOpt[0];
const eventsArray = eventOpt[1]; const eventsArray = eventOpt[1];
...@@ -1064,8 +1065,8 @@ function handleEvent (event) { ...@@ -1064,8 +1065,8 @@ function handleEvent (event) {
let handlerCtx = this.$vm; let handlerCtx = this.$vm;
if ( if (
handlerCtx.$options.generic && handlerCtx.$options.generic &&
handlerCtx.$parent && handlerCtx.$parent &&
handlerCtx.$parent.$parent handlerCtx.$parent.$parent
) { // mp-weixin,mp-toutiao 抽象节点模拟 scoped slots ) { // mp-weixin,mp-toutiao 抽象节点模拟 scoped slots
handlerCtx = handlerCtx.$parent.$parent; handlerCtx = handlerCtx.$parent.$parent;
} }
...@@ -1079,18 +1080,26 @@ function handleEvent (event) { ...@@ -1079,18 +1080,26 @@ function handleEvent (event) {
} }
handler.once = true; handler.once = true;
} }
handler.apply(handlerCtx, processEventArgs( ret.push(handler.apply(handlerCtx, processEventArgs(
this.$vm, this.$vm,
event, event,
eventArray[1], eventArray[1],
eventArray[2], eventArray[2],
isCustom, isCustom,
methodName methodName
)); )));
} }
}); });
} }
}); });
if (
eventType === 'input' &&
ret.length === 1 &&
typeof ret[0] !== 'undefined'
) {
return ret[0]
}
} }
const hooks = [ const hooks = [
...@@ -1257,8 +1266,8 @@ function createApp (vm) { ...@@ -1257,8 +1266,8 @@ function createApp (vm) {
} }
function parseBaseComponent (vueComponentOptions, { function parseBaseComponent (vueComponentOptions, {
isPage: isPage$$1, isPage,
initRelation: initRelation$$1 initRelation
} = {}) { } = {}) {
let [VueComponent, vueOptions] = initVueComponent(Vue, vueComponentOptions); let [VueComponent, vueOptions] = initVueComponent(Vue, vueComponentOptions);
...@@ -1275,7 +1284,7 @@ function parseBaseComponent (vueComponentOptions, { ...@@ -1275,7 +1284,7 @@ function parseBaseComponent (vueComponentOptions, {
const properties = this.properties; const properties = this.properties;
const options = { const options = {
mpType: isPage$$1.call(this) ? 'page' : 'component', mpType: isPage.call(this) ? 'page' : 'component',
mpInstance: this, mpInstance: this,
propsData: properties propsData: properties
}; };
...@@ -1283,7 +1292,7 @@ function parseBaseComponent (vueComponentOptions, { ...@@ -1283,7 +1292,7 @@ function parseBaseComponent (vueComponentOptions, {
initVueIds(properties.vueId, this); initVueIds(properties.vueId, this);
// 处理父子关系 // 处理父子关系
initRelation$$1.call(this, { initRelation.call(this, {
vuePid: this._$vuePid, vuePid: this._$vuePid,
vueOptions: options vueOptions: options
}); });
...@@ -1327,7 +1336,7 @@ function parseBaseComponent (vueComponentOptions, { ...@@ -1327,7 +1336,7 @@ function parseBaseComponent (vueComponentOptions, {
} }
}; };
if (isPage$$1) { if (isPage) {
return componentOptions return componentOptions
} }
return [componentOptions, VueComponent] return [componentOptions, VueComponent]
...@@ -1361,10 +1370,7 @@ function parseBasePage (vuePageOptions, { ...@@ -1361,10 +1370,7 @@ function parseBasePage (vuePageOptions, {
isPage, isPage,
initRelation initRelation
}) { }) {
const pageOptions = parseComponent$1(vuePageOptions, { const pageOptions = parseComponent$1(vuePageOptions);
isPage,
initRelation
});
initHooks(pageOptions.methods, hooks$2, vuePageOptions); initHooks(pageOptions.methods, hooks$2, vuePageOptions);
...@@ -1428,6 +1434,9 @@ let uni = {}; ...@@ -1428,6 +1434,9 @@ let uni = {};
if (typeof Proxy !== 'undefined' && "app-plus" !== 'app-plus') { if (typeof Proxy !== 'undefined' && "app-plus" !== 'app-plus') {
uni = new Proxy({}, { uni = new Proxy({}, {
get (target, name) { get (target, name) {
if (target[name]) {
return target[name]
}
if (baseApi[name]) { if (baseApi[name]) {
return baseApi[name] return baseApi[name]
} }
...@@ -1441,9 +1450,13 @@ if (typeof Proxy !== 'undefined' && "app-plus" !== 'app-plus') { ...@@ -1441,9 +1450,13 @@ if (typeof Proxy !== 'undefined' && "app-plus" !== 'app-plus') {
return return
} }
return promisify(name, wrapper(name, wx[name])) return promisify(name, wrapper(name, wx[name]))
},
set (target, name, value) {
target[name] = value;
return true
} }
}); });
} else { } else {
Object.keys(baseApi).forEach(name => { Object.keys(baseApi).forEach(name => {
uni[name] = baseApi[name]; uni[name] = baseApi[name];
}); });
...@@ -1477,4 +1490,4 @@ wx.createComponent = createComponent; ...@@ -1477,4 +1490,4 @@ wx.createComponent = createComponent;
var uni$1 = uni; var uni$1 = uni;
export default uni$1; export default uni$1;
export { createApp, createPage, createComponent }; export { createApp, createComponent, createPage };
{ {
"name": "@dcloudio/uni-app-plus", "name": "@dcloudio/uni-app-plus",
"version": "0.0.248", "version": "1.0.0-alpha-22120190814002",
"description": "uni-app app-plus", "description": "uni-app app-plus",
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"author": "fxy060608", "author": "fxy060608",
"license": "Apache-2.0" "license": "Apache-2.0",
"gitHead": "08ea04b669e93f0db3acb2dfa38138298edd5789"
} }
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
\ No newline at end of file
const {
updateAppJson,
updatePageJson,
updateUsingComponents,
getChangedJsonFileMap
} = require('../lib/cache')
describe('shared:cache', () => {
it('generate app.json', () => {
const name = 'app'
const appJson = {
debug: true
}
updateAppJson(name, appJson)
let appJsonStr = getChangedJsonFileMap().get(name + '.json')
expect(appJsonStr).toBe(JSON.stringify(appJson, null, 2))
expect(0).toBe(getChangedJsonFileMap().size)
appJson.resizable = true
updateAppJson(name, appJson)
appJsonStr = getChangedJsonFileMap().get(name + '.json')
expect(appJsonStr).toBe(JSON.stringify(appJson, null, 2))
expect(0).toBe(getChangedJsonFileMap().size)
const usingComponents = {
'my-component': '/components/component-tag-name'
}
updateUsingComponents('app', usingComponents)
appJsonStr = getChangedJsonFileMap().get(name + '.json')
appJson.usingComponents = usingComponents
expect(appJsonStr).toBe(JSON.stringify(appJson, null, 2))
})
it('generate page.json', () => {
const name = 'page/index/index'
const pageJson = {
navigationBarBackgroundColor: '#ffffff'
}
updatePageJson(name, pageJson)
let pageJsonStr = getChangedJsonFileMap().get(name + '.json')
expect(pageJsonStr).toBe(JSON.stringify(pageJson, null, 2))
expect(0).toBe(getChangedJsonFileMap().size)
pageJson.navigationBarTextStyle = 'black'
updatePageJson(name, pageJson)
pageJsonStr = getChangedJsonFileMap().get(name + '.json')
expect(pageJsonStr).toBe(JSON.stringify(pageJson, null, 2))
expect(0).toBe(getChangedJsonFileMap().size)
const usingComponents = {
'my-component1': '/components/component-tag-name1'
}
updateUsingComponents(name, usingComponents)
pageJsonStr = getChangedJsonFileMap().get(name + '.json')
pageJson.usingComponents = usingComponents
expect(pageJsonStr).toBe(JSON.stringify(pageJson, null, 2))
})
it('generate component.json', () => {
const name = 'components/component-tag-name'
let usingComponents = {
'my-component': '/components/component-tag-name'
}
updateUsingComponents(name, usingComponents, 'Component')
let componentJsonStr = getChangedJsonFileMap().get(name + '.json')
expect(componentJsonStr).toBe(JSON.stringify({
usingComponents,
component: true
}, null, 2))
expect(0).toBe(getChangedJsonFileMap().size)
usingComponents = {}
updateUsingComponents(name, usingComponents, 'Component')
componentJsonStr = getChangedJsonFileMap().get(name + '.json')
expect(componentJsonStr).toBe(JSON.stringify({
usingComponents,
component: true
}, null, 2))
expect(0).toBe(getChangedJsonFileMap().size)
})
})
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册