提交 99d48bbf 编写于 作者: Q qiang

Merge branch 'dev' into alpha

......@@ -40,7 +40,7 @@
## 更新日志
`uni-app`一直保持高频的更新迭代,详见[uni-app 更新日志](docs/release.md)
`uni-app`一直保持高频的更新迭代,详见[正式版更新日志](https://uniapp.dcloud.net.cn/release)[Alpha版更新日志](https://uniapp.dcloud.net.cn/release-note-alpha)
## 论坛
......
......@@ -28,6 +28,10 @@ const PLATFORMS = {
prefix: 'ks',
title: '快手小程序'
},
'mp-lark': {
prefix: 'tt',
title: '飞书小程序'
},
'quickapp-webview': {
prefix: 'qa',
title: '快应用(Webview)版'
......@@ -85,4 +89,4 @@ module.exports = {
})
],
external: ['vue', '@dcloudio/uni-i18n']
}
}
......@@ -223,6 +223,7 @@ const third = [
'preLogin',
'closeAuthView',
'getCheckBoxState',
'getUniverifyManager',
'share',
'shareWithSystem',
'showShareMenu',
......
......@@ -19,11 +19,12 @@
"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:mp-kuaishou": "cross-env UNI_PLATFORM=mp-kuaishou rollup -c build/rollup.config.mp.js",
"build:mp-lark": "cross-env UNI_PLATFORM=mp-lark rollup -c build/rollup.config.mp.js",
"build:quickapp-webview": "cross-env UNI_PLATFORM=quickapp-webview rollup -c build/rollup.config.mp.js",
"build:mp-weixin:mp": "cross-env UNI_PLATFORM=mp-weixin UNI_MP=true rollup -c build/rollup.config.mp.js",
"build:mp-weixin:wxs": "rollup -c build/rollup.config.wxs.js",
"build:quickapp-native": "cross-env NODE_ENV=development node build/build.qa.js && cross-env NODE_ENV=production node build/build.qa.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 && npm run build:quickapp-webview && npm run build:quickapp-native && npm run build:mp-kuaishou",
"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 && npm run build:quickapp-webview && npm run build:quickapp-native && npm run build:mp-kuaishou && npm run build:mp-lark",
"build:stat": "npm run lint && rollup -c build/rollup.config.stat.js",
"build:web-view": "rollup -c build/rollup.config.web-view.js",
"test:cli": "cross-env NODE_ENV=test jest",
......
......@@ -122,7 +122,7 @@ module.exports = {
getShadowCss,
getShadowTemplate (colorType = 'grey') {
let tagName = 'cover-image'
if (process.env.UNI_PLATFORM === 'mp-toutiao') {
if (process.env.UNI_PLATFORM === 'mp-toutiao' || process.env.UNI_PLATFORM === 'mp-lark') {
tagName = 'image'
}
return `<${tagName} src="https://cdn.dcloud.net.cn/img/shadow-${colorType}.png" style="z-index:998;position:fixed;left:0;top:0;width:100%;height:3px;"/>`
......
......@@ -10,6 +10,7 @@ const inlineLimit =
process.env.UNI_PLATFORM === 'mp-qq' ||
process.env.UNI_PLATFORM === 'mp-toutiao' ||
process.env.UNI_PLATFORM === 'mp-kuaishou' ||
process.env.UNI_PLATFORM === 'mp-lark' ||
process.env.UNI_PLATFORM === 'app-plus' // v2需要base64,v3需要rewriteUrl
// mp-weixin,mp-qq,app-plus 非v3(即:需要base64的平台)
......@@ -46,4 +47,4 @@ module.exports = {
}
},
rewriteUrl
}
}
# `uni-mp-lark`
> TODO: description
## Usage
```
const uniMpLark = require('uni-mp-lark');
// TODO: DEMONSTRATE API
```
此差异已折叠。
const compiler = require('@dcloudio/uni-mp-weixin/lib/uni.compiler.js')
const path = require('path')
const t = require('@babel/types')
const crypto = require('crypto')
function generateJsCode (properties = '{}') {
return `tt.createComponent({
generic: true,
props: ${properties},
render: function(){}
})
`
}
function generateCssCode (filename) {
return `@import "./${filename}"
`
}
function getBaseName (ownerName, parentName, slotName, resourcePath) {
const str = `${resourcePath}/${parentName}/${slotName}`
const md5 = crypto.createHash('md5').update(str).digest('hex')
if (process.env.NODE_ENV !== 'development') {
return `m${md5.substring(0, 8)}`
}
return `${ownerName}--${parentName}--${slotName}--${md5.substring(0, 4)}`
}
function hasOwn (obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key)
}
module.exports = Object.assign({}, compiler, {
directive: 'tt:',
resolveScopedSlots (slotName, {
genCode,
generate,
ownerName,
parentName,
parentNode,
resourcePath,
paramExprNode,
returnExprNodes,
traverseExpr
}, state) {
if (!state.scopedSlots) {
state.scopedSlots = {}
}
const baseName = getBaseName(ownerName, parentName, slotName, resourcePath)
let componentName = baseName
if (!hasOwn(state.scopedSlots, baseName)) {
state.scopedSlots[baseName] = 0
}
if (state.scopedSlots[baseName]) {
componentName = baseName + state.scopedSlots[baseName]
}
state.scopedSlots[baseName]++
if (!parentNode.attr.generic) {
parentNode.attr.generic = {}
}
parentNode.attr.generic[slotName] = componentName
// 生成 scopedSlots 文件,包括 json,js, ttml, ttss, 还需要更新 owner 的 usingComponents
if (!state.files) {
state.files = {}
}
const extname = path.extname(resourcePath)
const templateFile = resourcePath.replace(ownerName + extname, componentName + extname)
const templateContent = generate(traverseExpr(returnExprNodes, state), state)
state.files[templateFile] = templateContent
const jsFile = resourcePath.replace(ownerName + extname, componentName + '.js')
const objectProperties = []
if (t.isObjectPattern(paramExprNode)) {
paramExprNode.properties.forEach(property => {
const key = property.key
const value = property.value
const valueObjectProperties = [
t.objectProperty(t.identifier('type'), t.nullLiteral())
]
if (t.isIdentifier(value)) {
if (value.name !== key.name) {
state.errors.add(`解构插槽 Prop 时,不支持将${key.name}重命名为${value.name},重命名后会影响性能`)
}
} else if (t.isAssignmentPattern(value)) {
valueObjectProperties.push(t.objectProperty(t.identifier('default'), value.right))
}
objectProperties.push(t.objectProperty(key, t.objectExpression(valueObjectProperties)))
})
} else {
state.errors.add(`目前仅支持解构插槽 ${paramExprNode.name},如 v-slot="{ user }"`)
}
const jsContent = generateJsCode(genCode(t.objectExpression(objectProperties), true))
state.files[jsFile] = jsContent
try {
// TODO 使用 getPlatformExts 在单元测试报错,改从 state.options.platform 判断
const { getPlatformExts } = require('@dcloudio/uni-cli-shared')
const styleExtname = getPlatformExts().style
const styleFile = resourcePath.replace(ownerName + extname, componentName + styleExtname)
const styleContent = generateCssCode(ownerName + styleExtname)
state.files[styleFile] = styleContent
} catch (error) { }
// webpack-uni-mp-loader/lib/plugin/generate-component 处理 json 文件还有修改 slot 模版
const fixExtname = '.fix'
const extFile = resourcePath.replace(ownerName + extname, componentName + fixExtname)
state.files[extFile] = `${resourcePath.replace(ownerName + extname, ownerName)},${parentName},${componentName},scoped-slots-${slotName}`
if (!state.generic) {
state.generic = []
}
// 存储,方便后续生成 json
state.generic.push(componentName)
return ''
}
})
module.exports = {
options: {
cssVars: {
'--status-bar-height': '25px',
'--window-top': '0px',
'--window-bottom': '0px',
'--window-left': '0px',
'--window-right': '0px'
},
extnames: {
style: '.ttss',
template: '.ttml'
},
subPackages: true,
project: 'project.lark.json'
},
copyWebpackOptions (platformOptions, vueOptions) {
const copyOptions = ['ttcomponents']
global.uniModules.forEach(module => {
copyOptions.push('uni_modules/' + module + '/ttcomponents')
})
return copyOptions
}
}
{
"name": "@dcloudio/uni-mp-lark",
"version": "2.0.0-alpha-32520210827002",
"description": "uni-app mp-lark",
"main": "dist/index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/dcloudio/uni-app.git",
"directory": "packages/uni-mp-lark"
},
"scripts": {
"test": "echo \"Error: run tests from root\" && exit 1"
},
"author": "PerfectPan",
"license": "Apache-2.0",
"uni-app": {
"name": "mp-lark",
"title": "飞书小程序"
}
}
......@@ -79,7 +79,8 @@ export const getPlatformName = () => {
'mp-toutiao': 'tt',
'mp-qq': 'qq',
'quickapp-native': 'qn',
'mp-kuaishou': 'ks'
'mp-kuaishou': 'ks',
'mp-lark': 'lark'
}
return platformList[process.env.VUE_APP_PLATFORM];
}
......
const compiler = require('../lib')
function assertCodegen (template, templateCode, renderCode = 'with(this){}', options = {}) {
const res = compiler.compile(template, {
resourcePath: 'test.wxml',
mp: Object.assign({
minified: true,
isTest: true,
platform: 'mp-lark'
}, options)
})
expect(res.template).toBe(templateCode)
expect(res.render).toBe(renderCode)
}
describe('mp:compiler-mp-lark', () => {
it('generate v-for directive', () => {
assertCodegen(
'<view><view v-for="(item,index) in items" :key="index"></view></view>',
'<view><block tt:for="{{items}}" tt:for-item="item" tt:for-index="index" tt:key="index"><view></view></block></view>'
)
})
it('generate ref', () => {
assertCodegen(
'<my-component ref="ref"></my-component>',
'<my-component class="vue-ref" vue-id="551070e6-1" data-ref="ref" bind:__l="__l"></my-component>'
)
})
it('generate class binding', () => {
assertCodegen(
'<div :class="{ active: isActive }">1</div>',
'<view class="{{((\'_div\')+\' \'+((isActive)?\'active\':\'\'))}}">1</view>'
)
assertCodegen(
'<p class="static" :class="{ active: isActive, \'text-danger\': hasError }">2</p>',
'<view class="{{((((\'static\')+\' \'+\'_p\')+\' \'+((isActive)?\'active\':\'\'))+\' \'+((hasError)?\'text-danger\':\'\'))}}">2</view>'
)
assertCodegen(
'<p class="static" :class="[activeClass, errorClass]">3</p>',
'<view class="{{((((\'static\')+\' \'+\'_p\')+\' \'+activeClass)+\' \'+errorClass)}}">3</view>'
)
assertCodegen(
'<p class="static" :class="[isActive ? activeClass : \'\', errorClass]">4</p>',
'<view class="{{((((\'static\')+\' \'+\'_p\')+\' \'+(isActive?activeClass:\'\'))+\' \'+errorClass)}}">4</view>'
)
assertCodegen(
'<p class="static" :class="[{ active: isActive }, errorClass]">5</p>',
'<view class="{{((((\'static\')+\' \'+\'_p\')+\' \'+((isActive)?\'active\':\'\'))+\' \'+errorClass)}}">5</view>'
)
assertCodegen(
'<p class="static" :class="[{ active: isActive, disabled: isDisabled }, errorClass]">52</p>',
'<view class="{{((((\'static\')+\' \'+\'_p\')+\' \'+(((isActive)?\'active\':\'\')+\' \'+((isDisabled)?\'disabled\':\'\')))+\' \'+errorClass)}}">52</view>'
)
assertCodegen(
'<div class="container" :class="computedClassObject">6</div>',
'<view class="{{(((\'container\')+\' \'+\'_div\')+\' \'+computedClassObject)}}">6</view>'
)
// assertCodegen(
// `<div class="container" :class="computedClassObject">6</div>`,
// `<view class="{{$root.c0}}">6</view>`,
// `with(this){var c0=__get_class(computedClassObject,"container");$mp.data=Object.assign({},{$root:{c0:c0}})}`
// )
assertCodegen(
'<p :class="index === currentIndex ? activeClass : itemClass">7</p>',
'<view class="{{((\'_p\')+\' \'+(index===currentIndex?activeClass:itemClass))}}">7</view>'
)
assertCodegen(
'<p :class="\'m-content-head-\'+message.user">8</p>',
'<view class="{{((\'_p\')+\' \'+(\'m-content-head-\'+message.user))}}">8</view>'
)
assertCodegen(
'<p :class="classStr1 || classStr2" class="bg">9</p>',
'<view class="{{(((\'bg\')+\' \'+\'_p\')+\' \'+(classStr1||classStr2))}}">9</view>'
)
assertCodegen(
'<p class="static" :class="[{ active: isActive }, errorClass, [flex, \'flex-row\']]">10</p>',
'<view class="{{(((((\'static\')+\' \'+\'_p\')+\' \'+((isActive)?\'active\':\'\'))+\' \'+errorClass)+\' \'+((flex)+\' \'+\'flex-row\'))}}">10</view>'
)
assertCodegen(
'<p class="a external-class c" :class="class1">hello world</p>',
'<view class="{{(((((\'a\')+\' \'+\'external-class\')+\' \'+\'c\')+\' \'+\'_p\')+\' \'+class1)}}">hello world</view>'
)
})
it('generate v-show directive', () => {
assertCodegen(
'<test v-show="shown">hello world</test>',
'<test bind:-data-custom-hidden="{{!(shown)}}" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}">hello world</test>'
)
})
})
......@@ -94,7 +94,7 @@ module.exports = {
if (options.mp.platform === 'mp-alipay') {
options.modules.push(compilerAlipayModule)
} else if (options.mp.platform === 'mp-toutiao') {
} else if (options.mp.platform === 'mp-toutiao' || options.mp.platform === 'mp-lark') {
options.modules.push(compilerToutiaoModule)
}
......@@ -150,7 +150,7 @@ module.exports = {
delete state.files
// resolve scoped slots
res.generic = state.generic || []
res.generic = state.generic || []
delete state.generic
// define scoped slots
......@@ -290,4 +290,4 @@ at ${resourcePath}.vue:1`)
ssrCompile,
ssrCompileToFunctions,
generateCodeFrame
}
}
......@@ -38,10 +38,9 @@ function processStaticClass (classArrayExpression, staticClassPath, state) {
}
staticClassPath.remove()
}
if (
state.options.platform.name === 'mp-toutiao' ||
state.options.platform.name === 'mp-alipay'
) {
const transPlatform = ['mp-toutiao', 'mp-alipay', 'mp-lark'];
if (transPlatform.includes(state.options.platform.name)) {
// classArrayExpression => binaryExpression
return processClassArrayExpressionElements(classArrayExpression)
}
......
......@@ -71,8 +71,8 @@ function processElement (ast, state, isRoot) {
Object.keys(ast.attr.generic).forEach(scopedSlotName => {
slots.push(scopedSlotName)
})
if (platformName === 'mp-toutiao') {
// 用于字节跳动小程序模拟抽象节点
if (platformName === 'mp-toutiao' || platformName === 'mp-lark') {
// 用于字节跳动|飞书小程序模拟抽象节点
ast.attr.generic = `{{${JSON.stringify(ast.attr.generic)}}}`.replace(/"/g, '\'')
} else {
delete ast.attr.generic
......
......@@ -231,10 +231,10 @@ function traverseDataNode (dataNode, state, node) {
let key
// 自定义组件不支持 hidden 属性
const platform = state.options.platform.name
const platforms = ['mp-weixin', 'mp-qq', 'mp-toutiao']
const platforms = ['mp-weixin', 'mp-qq', 'mp-toutiao', 'mp-lark']
if (isComponent(node.type) && platforms.includes(platform)) {
// 字节跳动小程序自定义属性不会反应在DOM上,只能使用事件格式
key = `${platform === 'mp-toutiao' ? 'bind:-' : ''}${ATTE_DATA_CUSTOM_HIDDEN}`
// 字节跳动|飞书小程序自定义属性不会反应在DOM上,只能使用事件格式
key = `${platform === 'mp-toutiao' || platform === 'mp-lark' ? 'bind:-' : ''}${ATTE_DATA_CUSTOM_HIDDEN}`
} else {
key = 'hidden'
}
......
......@@ -41,7 +41,7 @@ module.exports = (api, options) => {
}
}
const platforms = ['mp-weixin', 'mp-qq', 'mp-baidu', 'mp-alipay', 'mp-toutiao']
const platforms = ['mp-weixin', 'mp-qq', 'mp-baidu', 'mp-alipay', 'mp-toutiao', 'mp-lark']
if (args.subpackage && platforms.includes(process.env.UNI_PLATFORM)) {
process.env.UNI_SUBPACKGE = args.subpackage
}
......
......@@ -17,6 +17,7 @@ module.exports = (api, options, rootOptions) => {
'dev:mp-alipay': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch',
'dev:mp-toutiao': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-toutiao vue-cli-service uni-build --watch',
'dev:mp-kuaishou': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build --watch',
'dev:mp-lark': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-lark vue-cli-service uni-build --watch',
'dev:quickapp-native': 'cross-env NODE_ENV=development UNI_PLATFORM=quickapp-native vue-cli-service uni-build --watch',
'dev:quickapp-webview': 'cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview vue-cli-service uni-build --watch',
'dev:quickapp-webview-huawei': 'cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build --watch',
......@@ -28,6 +29,7 @@ module.exports = (api, options, rootOptions) => {
'build:mp-alipay': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build',
'build:mp-toutiao': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build',
'build:mp-kuaishou': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build',
'build:mp-lark': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-lark vue-cli-service uni-build',
'build:quickapp-native': 'cross-env NODE_ENV=production UNI_PLATFORM=quickapp-native vue-cli-service uni-build',
'build:quickapp-webview': 'cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview vue-cli-service uni-build',
'build:quickapp-webview-huawei': 'cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build',
......
......@@ -410,7 +410,7 @@ if (process.env.UNI_PLATFORM === 'h5') {
moduleAlias.addAlias('vue-style-loader', '@dcloudio/vue-cli-plugin-uni/packages/h5-vue-style-loader')
}
if (process.env.UNI_PLATFORM === 'mp-toutiao') {
if (process.env.UNI_PLATFORM === 'mp-toutiao' || process.env.UNI_PLATFORM === 'mp-lark') {
// !important 始终带有一个空格
moduleAlias.addAlias(
'postcss-normalize-whitespace',
......
......@@ -47,7 +47,7 @@ module.exports = function generateApp (compilation) {
// 框架预设样式 用于隐藏自定义组件
// TODO 分平台 import 不同 css
const platforms = ['mp-weixin', 'mp-qq', 'mp-toutiao']
const platforms = ['mp-weixin', 'mp-qq', 'mp-toutiao', 'mp-lark']
const presetStyle = platforms.includes(process.env.UNI_PLATFORM) ? '[data-custom-hidden="true"],[bind-data-custom-hidden="true"]{display: none !important;}' : ''
if (compilation.assets[`common/main${ext}`]) { // 是否存在 main.css
......
......@@ -145,7 +145,7 @@ module.exports = function generateComponent (compilation, jsonpFunction = 'webpa
}
}
}
// 处理字节跳动小程序作用域插槽
// 处理字节跳动|飞书小程序作用域插槽
const fixExtname = '.fix'
if (name.endsWith(fixExtname)) {
const source = assets[name].source()
......
......@@ -214,4 +214,4 @@ module.exports = function (content, map) {
}
this.callback(null, '', map)
}
}
......@@ -107,4 +107,4 @@ module.exports = function (content, map) {
})
this.callback(null, '', map)
}
}
module.exports = function (pagesJson, manifestJson) {
const {
app,
project
} = require('../mp')(pagesJson, manifestJson, require('./project.config.json'))
return [app, project]
}
\ No newline at end of file
{
"setting": {
"urlCheck": true,
"es6": false,
"postcss": false,
"minified": false,
"newFeature": true
},
"appid": "testAppId",
"projectname": ""
}
......@@ -29,6 +29,9 @@ import {
import {
initWebviewApi as initKuaishouWebviewApi
} from 'uni-platforms/mp-kuaishou/runtime/web-view'
import {
initWebviewApi as initLarkWebviewApi
} from 'uni-platforms/mp-lark/runtime/web-view'
const UniAppJSBridgeReady = function () {
window.UniAppJSBridge = true
......@@ -47,6 +50,7 @@ const initWebviewApis = [
initToutiaoWebviewApi,
initQuickappWebviewApi,
initKuaishouWebviewApi,
initLarkWebviewApi,
initH5WebviewApi
]
......
let deviceId
export default function () {
deviceId = deviceId || plus.runtime.getDCloudId()
deviceId = deviceId || plus.device.uuid
return deviceId
}
......@@ -52,7 +52,8 @@ function getLocationSuccess (type, position, callbackId) {
export function getLocation ({
type = 'wgs84',
geocode = false,
altitude = false
altitude = false,
highAccuracyExpireTime
} = {}, callbackId) {
const errorCallback = warpPlusErrorCallback(callbackId, 'getLocation')
plus.geolocation.getCurrentPosition(
......@@ -68,7 +69,8 @@ export function getLocation ({
errorCallback(e)
}, {
geocode: geocode,
enableHighAccuracy: altitude
enableHighAccuracy: altitude,
timeout: highAccuracyExpireTime
}
)
}
......@@ -5,7 +5,9 @@ import {
warpPlusSuccessCallback,
warpPlusErrorCallback
} from '../util'
import { isPlainObject } from 'uni-shared'
import { isPlainObject, toRawType, callback } from 'uni-shared'
let univerifyManager
function getService (provider) {
return new Promise((resolve, reject) => {
......@@ -19,20 +21,21 @@ function getService (provider) {
/**
* 微信登录
*/
export function login (params, callbackId) {
export function login (params, callbackId, plus = true) {
const provider = params.provider || 'weixin'
const errorCallback = warpPlusErrorCallback(callbackId, 'login')
const errorCallback = warpErrorCallback(callbackId, 'login', plus)
const authOptions = provider === 'apple'
? { scope: 'email' }
: params.univerifyStyle
? { univerifyStyle: univerifyButtonsClickHandling(params.univerifyStyle, errorCallback) }
: {}
const _invoke = plus ? invoke : callback.invoke
getService(provider).then(service => {
function login () {
if (params.onlyAuthorize && provider === 'weixin') {
service.authorize(({ code }) => {
invoke(callbackId, {
_invoke(callbackId, {
code,
authResult: '',
errMsg: 'login:ok'
......@@ -42,7 +45,7 @@ export function login (params, callbackId) {
}
service.login(res => {
const authResult = res.target.authResult
invoke(callbackId, {
_invoke(callbackId, {
code: authResult.code,
authResult: authResult,
errMsg: 'login:ok'
......@@ -137,9 +140,9 @@ export function operateWXData (params, callbackId) {
}
}
export function preLogin (params, callbackId) {
const successCallback = warpPlusSuccessCallback(callbackId, 'preLogin')
const errorCallback = warpPlusErrorCallback(callbackId, 'preLogin')
export function preLogin (params, callbackId, plus) {
const successCallback = warpSuccessCallback(callbackId, 'preLogin', plus)
const errorCallback = warpErrorCallback(callbackId, 'preLogin', plus)
getService(params.provider).then(service => service.preLogin(successCallback, errorCallback)).catch(errorCallback)
}
......@@ -147,9 +150,9 @@ export function closeAuthView () {
return getService('univerify').then(service => service.closeAuthView())
}
export function getCheckBoxState (params, callbackId) {
const successCallback = warpPlusSuccessCallback(callbackId, 'getCheckBoxState')
const errorCallback = warpPlusErrorCallback(callbackId, 'getCheckBoxState')
export function getCheckBoxState (params, callbackId, plus) {
const successCallback = warpSuccessCallback(callbackId, 'getCheckBoxState', plus)
const errorCallback = warpErrorCallback(callbackId, 'getCheckBoxState', plus)
try {
getService('univerify').then(service => {
const state = service.getCheckBoxState()
......@@ -164,22 +167,92 @@ export function getCheckBoxState (params, callbackId) {
* 一键登录自定义登陆按钮点击处理
*/
function univerifyButtonsClickHandling (univerifyStyle, errorCallback) {
if (univerifyStyle && isPlainObject(univerifyStyle) && univerifyStyle.buttons &&
Object.prototype.toString.call(univerifyStyle.buttons.list) === '[object Array]' &&
univerifyStyle.buttons.list.length > 0
) {
if (isPlainObject(univerifyStyle) && isPlainObject(univerifyStyle.buttons) && toRawType(univerifyStyle.buttons.list) === 'Array') {
univerifyStyle.buttons.list.forEach((button, index) => {
univerifyStyle.buttons.list[index].onclick = function () {
closeAuthView().then(() => {
errorCallback({
code: '30008',
message: '用户点击了自定义按钮',
index,
provider: button.provider
const res = {
code: '30008',
message: '用户点击了自定义按钮',
index,
provider: button.provider
}
isPlainObject(univerifyManager)
? univerifyManager._triggerUniverifyButtonsClick(res)
: closeAuthView().then(() => {
errorCallback(res)
})
})
}
})
}
return univerifyStyle
}
class UniverifyManager {
constructor () {
this.provider = 'univerify'
this.eventName = 'api.univerifyButtonsClick'
}
close () {
closeAuthView()
}
login (options) {
this._warp((data, callbackId) => login(data, callbackId, false), this._getOptions(options))
}
getCheckBoxState (options) {
this._warp((_, callbackId) => getCheckBoxState(_, callbackId, false), options)
}
preLogin (options) {
this._warp((data, callbackId) => preLogin(data, callbackId, false), this._getOptions(options))
}
onButtonsClick (callback) {
UniServiceJSBridge.on(this.eventName, callback)
}
offButtonsClick (callback) {
UniServiceJSBridge.off(this.eventName, callback)
}
_triggerUniverifyButtonsClick (res) {
UniServiceJSBridge.emit(this.eventName, res)
}
_warp (fn, options) {
return callback.warp(fn)(this._getOptions(options))
}
_getOptions (options = {}) {
return Object.assign({}, options, { provider: this.provider })
}
}
export function getUniverifyManager () {
return univerifyManager || (univerifyManager = new UniverifyManager())
}
function warpSuccessCallback (callbackId, name, plus = true) {
return plus
? warpPlusSuccessCallback(callbackId, name)
: (options) => {
callback.invoke(callbackId, Object.assign({}, options, {
errMsg: `${name}:ok`
}))
}
}
function warpErrorCallback (callbackId, name, plus = true) {
return plus
? warpPlusErrorCallback(callbackId, name)
: (error) => {
const { code = 0, message: errorMessage } = error
callback.invoke(callbackId, {
errMsg: `${name}:fail ${errorMessage || ''}`,
errCode: code,
code
})
}
}
......@@ -73,53 +73,55 @@ export default {
}
},
mounted () {
this._adId = 'AdView-' + this._newGUID()
const adStyle = Object.assign({
id: this._adId
}, this.position)
const adView = this.adView = plus.ad.createAdView(adStyle)
adView.interceptTouchEvent(false)
plus.webview.currentWebview().append(adView)
if (this.hidden) {
adView.hide()
}
this.$watch('attrs', () => {
this._request()
}, {
deep: true
})
this.$watch('position', () => {
this.adView && this.adView.setStyle(this.position)
}, {
deep: true
})
// 模板渲染有效
adView.setDislikeListener && adView.setDislikeListener((data) => {
this.adView && this.adView.close()
this.$refs.container.style.height = '0px'
this._updateView()
this._onParentReady(() => {
this._adId = 'AdView-' + this._newGUID()
const adStyle = Object.assign({
id: this._adId
}, this.position)
const adView = this.adView = plus.ad.createAdView(adStyle)
adView.interceptTouchEvent(false)
plus.webview.currentWebview().append(adView)
if (this.hidden) {
adView.hide()
}
this.$watch('attrs', () => {
this._request()
}, {
deep: true
})
this.$watch('position', () => {
this.adView && this.adView.setStyle(this.position)
}, {
deep: true
})
// 模板渲染有效
adView.setDislikeListener && adView.setDislikeListener((data) => {
this.adView && this.adView.close()
this.$refs.container.style.height = '0px'
this.$trigger('close', {}, data)
})
adView.setRenderingListener && adView.setRenderingListener((data) => {
if (data.result === 0) {
this.$refs.container.style.height = data.height + 'px'
this._updateView()
} else {
this.$trigger('error', {}, {
errCode: data.result
})
}
})
adView.setAdClickedListener((data) => {
this.$trigger('adclicked', {}, data)
})
this._callbackId = this.$page.id + this._adId
UniViewJSBridge.subscribe(this._callbackId, this._handleAdData.bind(this))
this.$trigger('close', {}, data)
})
adView.setRenderingListener && adView.setRenderingListener((data) => {
if (data.result === 0) {
this.$refs.container.style.height = data.height + 'px'
this._updateView()
} else {
this.$trigger('error', {}, {
errCode: data.result
})
}
})
adView.setAdClickedListener((data) => {
this.$trigger('adclicked', {}, data)
})
this._callbackId = this.$page.id + this._adId
UniViewJSBridge.subscribe(this._callbackId, this._handleAdData.bind(this))
this._request()
this._request()
})
},
beforeDestroy () {
this.adView && this.adView.close()
......
......@@ -15,12 +15,17 @@ export default {
render (createElement) {
let coverContent = ''
const $slots = this.$slots.default || []
$slots.forEach(node => {
if (!node.tag) {
coverContent += node.text || ''
}
})
this.coverContent = coverContent
const _slots = $slots.filter(node => node.tag)
if (!_slots.length) {
$slots.forEach(node => {
if (!node.tag) {
coverContent += node.text || ''
}
})
this.coverContent = coverContent
} else {
coverContent = _slots
}
return createElement('uni-cover-view', {
on: {
on: this.$listeners
......@@ -28,7 +33,7 @@ export default {
}, [createElement('div', {
ref: 'container',
staticClass: 'uni-cover-view'
}, [coverContent])])
}, [].concat(coverContent))])
}
}
</script>
......@@ -48,5 +53,6 @@ uni-cover-view[hidden] {
uni-cover-view .uni-cover-view {
width: 100%;
height: 100%;
visibility: hidden;
}
</style>
......@@ -189,34 +189,36 @@ export default {
}
},
mounted () {
const mapStyle = Object.assign({}, this.attrs, this.position)
if (this.latitude && this.longitude) {
mapStyle.center = new plus.maps.Point(this.longitude, this.latitude)
}
const map = this.map = plus.maps.create(this.$page.id + '-map-' + (this.id || Date.now()), mapStyle)
map.__markers__ = []
map.__markers_map__ = {}
map.__lines__ = []
map.__circles__ = []
map.setZoom(parseInt(this.scale))
plus.webview.currentWebview().append(map)
if (this.hidden) {
map.hide()
}
this.$watch('position', () => {
this.map && this.map.setStyles(this.position)
}, {
deep: true
this._onParentReady(() => {
const mapStyle = Object.assign({}, this.attrs, this.position)
if (this.latitude && this.longitude) {
mapStyle.center = new plus.maps.Point(this.longitude, this.latitude)
}
const map = this.map = plus.maps.create(this.$page.id + '-map-' + (this.id || Date.now()), mapStyle)
map.__markers__ = []
map.__markers_map__ = {}
map.__lines__ = []
map.__circles__ = []
map.setZoom(parseInt(this.scale))
plus.webview.currentWebview().append(map)
if (this.hidden) {
map.hide()
}
this.$watch('position', () => {
this.map && this.map.setStyles(this.position)
}, {
deep: true
})
map.onclick = (e) => {
this.$trigger('click', {}, e)
}
map.onstatuschanged = (e) => {
this.$trigger('regionchange', {}, {})
}
this._addMarkers(this.markers)
this._addMapLines(this.polyline)
this._addMapCircles(this.circles)
})
map.onclick = (e) => {
this.$trigger('click', {}, e)
}
map.onstatuschanged = (e) => {
this.$trigger('regionchange', {}, {})
}
this._addMarkers(this.markers)
this._addMapLines(this.polyline)
this._addMapCircles(this.circles)
},
beforeDestroy () {
this.map && this.map.close()
......
......@@ -197,30 +197,32 @@ export default {
}
},
mounted () {
const video = this.video = plus.video.createVideoPlayer('video' + Date.now(), Object.assign({}, this.attrs, this.position))
plus.webview.currentWebview().append(video)
if (this.hidden) {
video.hide()
}
this.$watch('attrs', () => {
this.video && this.video.setStyles(this.attrs)
}, { deep: true })
this.$watch('position', () => {
this.video && this.video.setStyles(this.position)
}, { deep: true })
this.$watch('hidden', (val) => {
const video = this.video
if (video) {
video[val ? 'hide' : 'show']()
// iOS 隐藏状态设置 setStyles 不生效
if (!val) {
video.setStyles(this.position)
}
this._onParentReady(() => {
const video = this.video = plus.video.createVideoPlayer('video' + Date.now(), Object.assign({}, this.attrs, this.position))
plus.webview.currentWebview().append(video)
if (this.hidden) {
video.hide()
}
})
events.forEach(key => {
video.addEventListener(key, (e) => {
this.$trigger(key, {}, { ...e.detail })
this.$watch('attrs', () => {
this.video && this.video.setStyles(this.attrs)
}, { deep: true })
this.$watch('position', () => {
this.video && this.video.setStyles(this.position)
}, { deep: true })
this.$watch('hidden', (val) => {
const video = this.video
if (video) {
video[val ? 'hide' : 'show']()
// iOS 隐藏状态设置 setStyles 不生效
if (!val) {
video.setStyles(this.position)
}
}
})
events.forEach(key => {
video.addEventListener(key, (e) => {
this.$trigger(key, {}, { ...e.detail })
})
})
})
},
......
......@@ -93,15 +93,17 @@ export default {
}
},
mounted () {
this.htmlId = WEBVIEW_ID_PREFIX + this.$page.id
insertHTMLWebView({
htmlId: this.htmlId
})
updateHTMLWebView({
src: this.$getRealPath(this.src),
webviewStyles: this.webviewStyles
this._onParentReady(() => {
this.htmlId = WEBVIEW_ID_PREFIX + this.$page.id
insertHTMLWebView({
htmlId: this.htmlId
})
updateHTMLWebView({
src: this.$getRealPath(this.src),
webviewStyles: this.webviewStyles
})
UniViewJSBridge.publishHandler(WEBVIEW_INSERTED, {}, this.$page.id)
})
UniViewJSBridge.publishHandler(WEBVIEW_INSERTED, {}, this.$page.id)
},
beforeDestroy () {
removeHTMLWebView()
......
......@@ -8,7 +8,8 @@ export default {
name: 'Cover',
data () {
return {
style: {}
style: {},
parentPosition: {}
}
},
computed: {
......@@ -17,12 +18,12 @@ export default {
for (const key in this.position) {
let val = this.position[key]
const valNumber = parseFloat(val)
const parentValNumber = parseFloat(this._nativeParent.position[key])
const parentValNumber = parseFloat(this.parentPosition[key])
if (key === 'top' || key === 'left') {
val = Math.max(valNumber, parentValNumber) + 'px'
} else if (key === 'width' || key === 'height') {
const base = key === 'width' ? 'left' : 'top'
const parentStart = parseFloat(this._nativeParent.position[base])
const parentStart = parseFloat(this.parentPosition[base])
const viewStart = parseFloat(this.position[base])
const diff1 = Math.max(parentStart - viewStart, 0)
const diff2 = Math.max((viewStart + valNumber) - (parentStart + parentValNumber), 0)
......@@ -91,16 +92,10 @@ export default {
this._nativeParent = $parent
},
mounted () {
this._updateStyle()
const $nativeParent = this._nativeParent
if ($nativeParent.isNative) {
if ($nativeParent._isMounted) {
this._onCanInsert()
} else {
$nativeParent.onCanInsertCallbacks.push(() => {
this._onCanInsert()
})
}
this._onParentReady((parentPosition) => {
this.parentPosition = this._nativeParent.position || parentPosition
this._updateStyle()
this._onCanInsert()
this.$watch('hidden', (val) => {
this.cover && this.cover[val ? 'hide' : 'show']()
})
......@@ -115,7 +110,7 @@ export default {
}
}, { deep: true })
this.$on('uni-view-update', this._requestStyleUpdate)
}
})
},
beforeDestroy () {
if (this._nativeParent.isNative) {
......@@ -139,7 +134,7 @@ export default {
for (const key in this.position) {
let val = this.position[key]
if (key === 'top' || key === 'left') {
val = Math.min((parseFloat(val) - parseFloat(this._nativeParent.position[key])), 0) + 'px'
val = Math.min((parseFloat(val) - parseFloat(this.parentPosition[key])), 0) + 'px'
}
position[key] = val
}
......
......@@ -26,15 +26,23 @@ export default {
hidden: false
}
},
provide () {
return {
parentOnDraw: this._onDraw
}
},
inject: {
parentOnDraw: { default: null }
},
created () {
this.isNative = true
this.onCanInsertCallbacks = []
this.onDrawCallbacks = []
},
mounted () {
this._updatePosition()
this.$nextTick(() => {
this.onCanInsertCallbacks.forEach(callback => callback())
})
this.onCanInsertCallbacks.forEach(callback => callback())
this.onCanInsertCallbacks = null
this.$on('uni-view-update', this._requestPositionUpdate)
},
methods: {
......@@ -60,6 +68,40 @@ export default {
delete this._positionUpdateRequest
this._updatePosition()
})
},
_onParentReady (parentReadyCallback) {
const callback = (parentPosition) => {
parentReadyCallback(parentPosition)
this.onDrawCallbacks.forEach(callback => callback(this.position))
this.onDrawCallbacks = null
}
this._onSelfReady(() => {
if (this.parentOnDraw) {
this.parentOnDraw(callback)
} else {
callback({
top: '0px',
left: '0px',
width: Number.MAX_SAFE_INTEGER + 'px',
height: Number.MAX_SAFE_INTEGER + 'px',
position: 'static'
})
}
})
},
_onSelfReady (callback) {
if (this.onCanInsertCallbacks) {
this.onCanInsertCallbacks.push(callback)
} else {
callback()
}
},
_onDraw (callback) {
if (this.onDrawCallbacks) {
this.onDrawCallbacks.push(callback)
} else {
callback(this.position)
}
}
}
}
......@@ -13,7 +13,8 @@ import {
*/
export function getLocation ({
type,
altitude
altitude,
highAccuracyExpireTime
}, callbackId) {
const {
invokeCallbackHandler: invoke
......@@ -24,7 +25,7 @@ export function getLocation ({
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(res => resolve(res.coords), reject, {
enableHighAccuracy: altitude,
timeout: 1000 * 100
timeout: highAccuracyExpireTime || 1000 * 100
})
} else {
reject(new Error('device nonsupport geolocation'))
......
import navigateTo from 'uni-helpers/navigate-to'
import redirectTo from '../../../mp-weixin/helpers/redirect-to'
import previewImage from '../../../mp-weixin/helpers/normalize-preview-image'
import getSystemInfo from '../../../mp-weixin/helpers/system-info'
import getUserProfile from '../../../mp-weixin/helpers/get-user-profile'
// 需要做转换的 API 列表
export const protocols = {
navigateTo,
redirectTo,
previewImage,
getSystemInfo,
getSystemInfoSync: getSystemInfo,
getUserProfile,
connectSocket: {
args: {
method: false
}
},
chooseVideo: {
args: {
camera: false
}
},
scanCode: {
args: {
onlyFromCamera: false
}
},
startAccelerometer: {
args: {
interval: false
}
},
showToast: {
args: {
image: false
}
},
showModal: {
args: {
cancelColor: false,
confirmColor: false
}
},
showActionSheet: {
args: {
itemColor: false,
alertText: false
}
},
login: {
args: {
scopes: false,
timeout: false
}
},
getUserInfo: {
args: {
lang: false,
timeout: false
}
}
}
export const todos = []
export const canIUses = []
export default {
oauth: ['lark'],
share: ['lark'],
payment: [''],
push: ['']
}
import '../../mp-weixin/runtime/index'
const isLark = window.tt &&
window.tt.miniProgram &&
/Lark|Feishu/i.test(navigator.userAgent)
export function initWebviewApi (readyCallback) {
if (!isLark) {
return
}
document.addEventListener('DOMContentLoaded', readyCallback)
return window.tt.miniProgram
}
import Vue from 'vue'
import parseBaseApp from '../../../mp-weixin/runtime/wrapper/app-base-parser'
import {
mocks,
initRefs
} from './util'
export default function parseApp (vm) {
Vue.prototype._$fallback = true // 降级(调整原 vue 的部分生命周期,如 created,beforeMount,inject,provide)
Vue.mixin({
created () { // 处理 injections, triggerEvent 是异步,且触发时机很慢,故延迟 relation 设置
if (this.mpType !== 'app') {
if (this.mpType === 'page' && !this.$scope.route && this.$scope.__route__
) {
this.$scope.route = this.$scope.__route__
}
initRefs(this)
this.__init_injections(this)
this.__init_provide(this)
}
}
})
return parseBaseApp(vm, {
mocks,
initRefs: function () {} // attached 时,可能查询不到
})
}
import {
isPage,
initRelation,
handleLink
} from './util'
import {
initSlots,
initVueIds
} from 'uni-wrapper/util'
import parseBaseComponent from '../../../mp-weixin/runtime/wrapper/component-base-parser'
export default function parseComponent (vueOptions) {
const [componentOptions, VueComponent] = parseBaseComponent(vueOptions)
componentOptions.lifetimes.attached = function attached () {
const properties = this.properties
const options = {
mpType: isPage.call(this) ? 'page' : 'component',
mpInstance: this,
propsData: properties
}
initVueIds(properties.vueId, this)
// 初始化 vue 实例
this.$vm = new VueComponent(options)
// 处理$slots,$scopedSlots(暂不支持动态变化$slots)
initSlots(this.$vm, properties.vueSlots)
// 处理父子关系
initRelation.call(this, {
vuePid: this._$vuePid,
mpInstance: this
})
// 触发首次 setData
this.$vm.$mount()
}
// ready 比 handleLink 还早,初始化逻辑放到 handleLink 中
delete componentOptions.lifetimes.ready
componentOptions.methods.__l = handleLink
return componentOptions
}
import {
isPage,
instances,
initRelation
} from './util'
import parseBasePage from '../../../mp-weixin/runtime/wrapper/page-base-parser'
export default function parsePage (vuePageOptions) {
const pageOptions = parseBasePage(vuePageOptions, {
isPage,
initRelation
})
// 页面需要在 ready 中触发,其他组件是在 handleLink 中触发
pageOptions.lifetimes.ready = function ready () {
if (this.$vm && this.$vm.mpType === 'page') {
this.$vm.__call_hook('created')
this.$vm.__call_hook('beforeMount')
this.$vm._isMounted = true
this.$vm.__call_hook('mounted')
this.$vm.__call_hook('onReady')
} else {
this.is && console.warn(this.is + ' is not ready')
}
}
pageOptions.lifetimes.detached = function detached () {
this.$vm && this.$vm.$destroy()
// 清理
const webviewId = this.__webviewId__
webviewId && Object.keys(instances).forEach(key => {
if (key.indexOf(webviewId + '_') === 0) {
delete instances[key]
}
})
}
return pageOptions
}
import {
findVmByVueId,
initRefs
} from '../../../mp-weixin/runtime/wrapper/util'
export { initRefs }
export const mocks = ['__route__', '__webviewId__', '__nodeid__', '__nodeId__']
export const instances = Object.create(null)
export function isPage () {
return this.__nodeid__ === 0 || this.__nodeId__ === 0
}
export function initRelation ({
vuePid,
mpInstance
}) {
// triggerEvent 后,接收事件时机特别晚,已经到了 ready 之后
const nodeId = (mpInstance.__nodeId__ || mpInstance.__nodeid__) + ''
const webviewId = mpInstance.__webviewId__ + ''
instances[webviewId + '_' + nodeId] = mpInstance.$vm
this.triggerEvent('__l', {
vuePid,
nodeId,
webviewId
})
}
export function handleLink ({
detail: {
vuePid,
nodeId,
webviewId
}
}) {
const vm = instances[webviewId + '_' + nodeId]
if (!vm) {
return
}
let parentVm
if (vuePid) {
parentVm = findVmByVueId(this.$vm, vuePid)
}
if (!parentVm) {
parentVm = this.$vm
}
vm.$parent = parentVm
vm.$root = parentVm.$root
parentVm.$children.push(vm)
vm.__call_hook('created')
vm.__call_hook('beforeMount')
vm._isMounted = true
vm.__call_hook('mounted')
vm.__call_hook('onReady')
}
......@@ -111,7 +111,7 @@ export default function parseBaseApp (vm, {
}) {
initEventChannel()
if (__PLATFORM__ === 'mp-weixin' || __PLATFORM__ === 'mp-qq' || __PLATFORM__ === 'mp-toutiao' || __PLATFORM__ ===
'mp-kuaishou' || __PLATFORM__ === 'mp-alipay' || __PLATFORM__ === 'mp-baidu') {
'mp-kuaishou' || __PLATFORM__ === 'mp-alipay' || __PLATFORM__ === 'mp-baidu' || __PLATFORM__ === 'mp-lark') {
initScopedSlotsParams()
}
if (vm.$options.store) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册