提交 46869d42 编写于 作者: Q qiang

Merge branch 'dev' into alpha

......@@ -28,12 +28,19 @@ const DEPS = {
['/platforms/h5/view/components/map/index.vue', 'Map'],
['/core/view/components/input/index.vue', 'Input'],
['/core/view/components/scroll-view/index.vue', 'ScrollView'],
['/platforms/h5/service/api/network/request.js', 'request'],
['/platforms/h5/service/api/location/get-location.js', 'getLocation'],
['/platforms/h5/components/system-routes/choose-location/index.vue', 'ChooseLocation']
],
openLocation: [
['/platforms/h5/view/components/map/index.vue', 'Map'],
['/platforms/h5/service/api/network/request.js', 'request'],
['/platforms/h5/service/api/location/get-location.js', 'getLocation'],
['/platforms/h5/components/system-routes/open-location/index.vue', 'OpenLocation']
],
getLocation: [
['/platforms/h5/service/api/network/request.js', 'request']
],
previewImage: [
['/core/view/components/swiper/index.vue', 'Swiper'],
['/core/view/components/swiper-item/index.vue', 'SwiperItem'],
......
import Vue from 'vue';
import { initVueI18n } from '@dcloudio/uni-i18n';
let realAtob;
const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const b64re = /^(?:[A-Za-z\d+/]{4})*?(?:[A-Za-z\d+/]{2}(?:==)?|[A-Za-z\d+/]{3}=?)?$/;
if (typeof atob !== 'function') {
realAtob = function (str) {
str = String(str).replace(/[\t\n\f\r ]+/g, '');
if (!b64re.test(str)) { throw new Error("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.") }
// Adding the padding if missing, for semplicity
str += '=='.slice(2 - (str.length & 3));
var bitmap; var result = ''; var r1; var r2; var i = 0;
for (; i < str.length;) {
bitmap = b64.indexOf(str.charAt(i++)) << 18 | b64.indexOf(str.charAt(i++)) << 12 |
(r1 = b64.indexOf(str.charAt(i++))) << 6 | (r2 = b64.indexOf(str.charAt(i++)));
result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255)
: r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255)
: String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
}
return result
};
} else {
// 注意atob只能在全局对象上调用,例如:`const Base64 = {atob};Base64.atob('xxxx')`是错误的用法
realAtob = atob;
}
function b64DecodeUnicode (str) {
return decodeURIComponent(atob(str).split('').map(function (c) {
return decodeURIComponent(realAtob(str).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
}).join(''))
}
......@@ -431,6 +459,10 @@ function onLocaleChange (fn) {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
}
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const interceptors = {
......@@ -1304,7 +1336,9 @@ var en = {
"uni.video.danmu": "Danmu",
"uni.video.volume": "Volume",
"uni.button.feedback.title": "feedback",
"uni.button.feedback.send": "send"
"uni.button.feedback.send": "send",
"uni.chooseLocation.search": "Find Place",
"uni.chooseLocation.cancel": "Cancel"
};
var es = {
......@@ -1337,7 +1371,9 @@ var es = {
"uni.video.danmu": "Danmu",
"uni.video.volume": "Volumen",
"uni.button.feedback.title": "realimentación",
"uni.button.feedback.send": "enviar"
"uni.button.feedback.send": "enviar",
"uni.chooseLocation.search": "Encontrar",
"uni.chooseLocation.cancel": "Cancelar"
};
var fr = {
......@@ -1370,7 +1406,9 @@ var fr = {
"uni.video.danmu": "Danmu",
"uni.video.volume": "Le Volume",
"uni.button.feedback.title": "retour d'information",
"uni.button.feedback.send": "envoyer"
"uni.button.feedback.send": "envoyer",
"uni.chooseLocation.search": "Trouve",
"uni.chooseLocation.cancel": "Annuler"
};
var zhHans = {
......@@ -1403,7 +1441,9 @@ var zhHans = {
"uni.video.danmu": "弹幕",
"uni.video.volume": "音量",
"uni.button.feedback.title": "问题反馈",
"uni.button.feedback.send": "发送"
"uni.button.feedback.send": "发送",
"uni.chooseLocation.search": "搜索地点",
"uni.chooseLocation.cancel": "取消"
};
var zhHant = {
......@@ -1436,7 +1476,9 @@ var zhHant = {
"uni.video.danmu": "彈幕",
"uni.video.volume": "音量",
"uni.button.feedback.title": "問題反饋",
"uni.button.feedback.send": "發送"
"uni.button.feedback.send": "發送",
"uni.chooseLocation.search": "搜索地點",
"uni.chooseLocation.cancel": "取消"
};
const messages = {
......
......@@ -126,10 +126,10 @@ function normalizeLocale(locale, messages) {
}
locale = locale.toLowerCase();
if (locale.indexOf('zh') === 0) {
if (locale.indexOf('-hans') !== -1) {
if (locale.indexOf('-hans') > -1) {
return LOCALE_ZH_HANS;
}
if (locale.indexOf('-hant') !== -1) {
if (locale.indexOf('-hant') > -1) {
return LOCALE_ZH_HANT;
}
if (include(locale, ['-tw', '-hk', '-mo', '-cht'])) {
......@@ -221,11 +221,29 @@ class I18n {
}
}
const ignoreVueI18n = true;
function watchAppLocale(appVm, i18n) {
appVm.$watch(() => appVm.$locale, (newLocale) => {
i18n.setLocale(newLocale);
});
// 需要保证 watch 的触发在组件渲染之前
if (appVm.$watchLocale) {
// vue2
appVm.$watchLocale((newLocale) => {
i18n.setLocale(newLocale);
});
}
else {
appVm.$watch(() => appVm.$locale, (newLocale) => {
i18n.setLocale(newLocale);
});
}
}
function getDefaultLocale() {
if (typeof uni !== 'undefined' && uni.getLocale) {
return uni.getLocale();
}
// 小程序平台,uni 和 uni-i18n 互相引用,导致访问不到 uni,故在 global 上挂了 getLocale
if (typeof global !== 'undefined' && global.getLocale) {
return global.getLocale();
}
return LOCALE_EN;
}
function initVueI18n(locale, messages = {}, fallbackLocale, watcher) {
// 兼容旧版本入参
......@@ -236,9 +254,8 @@ function initVueI18n(locale, messages = {}, fallbackLocale, watcher) {
];
}
if (typeof locale !== 'string') {
locale =
(typeof uni !== 'undefined' && uni.getLocale && uni.getLocale()) ||
LOCALE_EN;
// 因为小程序平台,uni-i18n 和 uni 互相引用,导致此时访问 uni 时,为 undefined
locale = getDefaultLocale();
}
if (typeof fallbackLocale !== 'string') {
fallbackLocale =
......@@ -260,33 +277,32 @@ function initVueI18n(locale, messages = {}, fallbackLocale, watcher) {
};
}
else {
const appVm = getApp().$vm;
watchAppLocale(appVm, i18n);
if (!appVm.$t || !appVm.$i18n || ignoreVueI18n) {
// if (!locale) {
// i18n.setLocale(getDefaultLocale())
// }
/* eslint-disable no-func-assign */
t = function (key, values) {
let isWatchedAppLocale = false;
t = function (key, values) {
const appVm = getApp().$vm;
// 可能$vm还不存在,比如在支付宝小程序中,组件定义较早,在props的default里使用了t()函数(如uni-goods-nav),此时app还未初始化
// options: {
// type: Array,
// default () {
// return [{
// icon: 'shop',
// text: t("uni-goods-nav.options.shop"),
// }, {
// icon: 'cart',
// text: t("uni-goods-nav.options.cart")
// }]
// }
// },
if (appVm) {
// 触发响应式
appVm.$locale;
return i18n.t(key, values);
};
}
else {
/* eslint-disable no-func-assign */
t = function (key, values) {
const $i18n = appVm.$i18n;
const silentTranslationWarn = $i18n.silentTranslationWarn;
$i18n.silentTranslationWarn = true;
const msg = appVm.$t(key, values);
$i18n.silentTranslationWarn = silentTranslationWarn;
if (msg !== key) {
return msg;
if (!isWatchedAppLocale) {
isWatchedAppLocale = true;
watchAppLocale(appVm, i18n);
}
return i18n.t(key, $i18n.locale, values);
};
}
}
return i18n.t(key, values);
};
}
return t(key, values);
};
......@@ -420,6 +436,25 @@ function walkJsonObj(jsonObj, walk) {
return false;
}
function resolveLocale(locales) {
return (locale) => {
if (!locale) {
return locale;
}
locale = normalizeLocale(locale) || locale;
return resolveLocaleChain(locale).find((locale) => locales.indexOf(locale) > -1);
};
}
function resolveLocaleChain(locale) {
const chain = [];
const tokens = locale.split('-');
while (tokens.length) {
chain.push(tokens.join('-'));
tokens.pop();
}
return chain;
}
exports.Formatter = BaseFormatter;
exports.I18n = I18n;
exports.LOCALE_EN = LOCALE_EN;
......@@ -434,3 +469,4 @@ exports.isI18nStr = isI18nStr;
exports.isString = isString;
exports.normalizeLocale = normalizeLocale;
exports.parseI18nJson = parseI18nJson;
exports.resolveLocale = resolveLocale;
......@@ -59,6 +59,8 @@ export declare function isI18nStr(value: string, delimiters: [string, string]):
export declare const isString: (val: unknown) => val is string;
declare type Locale = string;
export declare const LOCALE_EN = "en";
export declare const LOCALE_ES = "es";
......@@ -77,6 +79,8 @@ export declare function normalizeLocale(locale: string, messages?: LocaleMessage
export declare function parseI18nJson(jsonObj: unknown, values: Record<string, string>, delimiters: [string, string]): unknown;
export declare function resolveLocale(locales: Locale[]): (locale: Locale) => string | undefined;
declare type Token = {
type: 'text' | 'named' | 'list' | 'unknown';
value: string;
......
......@@ -122,10 +122,10 @@ function normalizeLocale(locale, messages) {
}
locale = locale.toLowerCase();
if (locale.indexOf('zh') === 0) {
if (locale.indexOf('-hans') !== -1) {
if (locale.indexOf('-hans') > -1) {
return LOCALE_ZH_HANS;
}
if (locale.indexOf('-hant') !== -1) {
if (locale.indexOf('-hant') > -1) {
return LOCALE_ZH_HANT;
}
if (include(locale, ['-tw', '-hk', '-mo', '-cht'])) {
......@@ -217,11 +217,29 @@ class I18n {
}
}
const ignoreVueI18n = true;
function watchAppLocale(appVm, i18n) {
appVm.$watch(() => appVm.$locale, (newLocale) => {
i18n.setLocale(newLocale);
});
// 需要保证 watch 的触发在组件渲染之前
if (appVm.$watchLocale) {
// vue2
appVm.$watchLocale((newLocale) => {
i18n.setLocale(newLocale);
});
}
else {
appVm.$watch(() => appVm.$locale, (newLocale) => {
i18n.setLocale(newLocale);
});
}
}
function getDefaultLocale() {
if (typeof uni !== 'undefined' && uni.getLocale) {
return uni.getLocale();
}
// 小程序平台,uni 和 uni-i18n 互相引用,导致访问不到 uni,故在 global 上挂了 getLocale
if (typeof global !== 'undefined' && global.getLocale) {
return global.getLocale();
}
return LOCALE_EN;
}
function initVueI18n(locale, messages = {}, fallbackLocale, watcher) {
// 兼容旧版本入参
......@@ -232,9 +250,8 @@ function initVueI18n(locale, messages = {}, fallbackLocale, watcher) {
];
}
if (typeof locale !== 'string') {
locale =
(typeof uni !== 'undefined' && uni.getLocale && uni.getLocale()) ||
LOCALE_EN;
// 因为小程序平台,uni-i18n 和 uni 互相引用,导致此时访问 uni 时,为 undefined
locale = getDefaultLocale();
}
if (typeof fallbackLocale !== 'string') {
fallbackLocale =
......@@ -256,33 +273,32 @@ function initVueI18n(locale, messages = {}, fallbackLocale, watcher) {
};
}
else {
const appVm = getApp().$vm;
watchAppLocale(appVm, i18n);
if (!appVm.$t || !appVm.$i18n || ignoreVueI18n) {
// if (!locale) {
// i18n.setLocale(getDefaultLocale())
// }
/* eslint-disable no-func-assign */
t = function (key, values) {
let isWatchedAppLocale = false;
t = function (key, values) {
const appVm = getApp().$vm;
// 可能$vm还不存在,比如在支付宝小程序中,组件定义较早,在props的default里使用了t()函数(如uni-goods-nav),此时app还未初始化
// options: {
// type: Array,
// default () {
// return [{
// icon: 'shop',
// text: t("uni-goods-nav.options.shop"),
// }, {
// icon: 'cart',
// text: t("uni-goods-nav.options.cart")
// }]
// }
// },
if (appVm) {
// 触发响应式
appVm.$locale;
return i18n.t(key, values);
};
}
else {
/* eslint-disable no-func-assign */
t = function (key, values) {
const $i18n = appVm.$i18n;
const silentTranslationWarn = $i18n.silentTranslationWarn;
$i18n.silentTranslationWarn = true;
const msg = appVm.$t(key, values);
$i18n.silentTranslationWarn = silentTranslationWarn;
if (msg !== key) {
return msg;
if (!isWatchedAppLocale) {
isWatchedAppLocale = true;
watchAppLocale(appVm, i18n);
}
return i18n.t(key, $i18n.locale, values);
};
}
}
return i18n.t(key, values);
};
}
return t(key, values);
};
......@@ -416,4 +432,23 @@ function walkJsonObj(jsonObj, walk) {
return false;
}
export { BaseFormatter as Formatter, I18n, LOCALE_EN, LOCALE_ES, LOCALE_FR, LOCALE_ZH_HANS, LOCALE_ZH_HANT, compileI18nJsonStr, hasI18nJson, initVueI18n, isI18nStr, isString, normalizeLocale, parseI18nJson };
function resolveLocale(locales) {
return (locale) => {
if (!locale) {
return locale;
}
locale = normalizeLocale(locale) || locale;
return resolveLocaleChain(locale).find((locale) => locales.indexOf(locale) > -1);
};
}
function resolveLocaleChain(locale) {
const chain = [];
const tokens = locale.split('-');
while (tokens.length) {
chain.push(tokens.join('-'));
tokens.pop();
}
return chain;
}
export { BaseFormatter as Formatter, I18n, LOCALE_EN, LOCALE_ES, LOCALE_FR, LOCALE_ZH_HANS, LOCALE_ZH_HANT, compileI18nJsonStr, hasI18nJson, initVueI18n, isI18nStr, isString, normalizeLocale, parseI18nJson, resolveLocale };
import Vue from 'vue';
import { initVueI18n } from '@dcloudio/uni-i18n';
let realAtob;
const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const b64re = /^(?:[A-Za-z\d+/]{4})*?(?:[A-Za-z\d+/]{2}(?:==)?|[A-Za-z\d+/]{3}=?)?$/;
if (typeof atob !== 'function') {
realAtob = function (str) {
str = String(str).replace(/[\t\n\f\r ]+/g, '');
if (!b64re.test(str)) { throw new Error("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.") }
// Adding the padding if missing, for semplicity
str += '=='.slice(2 - (str.length & 3));
var bitmap; var result = ''; var r1; var r2; var i = 0;
for (; i < str.length;) {
bitmap = b64.indexOf(str.charAt(i++)) << 18 | b64.indexOf(str.charAt(i++)) << 12 |
(r1 = b64.indexOf(str.charAt(i++))) << 6 | (r2 = b64.indexOf(str.charAt(i++)));
result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255)
: r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255)
: String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
}
return result
};
} else {
// 注意atob只能在全局对象上调用,例如:`const Base64 = {atob};Base64.atob('xxxx')`是错误的用法
realAtob = atob;
}
function b64DecodeUnicode (str) {
return decodeURIComponent(atob(str).split('').map(function (c) {
return decodeURIComponent(realAtob(str).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
}).join(''))
}
......@@ -431,6 +459,10 @@ function onLocaleChange (fn) {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
}
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const interceptors = {
......
......@@ -473,7 +473,8 @@ const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interce
else if (isPlainObject(method)) {
removeInterceptorHook(globalInterceptors, method);
}
}, RemoveInterceptorProtocol);
}, RemoveInterceptorProtocol);
const interceptors = {};
const API_ON = '$on';
const OnProtocol = [
......@@ -753,7 +754,10 @@ const onLocaleChange = (fn) => {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
};
};
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const baseApis = {
$on,
......@@ -761,6 +765,7 @@ const baseApis = {
$once,
$emit,
upx2px,
interceptors,
addInterceptor,
removeInterceptor,
onAppLaunch,
......
......@@ -55,6 +55,7 @@ const ON_TAB_ITEM_TAP = 'onTabItemTap';
const ON_REACH_BOTTOM = 'onReachBottom';
const ON_PULL_DOWN_REFRESH = 'onPullDownRefresh';
const ON_ADD_TO_FAVORITES = 'onAddToFavorites';
const ON_SHARE_APP_MESSAGE = 'onShareAppMessage';
class EventChannel {
constructor(id, events) {
......@@ -557,6 +558,9 @@ const HOOKS = [
ON_PAGE_NOT_FOUND,
ON_UNHANDLE_REJECTION,
];
{
HOOKS.push(ON_SHARE_APP_MESSAGE);
}
function parseApp(instance, parseAppOptions) {
const internalInstance = instance.$;
const appOptions = {
......
import Vue from 'vue';
import { initVueI18n } from '@dcloudio/uni-i18n';
let realAtob;
const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const b64re = /^(?:[A-Za-z\d+/]{4})*?(?:[A-Za-z\d+/]{2}(?:==)?|[A-Za-z\d+/]{3}=?)?$/;
if (typeof atob !== 'function') {
realAtob = function (str) {
str = String(str).replace(/[\t\n\f\r ]+/g, '');
if (!b64re.test(str)) { throw new Error("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.") }
// Adding the padding if missing, for semplicity
str += '=='.slice(2 - (str.length & 3));
var bitmap; var result = ''; var r1; var r2; var i = 0;
for (; i < str.length;) {
bitmap = b64.indexOf(str.charAt(i++)) << 18 | b64.indexOf(str.charAt(i++)) << 12 |
(r1 = b64.indexOf(str.charAt(i++))) << 6 | (r2 = b64.indexOf(str.charAt(i++)));
result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255)
: r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255)
: String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
}
return result
};
} else {
// 注意atob只能在全局对象上调用,例如:`const Base64 = {atob};Base64.atob('xxxx')`是错误的用法
realAtob = atob;
}
function b64DecodeUnicode (str) {
return decodeURIComponent(atob(str).split('').map(function (c) {
return decodeURIComponent(realAtob(str).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
}).join(''))
}
......@@ -431,6 +459,10 @@ function onLocaleChange (fn) {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
}
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const interceptors = {
......
......@@ -473,7 +473,8 @@ const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interce
else if (isPlainObject(method)) {
removeInterceptorHook(globalInterceptors, method);
}
}, RemoveInterceptorProtocol);
}, RemoveInterceptorProtocol);
const interceptors = {};
const API_ON = '$on';
const OnProtocol = [
......@@ -753,7 +754,10 @@ const onLocaleChange = (fn) => {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
};
};
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const baseApis = {
$on,
......@@ -761,6 +765,7 @@ const baseApis = {
$once,
$emit,
upx2px,
interceptors,
addInterceptor,
removeInterceptor,
onAppLaunch,
......
import Vue from 'vue';
import { initVueI18n } from '@dcloudio/uni-i18n';
let realAtob;
const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const b64re = /^(?:[A-Za-z\d+/]{4})*?(?:[A-Za-z\d+/]{2}(?:==)?|[A-Za-z\d+/]{3}=?)?$/;
if (typeof atob !== 'function') {
realAtob = function (str) {
str = String(str).replace(/[\t\n\f\r ]+/g, '');
if (!b64re.test(str)) { throw new Error("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.") }
// Adding the padding if missing, for semplicity
str += '=='.slice(2 - (str.length & 3));
var bitmap; var result = ''; var r1; var r2; var i = 0;
for (; i < str.length;) {
bitmap = b64.indexOf(str.charAt(i++)) << 18 | b64.indexOf(str.charAt(i++)) << 12 |
(r1 = b64.indexOf(str.charAt(i++))) << 6 | (r2 = b64.indexOf(str.charAt(i++)));
result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255)
: r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255)
: String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
}
return result
};
} else {
// 注意atob只能在全局对象上调用,例如:`const Base64 = {atob};Base64.atob('xxxx')`是错误的用法
realAtob = atob;
}
function b64DecodeUnicode (str) {
return decodeURIComponent(atob(str).split('').map(function (c) {
return decodeURIComponent(realAtob(str).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
}).join(''))
}
......@@ -431,6 +459,10 @@ function onLocaleChange (fn) {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
}
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const interceptors = {
......
......@@ -473,7 +473,8 @@ const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interce
else if (isPlainObject(method)) {
removeInterceptorHook(globalInterceptors, method);
}
}, RemoveInterceptorProtocol);
}, RemoveInterceptorProtocol);
const interceptors = {};
const API_ON = '$on';
const OnProtocol = [
......@@ -753,7 +754,10 @@ const onLocaleChange = (fn) => {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
};
};
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const baseApis = {
$on,
......@@ -761,6 +765,7 @@ const baseApis = {
$once,
$emit,
upx2px,
interceptors,
addInterceptor,
removeInterceptor,
onAppLaunch,
......
import Vue from 'vue';
import { initVueI18n } from '@dcloudio/uni-i18n';
let realAtob;
const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const b64re = /^(?:[A-Za-z\d+/]{4})*?(?:[A-Za-z\d+/]{2}(?:==)?|[A-Za-z\d+/]{3}=?)?$/;
if (typeof atob !== 'function') {
realAtob = function (str) {
str = String(str).replace(/[\t\n\f\r ]+/g, '');
if (!b64re.test(str)) { throw new Error("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.") }
// Adding the padding if missing, for semplicity
str += '=='.slice(2 - (str.length & 3));
var bitmap; var result = ''; var r1; var r2; var i = 0;
for (; i < str.length;) {
bitmap = b64.indexOf(str.charAt(i++)) << 18 | b64.indexOf(str.charAt(i++)) << 12 |
(r1 = b64.indexOf(str.charAt(i++))) << 6 | (r2 = b64.indexOf(str.charAt(i++)));
result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255)
: r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255)
: String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
}
return result
};
} else {
// 注意atob只能在全局对象上调用,例如:`const Base64 = {atob};Base64.atob('xxxx')`是错误的用法
realAtob = atob;
}
function b64DecodeUnicode (str) {
return decodeURIComponent(atob(str).split('').map(function (c) {
return decodeURIComponent(realAtob(str).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
}).join(''))
}
......@@ -431,6 +459,10 @@ function onLocaleChange (fn) {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
}
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const interceptors = {
......
......@@ -473,7 +473,8 @@ const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interce
else if (isPlainObject(method)) {
removeInterceptorHook(globalInterceptors, method);
}
}, RemoveInterceptorProtocol);
}, RemoveInterceptorProtocol);
const interceptors = {};
const API_ON = '$on';
const OnProtocol = [
......@@ -753,7 +754,10 @@ const onLocaleChange = (fn) => {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
};
};
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const baseApis = {
$on,
......@@ -761,6 +765,7 @@ const baseApis = {
$once,
$emit,
upx2px,
interceptors,
addInterceptor,
removeInterceptor,
onAppLaunch,
......
import Vue from 'vue';
import { initVueI18n } from '@dcloudio/uni-i18n';
let realAtob;
const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const b64re = /^(?:[A-Za-z\d+/]{4})*?(?:[A-Za-z\d+/]{2}(?:==)?|[A-Za-z\d+/]{3}=?)?$/;
if (typeof atob !== 'function') {
realAtob = function (str) {
str = String(str).replace(/[\t\n\f\r ]+/g, '');
if (!b64re.test(str)) { throw new Error("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.") }
// Adding the padding if missing, for semplicity
str += '=='.slice(2 - (str.length & 3));
var bitmap; var result = ''; var r1; var r2; var i = 0;
for (; i < str.length;) {
bitmap = b64.indexOf(str.charAt(i++)) << 18 | b64.indexOf(str.charAt(i++)) << 12 |
(r1 = b64.indexOf(str.charAt(i++))) << 6 | (r2 = b64.indexOf(str.charAt(i++)));
result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255)
: r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255)
: String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
}
return result
};
} else {
// 注意atob只能在全局对象上调用,例如:`const Base64 = {atob};Base64.atob('xxxx')`是错误的用法
realAtob = atob;
}
function b64DecodeUnicode (str) {
return decodeURIComponent(atob(str).split('').map(function (c) {
return decodeURIComponent(realAtob(str).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
}).join(''))
}
......@@ -431,6 +459,10 @@ function onLocaleChange (fn) {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
}
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const interceptors = {
......
......@@ -473,7 +473,8 @@ const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interce
else if (isPlainObject(method)) {
removeInterceptorHook(globalInterceptors, method);
}
}, RemoveInterceptorProtocol);
}, RemoveInterceptorProtocol);
const interceptors = {};
const API_ON = '$on';
const OnProtocol = [
......@@ -753,7 +754,10 @@ const onLocaleChange = (fn) => {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
};
};
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const baseApis = {
$on,
......@@ -761,6 +765,7 @@ const baseApis = {
$once,
$emit,
upx2px,
interceptors,
addInterceptor,
removeInterceptor,
onAppLaunch,
......
import Vue from 'vue';
import { initVueI18n } from '@dcloudio/uni-i18n';
let realAtob;
const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const b64re = /^(?:[A-Za-z\d+/]{4})*?(?:[A-Za-z\d+/]{2}(?:==)?|[A-Za-z\d+/]{3}=?)?$/;
if (typeof atob !== 'function') {
realAtob = function (str) {
str = String(str).replace(/[\t\n\f\r ]+/g, '');
if (!b64re.test(str)) { throw new Error("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.") }
// Adding the padding if missing, for semplicity
str += '=='.slice(2 - (str.length & 3));
var bitmap; var result = ''; var r1; var r2; var i = 0;
for (; i < str.length;) {
bitmap = b64.indexOf(str.charAt(i++)) << 18 | b64.indexOf(str.charAt(i++)) << 12 |
(r1 = b64.indexOf(str.charAt(i++))) << 6 | (r2 = b64.indexOf(str.charAt(i++)));
result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255)
: r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255)
: String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
}
return result
};
} else {
// 注意atob只能在全局对象上调用,例如:`const Base64 = {atob};Base64.atob('xxxx')`是错误的用法
realAtob = atob;
}
function b64DecodeUnicode (str) {
return decodeURIComponent(atob(str).split('').map(function (c) {
return decodeURIComponent(realAtob(str).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
}).join(''))
}
......@@ -431,6 +459,10 @@ function onLocaleChange (fn) {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
}
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const interceptors = {
......
......@@ -437,7 +437,8 @@ const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interce
else if (isPlainObject(method)) {
removeInterceptorHook(globalInterceptors, method);
}
}, RemoveInterceptorProtocol);
}, RemoveInterceptorProtocol);
const interceptors = {};
const API_ON = '$on';
const OnProtocol = [
......@@ -717,7 +718,10 @@ const onLocaleChange = (fn) => {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
};
};
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const baseApis = {
$on,
......@@ -725,6 +729,7 @@ const baseApis = {
$once,
$emit,
upx2px,
interceptors,
addInterceptor,
removeInterceptor,
onAppLaunch,
......
import Vue from 'vue';
import { initVueI18n } from '@dcloudio/uni-i18n';
let realAtob;
const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const b64re = /^(?:[A-Za-z\d+/]{4})*?(?:[A-Za-z\d+/]{2}(?:==)?|[A-Za-z\d+/]{3}=?)?$/;
if (typeof atob !== 'function') {
realAtob = function (str) {
str = String(str).replace(/[\t\n\f\r ]+/g, '');
if (!b64re.test(str)) { throw new Error("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.") }
// Adding the padding if missing, for semplicity
str += '=='.slice(2 - (str.length & 3));
var bitmap; var result = ''; var r1; var r2; var i = 0;
for (; i < str.length;) {
bitmap = b64.indexOf(str.charAt(i++)) << 18 | b64.indexOf(str.charAt(i++)) << 12 |
(r1 = b64.indexOf(str.charAt(i++))) << 6 | (r2 = b64.indexOf(str.charAt(i++)));
result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255)
: r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255)
: String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
}
return result
};
} else {
// 注意atob只能在全局对象上调用,例如:`const Base64 = {atob};Base64.atob('xxxx')`是错误的用法
realAtob = atob;
}
function b64DecodeUnicode (str) {
return decodeURIComponent(atob(str).split('').map(function (c) {
return decodeURIComponent(realAtob(str).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
}).join(''))
}
......@@ -431,6 +459,10 @@ function onLocaleChange (fn) {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
}
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const interceptors = {
......
......@@ -473,7 +473,8 @@ const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interce
else if (isPlainObject(method)) {
removeInterceptorHook(globalInterceptors, method);
}
}, RemoveInterceptorProtocol);
}, RemoveInterceptorProtocol);
const interceptors = {};
const API_ON = '$on';
const OnProtocol = [
......@@ -753,7 +754,10 @@ const onLocaleChange = (fn) => {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn);
}
};
};
if (typeof global !== 'undefined') {
global.getLocale = getLocale;
}
const baseApis = {
$on,
......@@ -761,6 +765,7 @@ const baseApis = {
$once,
$emit,
upx2px,
interceptors,
addInterceptor,
removeInterceptor,
onAppLaunch,
......
......@@ -427,16 +427,10 @@ module.exports = function (pagesJson, manifestJson, loader) {
const networkTimeoutConfig = getNetworkTimeout(manifestJson)
let qqMapKey = 'XVXBZ-NDMC4-JOGUS-XGIEE-QVHDZ-AMFV2'
const sdkConfigs = h5.sdkConfigs || {}
if (
sdkConfigs.maps &&
sdkConfigs.maps.qqmap &&
sdkConfigs.maps.qqmap.key
) {
qqMapKey = sdkConfigs.maps.qqmap.key
}
const qqMapKey = sdkConfigs.maps && sdkConfigs.maps.qqmap && sdkConfigs.maps.qqmap.key
const googleMapKey = sdkConfigs.maps && sdkConfigs.maps.google && sdkConfigs.maps.google.key
let locale = manifestJson.locale
locale = locale && locale.toUpperCase() !== 'AUTO' ? locale : ''
......@@ -456,6 +450,7 @@ global.__uniConfig.debug = ${manifestJson.debug === true};
global.__uniConfig.networkTimeout = ${JSON.stringify(networkTimeoutConfig)};
global.__uniConfig.sdkConfigs = ${JSON.stringify(sdkConfigs)};
global.__uniConfig.qqMapKey = ${JSON.stringify(qqMapKey)};
global.__uniConfig.googleMapKey = ${JSON.stringify(googleMapKey)};
global.__uniConfig.locale = ${JSON.stringify(locale)};
global.__uniConfig.fallbackLocale = ${JSON.stringify(manifestJson.fallbackLocale)};
global.__uniConfig.locales = locales.keys().reduce((res,key)=>{const locale=key.replace(/\\.\\/(uni-app.)?(.*).json/,'$2');const messages = locales(key);Object.assign(res[locale]||(res[locale]={}),messages.common||messages);return res},{});
......
......@@ -86,7 +86,8 @@ module.exports = function (pagesJson, manifestJson) {
delete project.usingComponents
delete project.plugins
delete project.useDynamicPlugins
!('component2' in project) && (project.component2 = true)
!('component2' in project) && (project.component2 = true)
!('enableAppxNg' in project) && (project.enableAppxNg = true)
return [{
name: 'app',
......
......@@ -28,5 +28,7 @@
"uni.video.danmu": "Danmu",
"uni.video.volume": "Volume",
"uni.button.feedback.title": "feedback",
"uni.button.feedback.send": "send"
"uni.button.feedback.send": "send",
"uni.chooseLocation.search": "Find Place",
"uni.chooseLocation.cancel": "Cancel"
}
......@@ -28,5 +28,7 @@
"uni.video.danmu": "Danmu",
"uni.video.volume": "Volumen",
"uni.button.feedback.title": "realimentación",
"uni.button.feedback.send": "enviar"
"uni.button.feedback.send": "enviar",
"uni.chooseLocation.search": "Encontrar",
"uni.chooseLocation.cancel": "Cancelar"
}
......@@ -28,5 +28,7 @@
"uni.video.danmu": "Danmu",
"uni.video.volume": "Le Volume",
"uni.button.feedback.title": "retour d'information",
"uni.button.feedback.send": "envoyer"
"uni.button.feedback.send": "envoyer",
"uni.chooseLocation.search": "Trouve",
"uni.chooseLocation.cancel": "Annuler"
}
......@@ -28,5 +28,7 @@
"uni.video.danmu": "弹幕",
"uni.video.volume": "音量",
"uni.button.feedback.title": "问题反馈",
"uni.button.feedback.send": "发送"
"uni.button.feedback.send": "发送",
"uni.chooseLocation.search": "搜索地点",
"uni.chooseLocation.cancel": "取消"
}
......@@ -28,5 +28,7 @@
"uni.video.danmu": "彈幕",
"uni.video.volume": "音量",
"uni.button.feedback.title": "問題反饋",
"uni.button.feedback.send": "發送"
"uni.button.feedback.send": "發送",
"uni.chooseLocation.search": "搜索地點",
"uni.chooseLocation.cancel": "取消"
}
......@@ -30,4 +30,8 @@ export function onLocaleChange (fn) {
if (onLocaleChangeCallbacks.indexOf(fn) === -1) {
onLocaleChangeCallbacks.push(fn)
}
}
if (typeof global !== 'undefined') {
global.getLocale = getLocale
}
......@@ -21,7 +21,7 @@
ref="refresherinner"
:style="{
'background-color': refresherBackground,
height: refresherThreshold + 'px',
height: refresherHeight + 'px',
}"
class="uni-scroll-view-refresher"
>
......@@ -158,13 +158,13 @@ export default {
},
data () {
return {
lastScrollTop: this.scrollTopNumber || 0,
lastScrollLeft: this.scrollLeftNumber || 0,
lastScrollTop: this.scrollTopNumber,
lastScrollLeft: this.scrollLeftNumber,
lastScrollToUpperTime: 0,
lastScrollToLowerTime: 0,
refresherHeight: 0,
refreshRotate: 0,
refreshState: 'restore'
refreshState: ''
}
},
computed: {
......@@ -225,6 +225,7 @@ export default {
var x = event.touches[0].pageX
var y = event.touches[0].pageY
var main = self.$refs.main
if (Math.abs(x - touchStart.x) > Math.abs(y - touchStart.y)) {
// 横向滑动
if (self.scrollX) {
......@@ -245,13 +246,10 @@ export default {
} else {
// 纵向滑动
if (self.scrollY) {
if (main.scrollTop === 0 && y >= touchStart.y) {
if (main.scrollTop === 0 && y > touchStart.y) {
needStop = false
// 刷新时,阻止页面滚动
if (self.refresherEnabled && event.cancelable !== false) {
if (self.refreshState !== 'pulling' && self.refreshState !== 'refreshing') {
self.refreshState = 'pulling'
}
event.preventDefault()
}
} else if (
......@@ -267,71 +265,42 @@ export default {
needStop = false
}
}
if (needStop) {
event.stopPropagation()
}
// 刷新中
if (self.refresherEnabled && self.refreshState === 'refreshing') {
if (event.cancelable !== false) {
event.preventDefault()
}
// this.refresherThreshold
let dy = y - touchStart.y + self.refresherThreshold
if (dy <= 0) {
dy = 0
// 刷新时,阻止页面滚动
}
if (dy > self.refresherThreshold) {
self.refresherHeight = Math.floor(dy * 0.16) + self.refresherThreshold
} else {
self.refresherHeight = dy
}
const transform = 'translateY(' + self.refresherHeight + 'px) translateZ(0)'
self.$refs.content.style.transform = transform
self.$refs.content.style.webkitTransform = transform
// return
if (main.scrollTop === 0 && event.touches.length === 1) {
// 如果容器滑动到达顶端,则进入下拉状态
self.refreshState = 'pulling'
}
let _dy = 0
if (self.refresherEnabled && self.refreshState === 'pulling') {
if (event.cancelable !== false) {
event.preventDefault()
}
const dy = y - touchStart.y
if (self.toUpperNumber === 0) {
self.toUpperNumber = y
}
if (!self.beforeRefreshing) {
_dy = y - self.toUpperNumber
self.refresherHeight = y - self.toUpperNumber
// 之前为刷新状态则不再触发pulling
if (_dy > 0) {
if (self.refresherHeight > 0) {
self.triggerAbort = true
self.$trigger('refresherpulling', event, {
deltaY: dy
})
}
} else {
_dy = dy + self.refresherThreshold
self.refresherHeight = dy + self.refresherThreshold
// 如果之前在刷新状态,则不触发刷新中断
self.triggerAbort = false
}
self.refresherHeight = Math.floor(_dy * 0.16)
if (self.refresherHeight <= 0) {
self.refresherHeight = 0
}
const transform = 'translateY(' + self.refresherHeight + 'px) translateZ(0)'
self.$refs.content.style.transform = transform
self.$refs.content.style.webkitTransform = transform
const route = self.refresherHeight / self.refresherThreshold
self.refreshRotate = (route > 1 ? 1 : route) * 360
}
}
this.__handleTouchStart = function (event) {
self.$refs.content.style.transition = ''
self.$refs.content.style.webkitTransition = ''
if (event.touches.length === 1) {
disableScrollBounce({
disable: true
......@@ -347,21 +316,8 @@ export default {
disableScrollBounce({
disable: false
})
if (self.refreshState === 'refreshing' && self.refresherHeight < self.refresherThreshold) {
self._setRefreshState('restore')
return
}
if (self.refresherHeight >= self.refresherThreshold) {
if (self.refreshState !== 'refreshing') {
self._setRefreshState('refreshing')
} else {
const transform = 'translateY(' + self.refresherThreshold + 'px) translateZ(0)'
self.$refs.content.style.transition = 'transform .3s ease-out'
self.$refs.content.style.webkitTransition =
'-webkit-transform .3s ease-out'
self.$refs.content.style.transform = transform
self.$refs.content.style.webkitTransform = transform
}
self._setRefreshState('refreshing')
} else {
self._setRefreshState('refresherabort')
}
......@@ -677,13 +633,6 @@ export default {
}
break
}
const transform = 'translateY(' + this.refresherHeight + 'px) translateZ(0)'
this.$refs.content.style.transition = 'transform .3s ease-out'
this.$refs.content.style.webkitTransition =
'-webkit-transform .3s ease-out'
this.$refs.content.style.transform = transform
this.$refs.content.style.webkitTransform = transform
this.refreshState = state
},
getScrollPosition () {
......@@ -718,16 +667,12 @@ uni-scroll-view[hidden] {
}
.uni-scroll-view-content {
position: relative;
width: 100%;
height: 100%;
}
.uni-scroll-view-refresher {
position: absolute;
left: 0;
right: 0;
transform: translateY(-100%);
position: relative;
overflow: hidden;
}
......
......@@ -20,9 +20,10 @@ export function setTabBarItem ({
text,
iconPath,
selectedIconPath,
pagePath
pagePath,
visible
}) {
tabBar.setTabBarItem(index, text, iconPath, selectedIconPath)
tabBar.setTabBarItem(index, text, iconPath, selectedIconPath, visible)
const route = pagePath && __uniRoutes.find(({ path }) => path === pagePath)
if (route) {
const meta = route.meta
......
......@@ -49,7 +49,7 @@ function setTabBarBadge (type, index, text) {
/**
* 动态设置 tabBar 某一项的内容
*/
function setTabBarItem (index, text, iconPath, selectedIconPath) {
function setTabBarItem (index, text, iconPath, selectedIconPath, visible) {
const item = {
index
}
......@@ -62,7 +62,17 @@ function setTabBarItem (index, text, iconPath, selectedIconPath) {
if (selectedIconPath) {
item.selectedIconPath = getRealPath(selectedIconPath)
}
tabBar && tabBar.setTabBarItem(item)
if (visible !== undefined) {
item.visible = config.list[index].visible = visible
delete item.index
const tabbarItems = config.list.map(item => ({ visible: item.visible }))
tabbarItems[index] = item
tabBar && tabBar.setTabBarItems({ list: tabbarItems })
} else {
tabBar && tabBar.setTabBarItem(item)
}
}
/**
* 动态设置 tabBar 的整体样式
......
......@@ -12,7 +12,7 @@
class="uni-tabbar-border"
/>
<div
v-for="(item,index) in list"
v-for="(item,index) in visibleList"
:key="item.isMidButton ? index : item.pagePath"
:style="item.isMidButton ? {flex:'0 0 ' + item.width,position:'relative'} : {}"
class="uni-tabbar__item"
......@@ -36,14 +36,14 @@
:style="{height:height}"
>
<div
v-if="item.iconPath || item.isMidButton"
v-if="getIconPath(item,index) || item.iconPath || item.isMidButton"
:class="{'uni-tabbar__icon__diff':!item.text}"
class="uni-tabbar__icon"
:style="{width: iconWidth,height:iconWidth}"
>
<img
v-if="!item.isMidButton"
:src="_getRealPath(selectedIndex===index?item.selectedIconPath:item.iconPath)"
:src="_getRealPath(getIconPath(item,index))"
>
<div
v-if="item.redDot"
......@@ -287,7 +287,8 @@ export default {
},
data () {
return {
selectedIndex: 0
selectedIndex: 0,
visibleList: []
}
},
computed: {
......@@ -319,25 +320,45 @@ export default {
watch: {
$route: {
immediate: true,
handler (to) {
if (to.meta.isTabBar) {
this.__path__ = to.path
const index = this.list.findIndex(item => to.meta.pagePath === item.pagePath)
if (index > -1) {
this.selectedIndex = index
}
}
handler () {
// 只在此做一次 visibleList 的初始化
if (!this.visibleList.length) this._initVisibleList()
this.setSelectedIndex()
}
},
list: {
deep: true,
handler () {
this._initVisibleList()
this.setSelectedIndex()
}
}
},
created () {
this._initMidButton()
this.list.forEach(item => {
if (item.visible === undefined) {
this.$set(item, 'visible', true)
}
})
},
beforeCreate () {
this.__path__ = this.$route.path
},
methods: {
_getRealPath (filePath) {
getIconPath (item, index) {
return (this.selectedIndex === index ? item.selectedIconPath || item.iconPath : item.iconPath) || ''
},
setSelectedIndex () {
if (this.$route.meta.isTabBar) {
this.__path__ = this.$route.path
const index = this.visibleList.findIndex(item => this.$route.meta.pagePath === item.pagePath)
this.selectedIndex = index
}
},
_initVisibleList () {
this.visibleList = this._initMidButton(this.list.filter(item => item.visible !== false))
},
_getRealPath (filePath = '') {
const SCHEME_RE = /^([a-z-]+:)?\/\//i
const DATA_RE = /^data:.*,.*/
if (!(SCHEME_RE.test(filePath) || DATA_RE.test(filePath)) && filePath.indexOf('/') !== 0) {
......@@ -375,8 +396,8 @@ export default {
UniServiceJSBridge.emit('onTabItemTap', detail)
}
},
_initMidButton () {
const listLength = this.list.length
_initMidButton (list) {
const listLength = list.length
// 偶数则添加midButton
if (listLength % 2 === 0 && isPlainObject(this.midButton)) {
// 给midButton赋值默认值
......@@ -388,8 +409,9 @@ export default {
for (const key in DefaultMidButton) {
this.midButton[key] = this.midButton[key] || DefaultMidButton[key]
}
this.list.splice(~~(listLength / 2), 0, Object.assign({}, this.midButton, { isMidButton: true }))
list.splice(~~(listLength / 2), 0, Object.assign({}, this.midButton, { isMidButton: true }))
}
return list
},
_uniTabbarBdStyle (item) {
return Object.assign({}, {
......
<template>
<div class="uni-system-choose-location">
<v-uni-map
v-if="latitude"
:latitude="latitude"
:longitude="longitude"
class="map"
show-location
@regionchange="_regionchange"
:libraries="['places']"
@updated="getList"
@regionchange="onRegionChange"
>
<div class="map-location" />
<div
class="map-location"
:style="locationStyle"
/>
<div
class="map-move"
@click="_moveToLocation"
@click="moveToLocation"
>
<i>&#xec32;</i>
</div>
......@@ -19,14 +23,14 @@
<div class="nav">
<div
class="nav-btn back"
@click="_back"
@click="back"
>
<i class="uni-btn-icon">&#xe650;</i>
</div>
<div
class="nav-btn confirm"
:class="{ disable: !selected }"
@click="_choose"
@click="choose"
>
<i class="uni-btn-icon">&#xe651;</i>
</div>
......@@ -36,9 +40,9 @@
<v-uni-input
v-model="keyword"
class="search-input"
placeholder="搜索地点"
:placeholder="$$t('uni.chooseLocation.search')"
@focus="searching = true"
@input="_input"
@input="input"
/>
<div
v-if="searching"
......@@ -48,13 +52,13 @@
keyword = '';
"
>
取消
{{ $$t("uni.chooseLocation.cancel") }}
</div>
</div>
<v-uni-scroll-view
scroll-y
class="list"
@scrolltolower="_scrolltolower"
@scrolltolower="loadMore"
>
<div
v-if="loading"
......@@ -90,8 +94,15 @@ import {
} from 'uni-shared'
import {
getJSONP
} from 'uni-platform/helpers/get-jsonp'
const key = __uniConfig.qqMapKey
} from '../../../helpers/get-jsonp'
import {
i18nMixin
} from 'uni-core/helpers/i18n'
import {
ICON_PATH_TARGET,
MapType,
getMapInfo
} from '../../../helpers/location'
export default {
name: 'SystemChooseLocation',
......@@ -100,24 +111,32 @@ export default {
if (distance > 100) {
return `${distance > 1000 ? (distance / 1000).toFixed(1) + 'k' : distance.toFixed(0)}m | `
} else if (distance > 0) {
return '100m内 | '
return '<100m | '
} else {
return ''
}
}
},
mixins: [i18nMixin],
data () {
const {
latitude,
longitude
} = this.$route.query
return {
latitude: 0,
longitude: 0,
pageSize: 15,
latitude: latitude,
longitude: longitude,
pageSize: 20,
pageIndex: 1,
hasNextPage: true,
nextPage: null,
selectedIndex: -1,
list: [],
keyword: '',
searching: false,
loading: true,
adcode: ''
adcode: '',
locationStyle: `background-image: url("${ICON_PATH_TARGET}")`
}
},
computed: {
......@@ -129,50 +148,52 @@ export default {
}
},
created () {
this._moveToLocation()
this._search = debounce(() => {
this._reset()
if (!this.latitude || !this.longitude) {
this.moveToLocation()
}
this.search = debounce(() => {
this.reset()
if (this.keyword) {
this._getList()
this.getList()
}
}, 1000)
this.$watch('searching', val => {
this._reset()
this.reset()
if (!val) {
this._getList()
this.getList()
}
})
},
methods: {
_choose () {
choose () {
if (this.selected) {
UniViewJSBridge.publishHandler('onChooseLocation', Object.assign({}, this.selected))
getApp().$router.back()
}
},
_back () {
back () {
UniViewJSBridge.publishHandler('onChooseLocation', null)
getApp().$router.back()
},
_moveToLocation () {
moveToLocation () {
uni.getLocation({
type: 'gcj02',
success: this._move.bind(this),
success: this.move.bind(this),
fail: () => {
this._move({
latitude: 39.90960456049752,
longitude: 116.3972282409668
})
// this.move({
// latitude: 39.90960456049752,
// longitude: 116.3972282409668
// })
}
})
},
_regionchange ({ detail: { centerLocation } }) {
onRegionChange ({ detail: { centerLocation } }) {
if (centerLocation) {
// TODO 图钉 icon 动画
this._move(centerLocation)
this.move(centerLocation)
}
},
_pushData (array) {
pushData (array) {
array.forEach(item => {
this.list.push({
name: item.title,
......@@ -183,48 +204,92 @@ export default {
})
})
},
_getList () {
getList () {
this.loading = true
const url = this.searching ? `https://apis.map.qq.com/ws/place/v1/search?output=jsonp&key=${key}&boundary=${this.boundary}&keyword=${this.keyword}&page_size=${this.pageSize}&page_index=${this.pageIndex}` : `https://apis.map.qq.com/ws/geocoder/v1/?output=jsonp&key=${key}&location=${this.latitude},${this.longitude}&get_poi=1&poi_options=page_size=${this.pageSize};page_index=${this.pageIndex}`
// TODO 列表加载失败提示
getJSONP(url, {
callback: 'callback'
}, (res) => {
this.loading = false
if (this.searching && 'data' in res && res.data.length) {
this._pushData(res.data)
} else if ('result' in res) {
const result = res.result
this.adcode = result.ad_info ? result.ad_info.adcode : ''
if (result.pois) {
this._pushData(result.pois)
}
const mapInfo = getMapInfo()
if (mapInfo.type === MapType.GOOGLE) {
if (this.pageIndex > 1 && this.nextPage) {
this.nextPage()
return
}
}, () => {
this.loading = false
})
const service = new window.google.maps.places.PlacesService(document.createElement('div'))
service[this.searching ? 'textSearch' : 'nearbySearch']({
location: {
lat: this.latitude,
lng: this.longitude
},
query: this.keyword,
radius: 5000
}, (results, state, page) => {
this.loading = false
if (results && results.length) {
results.forEach((item) => {
this.list.push({
name: item.name || '',
address: item.vicinity || item.formatted_address || '',
distance: 0,
latitude: item.geometry.location.lat(),
longitude: item.geometry.location.lng()
})
})
}
if (page) {
if (!page.hasNextPage) {
this.hasNextPage = false
} else {
this.nextPage = () => {
page.nextPage()
}
}
}
})
} else if (mapInfo.type === MapType.QQ) {
const url = this.searching ? `https://apis.map.qq.com/ws/place/v1/search?output=jsonp&key=${mapInfo.key}&boundary=${this.boundary}&keyword=${this.keyword}&page_size=${this.pageSize}&page_index=${this.pageIndex}` : `https://apis.map.qq.com/ws/geocoder/v1/?output=jsonp&key=${mapInfo.key}&location=${this.latitude},${this.longitude}&get_poi=1&poi_options=page_size=${this.pageSize};page_index=${this.pageIndex}`
// TODO 列表加载失败提示
getJSONP(url, {
callback: 'callback'
}, (res) => {
this.loading = false
if (this.searching && 'data' in res && res.data.length) {
this.pushData(res.data)
} else if ('result' in res) {
const result = res.result
this.adcode = result.ad_info ? result.ad_info.adcode : ''
if (result.pois) {
this.pushData(result.pois)
}
if (this.list.length === this.pageSize * this.pageIndex) {
this.hasNextPage = false
}
}
}, () => {
this.loading = false
})
}
},
_scrolltolower () {
if (!this.loading && this.list.length === this.pageSize * this.pageIndex) {
loadMore () {
if (!this.loading && this.hasNextPage) {
this.pageIndex++
this._getList()
this.getList()
}
},
_reset () {
reset () {
this.selectedIndex = -1
this.pageIndex = 1
this.hasNextPage = true
this.nextPage = null
this.list = []
},
_move ({ latitude, longitude }) {
move ({ latitude, longitude }) {
this.latitude = latitude
this.longitude = longitude
if (!this.searching) {
this._reset()
this._getList()
this.reset()
this.getList()
}
},
_input () {
this._search()
input () {
this.search()
}
}
}
......@@ -264,7 +329,6 @@ export default {
height: 52px;
margin-left: -16px;
cursor: pointer;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAACcCAMAAAC3Fl5oAAAB3VBMVEVMaXH/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/EhL/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/Dw//AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/GRn/NTX/Dw//Fhb/AAD/AAD/AAD/GRn/GRn/Y2P/AAD/AAD/ExP/Ghr/AAD/AAD/MzP/GRn/AAD/Hh7/AAD/RUX/AAD/AAD/AAD/AAD/AAD/AAD/Dg7/AAD/HR3/Dw//FRX/SUn/AAD/////kJD/DQ3/Zmb/+/v/wMD/mJj/6en/vb3/1NT//Pz/ODj/+fn/3Nz/nJz/j4//9/f/7e3/9vb/7Oz/2Nj/x8f/Ozv/+Pj/3d3/nZ3/2dn//f3/6Oj/2tr/v7//09P/vr7/mZn/l5cdSvP3AAAAe3RSTlMAAhLiZgTb/vztB/JMRhlp6lQW86g8mQ4KFPs3UCH5U8huwlesWtTYGI7RsdVeJGfTW5rxnutLsvXWF8vQNdo6qQbuz7D4hgVIx2xtw8GC1TtZaIw0i84P98tU0/fsj7PKaAgiZZxeVfo8Z52eg1P0nESrENnjXVPUgw/uuSmDAAADsUlEQVR42u3aZ3cTRxgF4GtbYleSLdnGcsENG2ODjbExEHrvhAQCIb1Bem+QdkeuuFMNBBJIfmuOckzZI8/srHYmH3Lm+QNXK632LTvQ03Tu/IWeU/tTGTKT2n+q58L5c00wpXJd47DHEt5w47pKxLbhdLdPKb/7dBYxVLxw1GcI/2h1BcpzKNFHLX2JQ4gumaiitqpEEhEdOMJI9h5AFC3feYzI+7IF2tpSLEOqDXpObPRYFm/jCWho/4Ble7MdoT7fzhhq9yHEz28wltU1UPrJZ0wd66HwicfYvEFIfePTAP8tSLTupBHvtGJFH9bSkNrNWEHzERrT34xSH9Ogr1CijkbVAUH1KRqVqkdQAw07iIAaGlcTqI+/0LjeJJ5J0IIEnkpXMdzs4sTtW9dnZq7fuj2xOMtwVWk88RHDjBYejYvnjD8qjOpfQsUqhvj7oSjxcJIhVj3pyKqpNjYvVjQ/RrXq5YABKi3MCYm5BSrtWO5v11DlmlC4RpU1WRS9SJU7QukOVbpQ9JLu549+Dd0AUOlTbkGEuk85vxLAK5QbuytC3R2j3HoAjZSbFxrmKTcCoJdSk0LLJKV6gSaPMqNTQsvUKGW8JrxKqUWhaZFSeWyh1LTQNE2pHF6mzOy40DQ+S5mLimJcENoKlOnBWsr8KbRNUGYt5LXgd6HtD3lNQIoyN4S2G5RJIUOZm0LbTcqsBqVmhLYZSlkPsP4VWf+Rrd+m1v9o9h8Vv5p42C1R5qL1x7WRglOgVN52yfwNOBu76P+lLPoYidu23KPciIHGa07ZeIW1jvcNtI7q5vexCPGYCmf+m/Y9a3sAwQ5bI9T7ukPgPcn9GToEao+xk1OixJT+GIsvNAbx6eAgPq0xiF+KtkpYKhRXCQ8eFFcJhSWGu3rZ8jJkCM8kz9K4TUnrC6mAgzTsB9tLwQ2W15qfosQ2GrQNpZr7aczbzVjBZsvLcaC1g0bsbIVEnU8DOr6H1KDH2LwtUBi0/JII6Dxm9zUXkH+XMWzfh1Dte1i2Pe3QkC77Zel7aehpO8wyHG6Dtt0NjKxhN6I4uSli/TqJiJJDUQ4NDCURXTrXRy1XcumyD24M+AzhD1RXIIZsl/LoyZmurJHDM7s8lvB2FQ/PmPJ6PseAXP5HGMYAAC7ABbgAF+ACXIALcAEuwAW4ABfgAlyAC3ABLsAFuID/d8Cx4NEt8/byOf0wLnis8zjMq9/Kp7bWw4JOj8u8TlhRl+G/Mp2wpOX48GffvvZ1CyL4B53LAS6zb08EAAAAAElFTkSuQmCC");
background-size: 100%;
}
......@@ -373,7 +437,7 @@ export default {
}
.uni-system-choose-location .search-btn {
width: 2.8em;
margin-left: 5px;
color: #007aff;
font-size: 17px;
text-align: center;
......
<template>
<div class="uni-system-open-location">
<div
class="map-content"
:class="{ 'fix-position': isPoimarkerSrc }"
<v-uni-map
:latitude="center.latitude"
:longitude="center.longitude"
class="map"
:markers="[marker, location]"
@regionchange="onRegionChange"
>
<iframe
ref="map"
:src="src"
allow="geolocation"
sandbox="allow-scripts allow-same-origin allow-forms allow-top-navigation allow-modals allow-popups"
frameborder="0"
@load="_check"
/>
<!-- 去这里 -->
<div
v-if="isPoimarkerSrc"
class="actTonav"
@click="_nav"
/>
class="map-move"
@click="moveToLocation"
>
<i>&#xec32;</i>
</div>
</v-uni-map>
<div class="info">
<div
class="name"
@click="setCenter(marker)"
>
{{ name }}
</div>
<div
class="address"
@click="setCenter(marker)"
>
{{ address }}
</div>
<div
class="nav"
@click="nav"
>
<svg
width="26"
height="26"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M896 544c-207.807 0-388.391 82.253-480 203.149V173.136l201.555 201.555c12.412 12.412 32.723 12.412 45.136 0 12.412-12.412 12.412-32.723 0-45.136L408.913 75.777a31.93 31.93 0 0 0-2.222-2.468c-6.222-6.222-14.429-9.324-22.631-9.308l-0.059-0.002-0.059 0.002c-8.202-0.016-16.409 3.085-22.631 9.308a31.93 31.93 0 0 0-2.222 2.468l-253.78 253.778c-12.412 12.412-12.412 32.723 0 45.136 12.412 12.412 32.723 12.412 45.136 0L352 173.136V928c0 17.6 14.4 32 32 32s32-14.4 32-32c0-176.731 214.903-320 480-320 17.673 0 32-14.327 32-32 0-17.673-14.327-32-32-32z"
fill="#ffffff"
/>
</svg>
</div>
</div>
<div
class="nav-btn-back"
@click="_back"
@click="back"
>
<i class="uni-btn-icon">&#xe601;</i>
</div>
</div>
</template>
<script>
const key = __uniConfig.qqMapKey
const referer = 'uniapp'
const poimarkerSrc = 'https://apis.map.qq.com/tools/poimarker'
import {
ICON_PATH_ORIGIN,
ICON_PATH_TARGET,
MapType,
getMapInfo
} from '../../../helpers/location'
export default {
name: 'SystemOpenLocation',
......@@ -48,30 +77,78 @@ export default {
scale,
name,
address,
src: latitude && longitude ? `${poimarkerSrc}?type=0&marker=coord:${latitude},${longitude};title:${name};addr:${address};&key=${key}&referer=${referer}` : '',
isPoimarkerSrc: true
center: {
latitude,
longitude
},
marker: {
id: 1,
latitude,
longitude,
iconPath: ICON_PATH_TARGET,
width: 32,
height: 52
},
location: {
id: 2,
latitude: 0,
longitude: 0,
iconPath: ICON_PATH_ORIGIN,
width: 44,
height: 44
}
}
},
methods: {
_back () {
if (this.$refs.map.src.indexOf(poimarkerSrc) !== 0) {
this.$refs.map.src = this.src
} else {
getApp().$router.back()
onRegionChange (event) {
const centerLocation = event.detail.centerLocation
if (centerLocation) {
this.center.latitude = centerLocation.latitude
this.center.longitude = centerLocation.longitude
}
this._check()
},
_check () {
if (this.$refs.map.src.indexOf(poimarkerSrc) === 0) {
this.isPoimarkerSrc = true
} else {
this.isPoimarkerSrc = false
}
setCenter ({ latitude, longitude }) {
this.center.latitude = latitude
this.center.longitude = longitude
},
moveToLocation () {
uni.getLocation({
type: 'gcj02',
success: this.move.bind(this),
fail: () => {
// move({
// latitude: 0,
// longitude: 0
// })
}
})
},
_nav () {
var url =
`https://map.qq.com/nav/drive#routes/page?transport=2&epointy=${this.latitude}&epointx=${this.longitude}&eword=${encodeURIComponent(this.name || '目的地')}&referer=${referer}`
this.$refs.map.src = url
move ({ latitude, longitude }) {
this.location.latitude = latitude
this.location.longitude = longitude
this.setCenter({ latitude, longitude })
},
back () {
getApp().$router.back()
},
nav () {
const mapInfo = getMapInfo()
let url = ''
if (mapInfo.type === MapType.GOOGLE) {
const origin = this.location.latitude
? `&origin=${this.location.latitude}%2C${this.location.longitude}`
: ''
url = `https://www.google.com/maps/dir/?api=1${origin}&destination=${this.latitude}%2C${this.longitude}`
} else if (mapInfo.type === MapType.QQ) {
const fromcoord = this.location.latitude
? `&fromcoord=${this.location.latitude}%2C${this.location.longitude}`
: ''
url = `https://apis.map.qq.com/uri/v1/routeplan?type=drive${fromcoord}&tocoord=${this.latitude
}%2C${this.longitude}&from=${encodeURIComponent(
'我的位置'
)}&to=${encodeURIComponent(this.name || '目的地')}&ref=${mapInfo.key}`
}
window.open(url)
}
}
}
......@@ -85,6 +162,84 @@ export default {
width: 100%;
height: 100%;
background: #f8f8f8;
z-index: 999;
}
.uni-system-open-location .map {
position: absolute;
top: 0;
left: 0;
width: 100%;
bottom: 80px;
height: auto;
}
.uni-system-open-location .info {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 80px;
background-color: white;
padding: 15px;
box-sizing: border-box;
line-height: 1.5;
}
.uni-system-open-location .info > .name {
font-size: 17px;
color: #111111;
}
.uni-system-open-location .info > .address {
font-size: 14px;
color: #666666;
}
.uni-system-open-location .info > .nav {
position: absolute;
top: 50%;
right: 15px;
width: 50px;
height: 50px;
border-radius: 50%;
margin-top: -25px;
background-color: #007aff;
}
.uni-system-open-location .info > .nav > svg {
display: block;
width: 100%;
height: 100%;
padding: 10px;
box-sizing: border-box;
}
.uni-system-open-location .map-move {
position: absolute;
bottom: 50px;
right: 10px;
width: 40px;
height: 40px;
box-sizing: border-box;
line-height: 40px;
background-color: white;
border-radius: 50%;
pointer-events: auto;
cursor: pointer;
box-shadow: 0px 0 5px 1px rgba(0, 0, 0, 0.3);
}
.uni-system-open-location .map-move > i {
display: block;
width: 100%;
height: 100%;
font: normal normal normal 14px/1 "unimapbtn";
line-height: inherit;
text-align: center;
font-size: 24px;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
}
.uni-system-open-location .nav-btn-back {
......
export const ICON_PATH_ORIGIN =
'data:image/png;base64,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'
export const ICON_PATH_TARGET =
'data:image/png;base64,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'
export const MapType = {
QQ: 'qq',
GOOGLE: 'google',
UNKNOWN: ''
}
export function getMapInfo () {
let type = MapType.UNKNOWN
let key = ''
if (__uniConfig.qqMapKey) {
type = MapType.QQ
key = __uniConfig.qqMapKey
} else if (__uniConfig.googleMapKey) {
type = MapType.GOOGLE
key = __uniConfig.googleMapKey
}
return {
type,
key
}
}
import {
getJSONP
} from '../../../helpers/get-jsonp'
import {
MapType,
getMapInfo
} from '../../../helpers/location'
/**
* 获取定位信息
......@@ -14,7 +18,7 @@ export function getLocation ({
const {
invokeCallbackHandler: invoke
} = UniServiceJSBridge
const key = __uniConfig.qqMapKey
const mapInfo = getMapInfo()
new Promise((resolve, reject) => {
if (navigator.geolocation) {
......@@ -27,26 +31,50 @@ export function getLocation ({
}
}).catch(() => {
return new Promise((resolve, reject) => {
getJSONP(`https://apis.map.qq.com/ws/location/v1/ip?output=jsonp&key=${key}`, {
callback: 'callback'
}, (res) => {
if ('result' in res && res.result.location) {
const location = res.result.location
resolve({
latitude: location.lat,
longitude: location.lng
}, true)
} else {
reject(new Error(res.message || JSON.stringify(res)))
}
}, () => reject(new Error('network error')))
if (mapInfo.type === MapType.QQ) {
getJSONP(`https://apis.map.qq.com/ws/location/v1/ip?output=jsonp&key=${mapInfo.key}`, {
callback: 'callback'
}, (res) => {
if ('result' in res && res.result.location) {
const location = res.result.location
resolve({
latitude: location.lat,
longitude: location.lng
}, true)
} else {
reject(new Error(res.message || JSON.stringify(res)))
}
}, () => reject(new Error('network error')))
} else if (mapInfo.type === MapType.GOOGLE) {
uni.request({
method: 'POST',
url: `https://www.googleapis.com/geolocation/v1/geolocate?key=${mapInfo.key}`,
success (res) {
const data = res.data
if ('location' in data) {
resolve({
latitude: data.location.lat,
longitude: data.location.lng,
accuracy: data.accuracy
})
} else {
reject(new Error((data.error && data.error.message) || JSON.stringify(res)))
}
},
fail () {
reject(new Error('network error'))
}
})
} else {
reject(new Error('network error'))
}
})
}).then((coords, skip) => {
if (type.toUpperCase() === 'WGS84' || skip) {
if (type.toUpperCase() === 'WGS84' || mapInfo.type !== MapType.QQ || skip) {
return coords
}
return new Promise((resolve, reject) => {
getJSONP(`https://apis.map.qq.com/jsapi?qt=translate&type=1&points=${coords.longitude},${coords.latitude}&key=${key}&output=jsonp&pf=jsapi&ref=jsapi`, {
getJSONP(`https://apis.map.qq.com/jsapi?qt=translate&type=1&points=${coords.longitude},${coords.latitude}&key=${mapInfo.key}&output=jsonp&pf=jsapi&ref=jsapi`, {
callback: 'cb'
}, (res) => {
if ('detail' in res && 'points' in res.detail && res.detail.points.length) {
......
......@@ -2,7 +2,7 @@ import {
setProperties
} from 'uni-shared'
const setTabBarItemProps = ['text', 'iconPath', 'selectedIconPath']
const setTabBarItemProps = ['text', 'iconPath', 'selectedIconPath', 'visible']
const setTabBarStyleProps = ['color', 'selectedColor', 'backgroundColor', 'borderStyle']
......
import getRealPath from 'uni-platform/helpers/get-real-path'
export default {
props: {
id: {
type: [Number, String],
default: ''
},
latitude: {
type: [Number, String],
require: true
},
longitude: {
type: [Number, String],
require: true
},
title: {
type: String,
default: ''
},
iconPath: {
type: String,
require: true
},
rotate: {
type: [Number, String],
default: 0
},
alpha: {
type: [Number, String],
default: 1
},
width: {
type: [Number, String],
default: ''
},
height: {
type: [Number, String],
default: ''
},
callout: {
type: Object,
default: null
},
label: {
type: Object,
default: null
},
anchor: {
type: Object,
default: null
},
clusterId: {
type: [Number, String],
default: ''
},
customCallout: {
type: Object,
default: null
},
ariaLabel: {
type: String,
default: ''
}
},
mounted () {
const $parent = this.$parent
$parent.mapReady(() => {
this._maps = $parent._maps
this._map = $parent._map
this.addMarker(this.$props)
Object.keys(this.$props).forEach(key => {
this.$watch(key, () => {
this.updateMarker(this.$props)
})
})
})
},
beforeDestroy () {
this.removeMarker()
},
methods: {
addMarker (props) {
const maps = this._maps
const map = this._map
const marker = this._marker = new maps.Marker({
map,
flat: true,
autoRotation: false
})
this.$parent._markers[this.id] = marker
this.updateMarker(props)
maps.event.addListener(marker, 'click', () => {
const callout = marker.callout
if (callout) {
const div = callout.div
const parent = div.parentNode
if (!callout.alwaysVisible) {
callout.set('visible', !callout.visible)
}
if (callout.visible) {
parent.removeChild(div)
parent.appendChild(div)
}
}
if (this.id) {
this.$parent.$trigger('markertap', {}, {
markerId: this.id
})
}
})
},
updateMarker (option) {
const map = this._map
const maps = this._maps
const marker = this._marker
const title = option.title
const position = new maps.LatLng(option.latitude, option.longitude)
const img = new Image()
img.onload = () => {
const anchor = option.anchor || {}
let icon
let w
let h
const x = typeof anchor.x === 'number' ? anchor.x : 0.5
const y = typeof anchor.y === 'number' ? anchor.y : 1
if (option.iconPath && (option.width || option.height)) {
w = option.width || (img.width / img.height) * option.height
h = option.height || (img.height / img.width) * option.width
} else {
w = img.width / 2
h = img.height / 2
}
const top = h - (h - y)
if ('MarkerImage' in maps) {
icon = new maps.MarkerImage(
img.src,
null,
null,
new maps.Point(x * w, y * h),
new maps.Size(w, h)
)
} else {
icon = {
url: img.src,
anchor: new maps.Point(x, y),
size: new maps.Size(w, h)
}
}
marker.setPosition(position)
marker.setIcon(icon)
if ('setRotation' in marker) {
marker.setRotation(option.rotate || 0)
}
const labelOpt = option.label || {}
if ('label' in marker) {
marker.label.setMap(null)
delete marker.label
}
let label
if (labelOpt.content) {
if ('Label' in maps) {
label = new maps.Label({
position: position,
map: map,
clickable: false,
content: labelOpt.content,
style: {
border: 'none',
padding: '8px',
background: 'none',
color: labelOpt.color,
fontSize: (labelOpt.fontSize || 14) + 'px',
lineHeight: (labelOpt.fontSize || 14) + 'px',
marginLeft: labelOpt.x,
marginTop: labelOpt.y
}
})
marker.label = label
} else if ('setLabel' in marker) {
marker.setLabel({
text: labelOpt.content,
color: labelOpt.color,
fontSize: (labelOpt.fontSize || 14) + 'px'
})
}
}
const calloutOpt = option.callout || {}
let callout = marker.callout
let calloutStyle
if (calloutOpt.content || title) {
calloutStyle = calloutOpt.content
? {
position,
map,
top,
content: calloutOpt.content,
color: calloutOpt.color,
fontSize: calloutOpt.fontSize,
borderRadius: calloutOpt.borderRadius,
bgColor: calloutOpt.bgColor,
padding: calloutOpt.padding,
boxShadow: calloutOpt.boxShadow,
display: calloutOpt.display
}
: {
position,
map,
top,
content: title,
boxShadow: '0px 0px 3px 1px rgba(0,0,0,0.5)'
}
if (callout) {
callout.setOption(calloutStyle)
} else {
callout = marker.callout = new maps.Callout(calloutStyle)
callout.div.onclick = function ($event) {
if (this.id !== '') {
this.$parent.$trigger('callouttap', $event, {
markerId: this.id
})
}
$event.stopPropagation()
$event.preventDefault()
}
}
} else {
if (callout) {
callout.setMap(null)
delete marker.callout
}
}
}
img.src = getRealPath(option.iconPath)
},
removeMarker () {
const marker = this._marker
if (marker) {
if (marker.label) {
marker.label.setMap(null)
}
if (marker.callout) {
marker.callout.setMap(null)
}
marker.setMap(null)
}
delete this.$parent._markers[this.id]
this._marker = null
}
},
render () {
return null
}
}
export function createCallout (maps) {
const overlay = new (maps.OverlayView || maps.Overlay)()
function onAdd () {
const div = this.div
const panes = this.getPanes()
panes.floatPane.appendChild(div)
}
function onRemove () {
const parentNode = this.div.parentNode
if (parentNode) {
parentNode.removeChild(this.div)
}
}
class Callout {
option
position
index
visible
alwaysVisible
div
triangle
set onclick (callback) {
this.div.onclick = callback
}
get onclick () {
return this.div.onclick
}
constructor (option = {}) {
this.option = option || {}
const map = option.map
this.position = option.position
this.index = 1
const visible = (this.visible = this.alwaysVisible = option.display === 'ALWAYS')
const div = (this.div = document.createElement('div'))
const divStyle = div.style
divStyle.position = 'absolute'
divStyle.whiteSpace = 'nowrap'
divStyle.transform = 'translateX(-50%) translateY(-100%)'
divStyle.zIndex = '1'
divStyle.boxShadow = option.boxShadow || 'none'
divStyle.display = visible ? 'block' : 'none'
const triangle = (this.triangle = document.createElement('div'))
triangle.setAttribute(
'style',
'position: absolute;white-space: nowrap;border-width: 4px;border-style: solid;border-color: #fff transparent transparent;border-image: initial;font-size: 12px;padding: 0px;background-color: transparent;width: 0px;height: 0px;transform: translate(-50%, 100%);left: 50%;bottom: 0;'
)
this.setStyle(option)
div.appendChild(triangle)
if (map) {
this.setMap(map)
}
}
onAdd = onAdd
construct = onAdd
setOption (option) {
this.option = option
this.setPosition(option.position)
if (option.display === 'ALWAYS') {
this.alwaysVisible = this.visible = true
} else {
this.alwaysVisible = false
}
this.setStyle(option)
}
setStyle (option) {
const div = this.div
const divStyle = div.style
div.innerText = option.content || ''
divStyle.lineHeight = (option.fontSize || 14) + 'px'
divStyle.fontSize = (option.fontSize || 14) + 'px'
divStyle.padding = (option.padding || 8) + 'px'
divStyle.color = option.color || '#000'
divStyle.borderRadius = (option.borderRadius || 0) + 'px'
divStyle.backgroundColor = option.bgColor || '#fff'
divStyle.marginTop = '-' + ((option.top || 0) + 5) + 'px'
this.triangle.style.borderColor = `${option.bgColor || '#fff'} transparent transparent`
}
setPosition (position) {
this.position = position
this.draw()
}
draw () {
const overlayProjection = this.getProjection()
if (!this.position || !this.div || !overlayProjection) {
return
}
const pixel = overlayProjection.fromLatLngToDivPixel(this.position)
const divStyle = this.div.style
divStyle.left = pixel.x + 'px'
divStyle.top = pixel.y + 'px'
}
changed () {
const divStyle = this.div.style
divStyle.display = this.visible ? 'block' : 'none'
}
onRemove = onRemove
destroy = onRemove
}
Callout.prototype = overlay
return Callout
}
import {
MapType,
getMapInfo
} from '../../../../helpers/location'
import { createCallout } from './callout'
let maps
const callbacksMap = {}
const GOOGLE_MAP_CALLBACKNAME = '__map_callback__'
export function loadMaps (libraries, callback) {
const mapInfo = getMapInfo()
if (!mapInfo.key) {
console.error('Map key not configured.')
return
}
const callbacks = (callbacksMap[mapInfo.type] = callbacksMap[mapInfo.type] || [])
if (maps) {
callback(maps)
} else if (
window[mapInfo.type] &&
window[mapInfo.type].maps
) {
maps = window[mapInfo.type].maps
maps.Callout = maps.Callout || createCallout(maps)
callback(maps)
} else if (callbacks.length) {
callbacks.push(callback)
} else {
callbacks.push(callback)
const globalExt = window
const callbackName = GOOGLE_MAP_CALLBACKNAME + mapInfo.type
globalExt[callbackName] = function () {
delete globalExt[callbackName]
maps = window[mapInfo.type].maps
maps.Callout = createCallout(maps)
callbacks.forEach((callback) => callback(maps))
callbacks.length = 0
}
const script = document.createElement('script')
let src =
mapInfo.type === MapType.GOOGLE ? 'https://maps.googleapis.com/maps/api/js?' : 'https://map.qq.com/api/js?v=2.exp&'
if (mapInfo.type === MapType.QQ) {
libraries.push('geometry')
}
if (libraries.length) {
src += `libraries=${libraries.join('%2C')}&`
}
script.src = `${src}key=${mapInfo.key}&callback=${callbackName}`
script.onerror = function () {
console.error('Map load failed.')
}
document.body.appendChild(script)
}
}
let realAtob
const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
const b64re = /^(?:[A-Za-z\d+/]{4})*?(?:[A-Za-z\d+/]{2}(?:==)?|[A-Za-z\d+/]{3}=?)?$/
if (typeof atob !== 'function') {
realAtob = function (str) {
str = String(str).replace(/[\t\n\f\r ]+/g, '')
if (!b64re.test(str)) { throw new Error("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.") }
// Adding the padding if missing, for semplicity
str += '=='.slice(2 - (str.length & 3))
var bitmap; var result = ''; var r1; var r2; var i = 0
for (; i < str.length;) {
bitmap = b64.indexOf(str.charAt(i++)) << 18 | b64.indexOf(str.charAt(i++)) << 12 |
(r1 = b64.indexOf(str.charAt(i++))) << 6 | (r2 = b64.indexOf(str.charAt(i++)))
result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255)
: r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255)
: String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255)
}
return result
}
} else {
// 注意atob只能在全局对象上调用,例如:`const Base64 = {atob};Base64.atob('xxxx')`是错误的用法
realAtob = atob
}
function b64DecodeUnicode (str) {
return decodeURIComponent(atob(str).split('').map(function (c) {
return decodeURIComponent(realAtob(str).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
}).join(''))
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册