提交 108a3508 编写于 作者: Q qiang

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

......@@ -12,5 +12,5 @@
"message": "chore(release): publish %s"
}
},
"version": "3.0.0-alpha-24020191018017"
"version": "3.0.0-alpha-24020191018022"
}
......@@ -192,7 +192,9 @@ const third = [
'offPush',
'requireNativePlugin',
'upx2px',
'restoreGlobal'
'restoreGlobal',
'getSubNVueById',
'getCurrentSubNVue'
]
const apis = [
......
......@@ -28,7 +28,7 @@
"release": "npm run lint:cli && lerna publish --force-publish=*",
"release:alpha": "npm run lint:cli && lerna publish --force-publish=* --npm-tag=alpha",
"release:next": "npm run lint:cli && lerna publish --force-publish=* --npm-tag=next",
"release:v3": "npm run lint:cli && lerna publish --force-publish=* --npm-tag=v3"
"release:v3": "npm run lint:cli && lerna publish --no-git-tag-version --force-publish=* --npm-tag=v3"
},
"dependencies": {
"base64-arraybuffer": "^0.2.0",
......
{
"name": "@dcloudio/uni-app-plus-nvue",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-app app-plus-nvue",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
......@@ -1391,3 +1391,12 @@ uni-video[hidden] {
pointer-events: none;
}
uni-web-view {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
{
"name": "@dcloudio/uni-app-plus",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-app app-plus",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/uni-cli-shared",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-cli-shared",
"main": "lib/index.js",
"repository": {
......@@ -21,5 +21,5 @@
"hash-sum": "^1.0.2",
"strip-json-comments": "^2.0.1"
},
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/uni-h5-ui",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-app h5 ui",
"main": "dist/index.umd.min.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/uni-h5",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-app h5",
"main": "dist/index.umd.min.js",
"repository": {
......@@ -18,5 +18,5 @@
"intersection-observer": "^0.7.0",
"safe-area-insets": "^1.4.1"
},
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/uni-mp-alipay",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-app mp-alipay",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/uni-mp-baidu",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-app mp-baidu",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/uni-mp-qq",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-app mp-qq",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/uni-mp-toutiao",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-app mp-toutiao",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/uni-mp-weixin",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-app mp-weixin",
"main": "dist/index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/uni-stat",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "",
"main": "dist/index.js",
"repository": {
......@@ -34,5 +34,5 @@
"rollup-plugin-replace": "^2.2.0",
"rollup-plugin-uglify": "^6.0.2"
},
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/uni-template-compiler",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-template-compiler",
"main": "lib/index.js",
"repository": {
......@@ -22,5 +22,5 @@
"@babel/types": "^7.3.3",
"vue-template-compiler": "^2.6.10"
},
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/vue-cli-plugin-hbuilderx",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "HBuilderX plugin for vue-cli 3",
"main": "index.js",
"repository": {
......@@ -18,5 +18,5 @@
"css": "~2.2.1",
"escodegen": "^1.8.1"
},
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/vue-cli-plugin-uni-optimize",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-app optimize plugin for vue-cli 3",
"main": "index.js",
"repository": {
......@@ -13,5 +13,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/vue-cli-plugin-uni",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-app plugin for vue-cli 3",
"main": "index.js",
"repository": {
......@@ -17,7 +17,7 @@
"author": "fxy060608",
"license": "Apache-2.0",
"dependencies": {
"@dcloudio/uni-stat": "^3.0.0-alpha-24020191018017",
"@dcloudio/uni-stat": "^3.0.0-alpha-24020191018022",
"copy-webpack-plugin": "^4.6.0",
"cross-env": "^5.2.0",
"envinfo": "^6.0.1",
......@@ -34,5 +34,5 @@
"wrap-loader": "^0.2.0",
"xregexp": "4.0.0"
},
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
{
"name": "@dcloudio/webpack-uni-mp-loader",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "webpack-uni-mp-loader",
"main": "index.js",
"repository": {
......@@ -16,5 +16,5 @@
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
......@@ -41,7 +41,7 @@ var isReady=false;var onReadyCallbacks=[];
var __uniConfig = ${JSON.stringify(appJson, null)};
var __uniRoutes = ${JSON.stringify(__uniRoutes)};
__uniConfig.onReady=function(callback){if(__uniConfig.ready){callback()}else{onReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"ready",{get:function(){return isReady},set:function(val){isReady=val;if(!isReady){return}const callbacks=onReadyCallbacks.slice(0);onReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}});
service.register('uni-app-config', {create(id, env, config) {if(!__uniConfig.viewport){Object.assign(__uniConfig,{"viewport": env.weex.config.env.deviceWidth,"defaultFontSize": env.weex.config.env.deviceWidth / 20})}return {instance: {__uniConfig: __uniConfig,__uniRoutes: __uniRoutes}}}});
service.register("uni-app-config",{create(a,b,c){if(!__uniConfig.viewport){var d=b.weex.config.env.scale,e=b.weex.config.env.deviceWidth,f=Math.ceil(e/d);Object.assign(__uniConfig,{viewport:f,defaultFontSize:Math.round(f/20)})}return{instance:{__uniConfig:__uniConfig,__uniRoutes:__uniRoutes}}}});
`
}
}
{
"name": "@dcloudio/webpack-uni-pages-loader",
"version": "3.0.0-alpha-24020191018017",
"version": "3.0.0-alpha-24020191018022",
"description": "uni-app pages.json loader",
"main": "lib/index.js",
"repository": {
......@@ -23,5 +23,5 @@
"uni-app": {
"compilerVersion": "2.3.4"
},
"gitHead": "e5da9bbe2de350cb7302245c0e968a5610c65a23"
"gitHead": "a45fd8399f6eb89d466a2834475e3297cb2cd900"
}
......@@ -9,7 +9,7 @@ const eventNames = [
'pause',
'stop',
'ended',
'timeupdate',
'timeUpdate',
'prev',
'next',
'error',
......
......@@ -17,7 +17,9 @@ export function onWindowResize (callbackId) {
callbacks.push(callbackId)
}
export function offWindowResize (callbackId) {
export function offWindowResize (callbackId) {
// TODO 目前 on 和 off 即使传入同一个 function,获取到的 callbackId 也不会一致,导致不能 off 掉指定
// 后续修复
// 此处和微信平台一致查询不到去掉最后一个
callbacks.splice(callbacks.indexOf(callbackId), 1)
}
......@@ -19,6 +19,11 @@ export default function initOn (on, {
callAppHook(getApp(), 'onPageNotFound', page)
}
function onResize (args, pageId) {
const page = getCurrentPages().find(page => page.$page.id === pageId)
page && callPageHook(page, 'onResize', args)
}
function onPullDownRefresh (args, pageId) {
const page = getCurrentPages().find(page => page.$page.id === pageId)
if (page) {
......@@ -50,17 +55,6 @@ export default function initOn (on, {
callCurrentPageHook('onShow')
}
function onWebInvokeAppService ({
name,
arg
}, pageId) {
if (name === 'postMessage') {
// TODO 小程序后退、组件销毁、分享时通知
} else {
uni[name](arg)
}
}
const routeHooks = {
navigateTo () {
callCurrentPageHook('onHide')
......@@ -87,6 +81,7 @@ export default function initOn (on, {
on('onAppEnterBackground', onAppEnterBackground)
on('onAppEnterForeground', onAppEnterForeground)
on('onResize', onResize)
on('onPullDownRefresh', onPullDownRefresh)
on('onTabItemTap', createCallCurrentPageHook('onTabItemTap'))
......@@ -95,6 +90,4 @@ export default function initOn (on, {
on('onNavigationBarSearchInputChanged', createCallCurrentPageHook('onNavigationBarSearchInputChanged'))
on('onNavigationBarSearchInputConfirmed', createCallCurrentPageHook('onNavigationBarSearchInputConfirmed'))
on('onNavigationBarSearchInputClicked', createCallCurrentPageHook('onNavigationBarSearchInputClicked'))
on('onWebInvokeAppService', onWebInvokeAppService)
}
......@@ -125,11 +125,9 @@ function touchstart (evt) {
return
}
const {
touches: [{
pageX,
pageY
}]
} = evt
pageX,
pageY
} = evt.touches[0]
startPageX = pageX
startPageY = pageY
......@@ -156,12 +154,10 @@ function touchmove (evt) {
return clearLongPressTimer()
}
const {
touches: [{
pageX,
pageY
}]
} = evt
const {
pageX,
pageY
} = evt.touches[0]
if (Math.abs(pageX - startPageX) > LONGPRESS_THRESHOLD || Math.abs(pageY - startPageY) > LONGPRESS_THRESHOLD) {
return clearLongPressTimer()
......
......@@ -15,3 +15,4 @@ export const WEBVIEW_READY = 'webviewReady'
export const WEBVIEW_UI_EVENT = 'webviewUIEvent'
export const VD_SYNC_CALLBACK = 'vdSyncCallback'
export const INVOKE_API = 'invokeApi'
export const WEB_INVOKE_APPSERVICE = 'WEB_INVOKE_APPSERVICE'
......@@ -44,7 +44,8 @@ export * from './plugin/payment'
export * from './plugin/push'
export * from './plugin/require-native-plugin'
export * from './plugin/share'
export * from './plugin/restore-global'
export * from './plugin/restore-global'
export * from './plugin/sub-nvue'
export * from './route/navigate-back'
export * from './route/navigate-to'
......
import {
requireNativePlugin
} from './require-native-plugin'
function wrapper (webview) {
webview.$processed = true
webview.postMessage = function (data) {
plus.webview.postMessageToUniNView({
type: 'UniAppSubNVue',
data
}, webview.id)
}
let callbacks = []
webview.onMessage = function (callback) {
callbacks.push(callback)
}
webview.$consumeMessage = function (e) {
callbacks.forEach(callback => callback(e))
}
if (!webview.__uniapp_mask_id) {
return
}
const maskColor = webview.__uniapp_mask
let maskWebview = webview.__uniapp_mask_id === '0' ? {
setStyle ({
mask
}) {
requireNativePlugin('uni-tabview').setMask({
color: mask
})
}
} : plus.webview.getWebviewById(webview.__uniapp_mask_id)
const oldShow = webview.show
const oldHide = webview.hide
const oldClose = webview.close
const showMask = function () {
maskWebview.setStyle({
mask: maskColor
})
}
const closeMask = function () {
maskWebview.setStyle({
mask: 'none'
})
}
webview.show = function (...args) {
showMask()
return oldShow.apply(webview, args)
}
webview.hide = function (...args) {
closeMask()
return oldHide.apply(webview, args)
}
webview.close = function (...args) {
closeMask()
callbacks = []
return oldClose.apply(webview, args)
}
}
export function getSubNVueById (id) {
const webview = plus.webview.getWebviewById(id)
if (webview && !webview.$processed) {
wrapper(webview)
}
return webview
}
export function getCurrentSubNVue () {
return getSubNVueById(plus.webview.currentWebview().id)
}
......@@ -7,7 +7,8 @@ export {
pack,
unpack,
invoke
} from 'uni-core/service/bridge'
}
from 'uni-core/service/bridge'
export function requireNativePlugin (name) {
return uni.requireNativePlugin(name)
......@@ -16,8 +17,8 @@ export function requireNativePlugin (name) {
/**
* 触发 service 层,与 onMethod 对应
*/
export function publish (name, res) {
return UniServiceJSBridge.emit('api.' + name, res)
export function publish (name, ...args) {
return UniServiceJSBridge.emit('api.' + name, ...args)
}
let lastStatusBarStyle
......@@ -74,4 +75,4 @@ export function base64ToArrayBuffer (data) {
export function arrayBufferToBase64 (data) {
return encode(data)
}
}
......@@ -30,6 +30,10 @@ import {
perf
} from './perf'
import {
backbuttonListener
} from './backbutton'
let appCtx
export function getApp () {
......@@ -37,12 +41,11 @@ export function getApp () {
}
function initGlobalListeners () {
const emit = UniServiceJSBridge.emit
const emit = UniServiceJSBridge.emit
plus.key.addEventListener('backbutton', () => {
uni.navigateBack({
from: 'backbutton'
})
// splashclosed 时开始监听 backbutton
plus.globalEvent.addEventListener('splashclosed', () => {
plus.key.addEventListener('backbutton', backbuttonListener)
})
plus.globalEvent.addEventListener('pause', () => {
......@@ -140,7 +143,7 @@ export function registerApp (appVm) {
initAppLaunch(appVm)
__uniConfig.ready = true
__uniConfig.ready = true
process.env.NODE_ENV !== 'production' && perf('registerApp')
}
export function backbuttonListener () {
uni.navigateBack({
from: 'backbutton'
})
}
......@@ -42,7 +42,8 @@ export function registerPage ({
if (!webview) {
webview = createWebview(path, routeOptions)
} else {
webview = plus.webview.getWebviewById(webview.id)
webview = plus.webview.getWebviewById(webview.id)
webview.nvue = routeOptions.meta.isNVue
}
if (routeOptions.meta.isTabBar) {
......@@ -66,8 +67,10 @@ export function registerPage ({
const pageInstance = {
route,
options: Object.assign({}, query || {}),
$getAppWebview () {
return webview
$getAppWebview () {
// 重要,不能直接返回 webview 对象,因为 plus 可能会被二次替换,返回的 webview 对象内部的 plus 不正确
// 导致 webview.getStyle 等逻辑出错(旧的 webview 内部 plus 被释放)
return plus.webview.getWebviewById(webview.id)
},
$page: {
id: parseInt(webview.id),
......@@ -93,8 +96,7 @@ export function registerPage ({
pages.push(pageInstance)
// 首页是 nvue 时,在 registerPage 时,执行路由堆栈
if (webview.id === '1' && routeOptions.meta.isNVue) {
webview.nvue = true
if (webview.id === '1' && webview.nvue) {
__uniConfig.onReady(function () {
navigateFinish(webview)
})
......
......@@ -14,7 +14,7 @@ import {
import {
V_IF,
V_FOR,
V_FOR,
V_SHOW,
V_ELSE_IF,
B_CLASS,
......@@ -78,7 +78,7 @@ export function initData (Vue) {
return
}
if (this.mpType === 'page') {
this._$vdomSync = new VDomSync(this.$options.pageId, this.$options.pagePath)
this._$vdomSync = new VDomSync(this.$options.pageId, this.$options.pagePath, this)
}
if (this._$vd) {
this._$id = guid()
......@@ -115,7 +115,7 @@ function setData (id, name, value) {
case B_STYLE:
value = this._$normalizeStyleBinding(value)
break
case V_IF:
case V_IF:
case V_SHOW:
case V_ELSE_IF:
value = value ? 1 : 0
......
......@@ -15,11 +15,6 @@ import {
}
from 'uni-core/service/plugins/lifecycle'
import {
VD_SYNC,
PAGE_CREATE
} from '../../../constants'
import {
ON_REACH_BOTTOM_DISTANCE
}
......@@ -59,14 +54,7 @@ export function initLifecycle (Vue) {
const route = this.$scope.route
const pageId = this.$scope.$page.id
// 通知页面已开始创建
UniServiceJSBridge.publishHandler(VD_SYNC, {
data: [
[PAGE_CREATE, [pageId, route, parsePageCreateOptions(this, route)]]
],
options: {
timestamp: Date.now()
}
}, [pageId])
this._$vd.sendPageCreate([pageId, route, parsePageCreateOptions(this, route)])
}
},
created () {
......
......@@ -6,7 +6,9 @@ import {
import {
VD_SYNC,
UI_EVENT,
PAGE_CREATED
PAGE_CREATE,
PAGE_CREATED,
MOUNTED_DATA
} from '../../../constants'
import {
......@@ -47,13 +49,16 @@ function onVdSync (vdBatchData, vd) {
}
export class VDomSync {
constructor (pageId, pagePath) {
constructor (pageId, pagePath, pageVm) {
this.pageId = pageId
this.pagePath = pagePath
this.pageVm = pageVm
this.batchData = []
this.vms = Object.create(null)
this.initialized = false
this.pageCreateData = false
this.elements = [] // 目前仅存储事件 element
this._init()
......@@ -111,6 +116,18 @@ export class VDomSync {
this.batchData.push([type, [cid, data]])
}
sendPageCreate (data) {
this.pageCreateData = data
UniServiceJSBridge.publishHandler(VD_SYNC, {
data: [
[PAGE_CREATE, data]
],
options: {
timestamp: Date.now()
}
}, [this.pageId])
}
flush () {
if (!this.initialized) {
this.initialized = true
......@@ -127,6 +144,36 @@ export class VDomSync {
}
}
restorePageCreate () {
this.batchData.push([PAGE_CREATE, this.pageCreateData])
}
restoreMountedData () {
const addMountedData = (vm) => {
if (vm._$id) {
this.push(MOUNTED_DATA, vm._$id, vm._$data)
}
// TODO vue 中 $children 顺序不可靠,可能存在恢复误差
vm.$children.forEach(childVm => addMountedData(childVm))
}
addMountedData(this.pageVm)
}
restorePageCreated () {
this.batchData.push([PAGE_CREATED, [this.pageId, this.pagePath]])
}
restore () {
this.initialized = true
this.batchData.length = 0
this.restorePageCreate()
this.restoreMountedData()
this.restorePageCreated()
this.flush()
}
destroy () {
this.batchData.length = 0
this.vms = Object.create(null)
......
......@@ -4,7 +4,8 @@ import {
VD_SYNC,
VD_SYNC_CALLBACK,
INVOKE_API,
WEBVIEW_READY
WEBVIEW_READY,
WEB_INVOKE_APPSERVICE
} from '../../../constants'
import {
......@@ -16,10 +17,13 @@ import onWebviewReady from './on-webview-ready'
import onVdSync from './on-vd-sync'
import onVdSyncCallback from './on-vd-sync-callback'
import onInvokeApi from './on-invoke-api'
import onInvokeApi from './on-invoke-api'
import onWebInvokeAppService from './on-web-invoke-app-service'
export function initSubscribeHandlers () {
const {
on,
emit,
subscribe,
publishHandler,
subscribeHandler
......@@ -42,6 +46,11 @@ export function initSubscribeHandlers () {
// 防止首页 webview 初始化过早, service 还未开始监听
publishHandler(WEBVIEW_READY, Object.create(null), [1])
}
// 应该使用subscribe,兼容老版本先用 on api 吧
on('api.' + WEB_INVOKE_APPSERVICE, function (data, webviewIds) {
emit('onWebInvokeAppService', data, webviewIds)
})
on('onWebInvokeAppService', onWebInvokeAppService)
subscribe(VD_SYNC, onVdSync)
subscribe(VD_SYNC_CALLBACK, onVdSyncCallback)
......
function onMessage (pageId, arg) {
pageId = parseInt(pageId)
const page = getCurrentPages(true).find(page => page.$page.id === pageId)
if (!page) {
return
}
if (!page.$page.meta.isNVue) {
const target = page.$vm._$vd.elements.find(target => target.tagName === 'web-view' && target.events['message'])
if (!target) {
return
}
target.dispatchEvent('message', {
type: 'message',
target: Object.create(null),
currentTarget: Object.create(null),
timeStamp: Date.now(),
detail: {
data: [arg]
}
})
}
}
export default function onWebInvokeAppService ({
name,
arg
}, pageIds) {
if (name === 'postMessage') {
onMessage(pageIds[0], arg)
} else {
uni[name](arg)
}
}
const REGEX_UPX = /(\d+(\.\d+)?)[r|u]px/g
export function transformCSS (css) {
return css.replace(REGEX_UPX, (a, b) => {
return uni.upx2px(parseInt(b) || 0) + 'px'
})
}
......@@ -3,13 +3,29 @@ import {
} from './parser/webview-style-parser'
import {
publish
} from '../../bridge'
initSubNVues
} from './parser/sub-nvue-parser'
import {
VIEW_WEBVIEW_PATH
} from '../../constants'
import {
onWebviewClose
} from './on-webview-close'
import {
onWebviewResize
} from './on-webview-resize'
import {
onWebviewRecovery
} from './on-webview-recovery'
import {
onWebviewPopGesture
} from './on-webview-pop-gesture'
export let preloadWebview
let id = 2
......@@ -67,28 +83,22 @@ export function initWebview (webview, routeOptions) {
emit
} = UniServiceJSBridge
// TODO subNVues
initSubNVues(routeOptions, webview)
Object.keys(WEBVIEW_LISTENERS).forEach(name => {
webview.addEventListener(name, (e) => {
emit(WEBVIEW_LISTENERS[name], e, parseInt(webview.id))
})
})
webview.addEventListener('resize', ({
width,
height
}) => {
const res = {
size: {
windowWidth: Math.ceil(width),
windowHeight: Math.ceil(height)
}
}
publish('onViewDidResize', res)
emit('onResize', res, parseInt(webview.id))
})
onWebviewClose(webview)
onWebviewResize(webview)
if (plus.os.name === 'iOS') {
!webview.nvue && onWebviewRecovery(webview, routeOptions)
onWebviewPopGesture(webview)
}
// TODO 应该结束之前未完成的下拉刷新
on(webview.id + '.startPullDownRefresh', () => {
webview.beginPullToRefresh()
})
......@@ -102,9 +112,9 @@ export function initWebview (webview, routeOptions) {
export function createPreloadWebview () {
if (!preloadWebview || preloadWebview.__uniapp_route) { // 不存在,或已被使用
preloadWebview = plus.webview.create(VIEW_WEBVIEW_PATH, String(id++))
if (process.env.NODE_ENV !== 'production') {
console.log(`[uni-app] preloadWebview[${preloadWebview.id}]`)
preloadWebview = plus.webview.create(VIEW_WEBVIEW_PATH, String(id++))
if (process.env.NODE_ENV !== 'production') {
console.log(`[uni-app] preloadWebview[${preloadWebview.id}]`)
}
}
return preloadWebview
......
export function onWebviewClose (webview) {
webview.popupSubNVueWebviews && webview.addEventListener('close', () => {
Object.keys(webview.popupSubNVueWebviews).forEach(id => {
if (process.env.NODE_ENV !== 'production') {
console.log(
`UNIAPP[webview][${webview.id}]:popupSubNVueWebview[${id}].close`
)
}
webview.popupSubNVueWebviews[id].close('none')
})
})
}
export function onWebviewPopGesture (webview) {
// TODO 优化相关依赖性
// webview.addEventListener('popGesture', e => {
// if (e.type === 'start') {
// // 开始拖拽,还原状态栏前景色
// this.restoreStatusBarStyle()
// } else if (e.type === 'end' && !e.result) {
// // 拖拽未完成,设置为当前状态栏前景色
// this.setStatusBarStyle()
// } else if (e.type === 'end' && e.result) {
// removeWebview(this.id)
// const lastWebview = getLastWebview()
// if (lastWebview) {
// publish('onAppRoute', {
// path: lastWebview.page.replace('.html', ''),
// query: {},
// openType: 'navigateBack',
// webviewId: lastWebview.id
// })
// }
// }
// })
}
import {
WEBVIEW_READY
} from '../../../constants'
export function onWebviewRecovery (webview, routeOptions) {
const {
subscribe,
unsubscribe
} = UniServiceJSBridge
const id = webview.id
const onWebviewRecoveryReady = function (data, pageId) {
if (id !== pageId) {
return
}
unsubscribe(WEBVIEW_READY, onWebviewRecoveryReady)
if (process.env.NODE_ENV !== 'production') {
console.log(`UNIAPP[webview][${this.id}]:onWebviewRecoveryReady ready`)
}
// 恢复目标页面
pageId = parseInt(pageId)
const page = getCurrentPages(true).find(page => page.$page.id === pageId)
if (!page) {
return console.error(`Page[${pageId}] not found`)
}
page.$vm._$vd.restore()
}
webview.addEventListener('recovery', e => {
if (process.env.NODE_ENV !== 'production') {
console.log(`UNIAPP[webview][${this.id}].recovery.reload:` + JSON.stringify({
path: routeOptions.path,
webviewId: id
}))
}
subscribe(WEBVIEW_READY, onWebviewRecoveryReady)
})
}
import {
debounce
} from 'uni-shared'
import {
publish
} from '../../bridge'
export function onWebviewResize (webview) {
const onResize = function ({
width,
height
}) {
const landscape = Math.abs(plus.navigator.getOrientation()) === 90
const res = {
deviceOrientation: landscape ? 'landscape' : 'portrait',
size: {
windowWidth: Math.ceil(width),
windowHeight: Math.ceil(height)
}
}
publish('onViewDidResize', res) // API
UniServiceJSBridge.emit('onResize', res, parseInt(webview.id)) // Page lifecycle
}
webview.addEventListener('resize', debounce(onResize, 50))
}
import {
transformCSS
} from '../../upx'
export function parseStyleUnit (styles) {
let newStyles = {}
const stylesStr = JSON.stringify(styles)
if (~stylesStr.indexOf('upx') || ~stylesStr.indexOf('rpx')) {
try {
newStyles = JSON.parse(transformCSS(stylesStr))
} catch (e) {
newStyles = styles
console.error(e)
}
} else {
newStyles = JSON.parse(stylesStr)
}
return newStyles
}
import {
TITLEBAR_HEIGHT
} from '../../../constants'
import {
backbuttonListener
} from '../../backbutton'
import {
isTabBarPage
} from '../../../bridge'
import tabBar from '../../tab-bar'
function initPopupSubNVue (subNVueWebview, style, maskWebview) {
if (!maskWebview.popupSubNVueWebviews) {
maskWebview.popupSubNVueWebviews = {}
}
maskWebview.popupSubNVueWebviews[subNVueWebview.id] = subNVueWebview
if (process.env.NODE_ENV !== 'production') {
console.log(
`UNIAPP[webview][${maskWebview.id}]:add.popupSubNVueWebview[${subNVueWebview.id}]`
)
}
const hideSubNVue = function () {
maskWebview.setStyle({
mask: 'none'
})
subNVueWebview.hide('auto')
}
maskWebview.addEventListener('maskClick', hideSubNVue)
let isRemoved = false // 增加个 remove 标记,防止出错
subNVueWebview.addEventListener('show', () => {
if (!isRemoved) {
plus.key.removeEventListener('backbutton', backbuttonListener)
plus.key.addEventListener('backbutton', hideSubNVue)
isRemoved = true
}
})
subNVueWebview.addEventListener('hide', () => {
if (isRemoved) {
plus.key.removeEventListener('backbutton', hideSubNVue)
plus.key.addEventListener('backbutton', backbuttonListener)
isRemoved = false
}
})
subNVueWebview.addEventListener('close', () => {
delete maskWebview.popupSubNVueWebviews[subNVueWebview.id]
if (isRemoved) {
plus.key.removeEventListener('backbutton', hideSubNVue)
plus.key.addEventListener('backbutton', backbuttonListener)
isRemoved = false
}
})
}
function initNormalSubNVue (subNVueWebview, style, webview) {
webview.append(subNVueWebview)
}
function initSubNVue (subNVue, routeOptions, webview) {
if (!subNVue.path) {
return
}
const style = subNVue.style || {}
const isNavigationBar = subNVue.type === 'navigationBar'
const isPopup = subNVue.type === 'popup'
delete style.type
if (isPopup && !subNVue.id) {
console.warn('subNVue[' + subNVue.path + '] 尚未配置 id')
}
// TODO lazyload
style.uniNView = {
path: subNVue.path.replace('.nvue', '.js'),
defaultFontSize: __uniConfig.defaultFontSize,
viewport: __uniConfig.viewport
}
const extras = {
__uniapp_host: routeOptions.path,
__uniapp_origin: style.uniNView.path.split('?')[0].replace('.js', ''),
__uniapp_origin_id: webview.id,
__uniapp_origin_type: webview.__uniapp_type
}
let maskWebview
if (isNavigationBar) {
style.position = 'dock'
style.dock = 'top'
style.top = 0
style.width = '100%'
style.height = TITLEBAR_HEIGHT + plus.navigator.getStatusbarHeight()
delete style.left
delete style.right
delete style.bottom
delete style.margin
} else if (isPopup) {
style.position = 'absolute'
console.log(isTabBarPage(routeOptions.path))
if (isTabBarPage(routeOptions.path)) {
maskWebview = tabBar
} else {
maskWebview = webview
}
extras.__uniapp_mask = style.mask || 'rgba(0,0,0,0.5)'
extras.__uniapp_mask_id = maskWebview.id
}
if (process.env.NODE_ENV !== 'production') {
console.log(
`UNIAPP[webview][${webview.id}]:create[${subNVue.id}]:${JSON.stringify(style)}`
)
}
const subNVueWebview = plus.webview.create('', subNVue.id, style, extras)
if (isPopup) {
initPopupSubNVue(subNVueWebview, style, maskWebview)
} else {
initNormalSubNVue(subNVueWebview, style, webview)
}
}
export function initSubNVues (routeOptions, webview) {
const subNVues = routeOptions.window.subNVues
if (!subNVues || !subNVues.length) {
return
}
subNVues.forEach(subNVue => {
initSubNVue(subNVue, routeOptions, webview)
})
}
......@@ -4,7 +4,11 @@ import {
import {
parsePullToRefresh
} from './pull-to-refresh-parser'
} from './pull-to-refresh-parser'
import {
parseStyleUnit
} from './style-unit-parser'
const WEBVIEW_STYLE_BLACKLIST = [
'navigationBarBackgroundColor',
......@@ -27,10 +31,10 @@ export function parseWebviewStyle (id, path, routeOptions = {}) {
const webviewStyle = Object.create(null)
// 合并
routeOptions.window = Object.assign(
routeOptions.window = parseStyleUnit(Object.assign(
JSON.parse(JSON.stringify(__uniConfig.window || {})),
routeOptions.window || {}
)
))
Object.keys(routeOptions.window).forEach(name => {
if (WEBVIEW_STYLE_BLACKLIST.indexOf(name) === -1) {
......
<template>
<uni-web-view />
</template>
<script>
let webview = false
const insertHTMLWebView = ({
htmlId
}) => {
const parentWebview = plus.webview.currentWebview()
// fixed by hxy web-view 组件所在的 webview 不注入 uni-app 框架
const styles = {
'uni-app': 'none'
}
const parentTitleNView = parentWebview.getTitleNView()
if (parentTitleNView) {
styles.top = 44 + plus.navigator.getStatusbarHeight()
styles.bottom = 0
}
webview = plus.webview.create('', htmlId, styles)
if (parentTitleNView) {
webview.addEventListener('titleUpdate', function () {
let title = webview.getTitle()
parentWebview.setStyle({
titleNView: {
titleText: (!title || title === 'null') ? '' : title
}
})
})
}
plus.webview.currentWebview().append(webview)
}
const updateHTMLWebView = ({
htmlId,
src,
webviewStyles
}) => {
// fixed by xxx 非空时才执行更新操作
const realPath = src || ''
if (!realPath) {
return
}
if (/^(http|https):\/\//.test(realPath) && webviewStyles.progress) {
webview.setStyle({
progress: {
color: webviewStyles.progress.color
}
})
}
webview.loadURL(realPath)
}
const removeHTMLWebView = () => {
plus.webview.currentWebview().remove(webview)
webview.close('none')
webview = false
}
export default {
name: 'WebView',
props: {
src: {
type: String,
default: ''
},
webviewStyles: {
type: Object,
default () {
return {}
}
}
},
watch: {
src (val, oldVal) {
webview && updateHTMLWebView({
src: this.$getRealPath(val),
webviewStyles: this.webviewStyles
})
}
},
mounted () {
this.htmlId = 'webviewId' + this.$page.id
insertHTMLWebView({
htmlId: this.htmlId
})
updateHTMLWebView({
src: this.$getRealPath(this.src),
webviewStyles: this.webviewStyles
})
},
beforeDestroy () {
removeHTMLWebView()
}
}
</script>
<style>
uni-web-view {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
</style>
......@@ -12,7 +12,8 @@ import {
export default {
install (Vue, options) {
if (process.env.NODE_ENV !== 'production') {
if (process.env.NODE_ENV !== 'production') {
Vue.config.productionTip = false
Vue.config.performance = true
}
......
......@@ -78,4 +78,13 @@ export function updateElementStyle (element, styles) {
export function guid () {
return Math.floor(4294967296 * (1 + Math.random())).toString(16).slice(1)
}
export function debounce (fn, delay) {
let timeout
return function () {
clearTimeout(timeout)
const timerFn = () => fn.apply(this, arguments)
timeout = setTimeout(timerFn, delay)
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册