diff --git a/package.json b/package.json index 04da3d1a0c2f0d8ebbbb0b5fcbb5a047b5f42692..a9d2b0191f69520cd185291733f1e5e450e12755 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@rollup/plugin-node-resolve": "^11.0.1", "@rollup/plugin-replace": "^2.3.4", "@size-limit/preset-app": "^4.10.1", + "@types/css-font-loading-module": "^0.0.4", "@types/debug": "^4.1.5", "@types/es-module-lexer": "^0.3.0", "@types/fs-extra": "^9.0.6", diff --git a/packages/uni-api/src/index.ts b/packages/uni-api/src/index.ts index 535c878699441ede74be1e0e68cbf451b0a77a4f..bdc830af1db106afdefca1a1c051fa3f3da0d789 100644 --- a/packages/uni-api/src/index.ts +++ b/packages/uni-api/src/index.ts @@ -45,6 +45,8 @@ export * from './protocols/location/getLocation' export * from './protocols/route/route' +export * from './protocols/ui/loadFontFace' +export * from './protocols/ui/pageScrollTo' export * from './protocols/ui/navigationBar' export * from './protocols/ui/popup' export * from './protocols/ui/tabBar' diff --git a/packages/uni-api/src/protocols/ui/pageScrollTo.ts b/packages/uni-api/src/protocols/ui/pageScrollTo.ts index 732f8ef73549e4d85f00fe2aa2e12c23af9836ad..8513792bb0ab5c5441f54e77ca420e3b60c9556e 100644 --- a/packages/uni-api/src/protocols/ui/pageScrollTo.ts +++ b/packages/uni-api/src/protocols/ui/pageScrollTo.ts @@ -1,5 +1,3 @@ -import { hasOwn } from '@vue/shared' - export const API_PAGE_SCROLL_TO = 'pageScrollTo' export type API_TYPE_PAGE_SCROLL_TO = typeof uni.pageScrollTo export const PageScrollToProtocol: ApiProtocol = { @@ -11,20 +9,11 @@ export const PageScrollToProtocol: ApiProtocol = { type: Number, }, } -const DEFAULT_DURATION = 400 +const DEFAULT_DURATION = 300 export const PageScrollToOptions: ApiOptions = { formatArgs: { duration(value, params) { - if (!hasOwn(params, 'duration')) { - return (params.duration = DEFAULT_DURATION) - } - value = parseInt(value + '') - if (isNaN(value)) { - value = DEFAULT_DURATION - } else { - value = Math.max(0, value) - } - params.duration = value + params.duration = Math.max(0, parseInt(value + '') || DEFAULT_DURATION) }, }, } diff --git a/packages/uni-components/src/components/image/index.tsx b/packages/uni-components/src/components/image/index.tsx index 078314612ef1ab6f8914bbd804f216c8fa834388..45f976fe7cf8277625004197f864ea8b1bbbbcb2 100644 --- a/packages/uni-components/src/components/image/index.tsx +++ b/packages/uni-components/src/components/image/index.tsx @@ -35,7 +35,6 @@ const props = { type ImageProps = ExtractPropTypes type ImageState = ReturnType type FixSize = ReturnType['fixSize'] -type ResetSize = ReturnType['resetSize'] const FIX_MODES = { widthFix: ['width', 'height'], @@ -64,11 +63,10 @@ export default /*#__PURE__*/ defineComponent({ const rootRef = ref(null) const state = useImageState(rootRef, props) const trigger = useCustomEvent(rootRef, emit) - const { fixSize, resetSize } = useImageSize(rootRef, props, state) + const { fixSize } = useImageSize(rootRef, props, state) useImageLoader(state, { trigger, fixSize, - resetSize, }) return () => { const { mode } = props @@ -127,20 +125,21 @@ function useImageLoader( { trigger, fixSize, - resetSize, }: { fixSize: FixSize - resetSize: ResetSize trigger: CustomEventTrigger } ) { let img: HTMLImageElement | null + const setState = (width = 0, height = 0, imgSrc = '') => { + state.origWidth = width + state.origHeight = height + state.imgSrc = imgSrc + } const loadImage = (src: string) => { if (!src) { resetImage() - state.origWidth = 0 - state.origHeight = 0 - state.imgSrc = '' + setState() // 与微信小程序保持一致,保留之前样式 // resetSize() return @@ -150,9 +149,7 @@ function useImageLoader( } img.onload = (evt) => { const { width, height } = img! - state.origWidth = width - state.origHeight = height - state.imgSrc = src + setState(width, height, src) fixSize() resetImage() trigger('load', evt, { @@ -161,13 +158,10 @@ function useImageLoader( }) } img.onerror = (evt) => { - const { src } = state - state.origWidth = 0 - state.origHeight = 0 - state.imgSrc = '' + setState() resetImage() trigger('error', evt as Event, { - errMsg: `GET ${src} 404 (Not Found)`, + errMsg: `GET ${state.src} 404 (Not Found)`, }) } img.src = src diff --git a/packages/uni-core/src/view/plugin/componentInstance.ts b/packages/uni-core/src/view/plugin/componentInstance.ts index e7b81bad938073bdbdd58cf7d26cd978ccfc8419..bd6dff65ba21723b85e507ed54ce3fd6dbd36a21 100644 --- a/packages/uni-core/src/view/plugin/componentInstance.ts +++ b/packages/uni-core/src/view/plugin/componentInstance.ts @@ -10,6 +10,7 @@ export function $normalizeNativeEvent( this: ComponentPublicInstance, evt: Event ) { + // TODO 目前内置组件,也会进入以下处理逻辑,是否有影响? const { currentTarget } = evt if (!(evt instanceof Event) || !(currentTarget instanceof HTMLElement)) { return evt @@ -24,6 +25,10 @@ export function $normalizeNativeEvent( normalizeClickEvent((res as unknown) as WechatMiniprogram.Touch, evt) } else if (__PLATFORM__ === 'h5' && isMouseEvent(evt)) { normalizeMouseEvent((res as unknown) as WechatMiniprogram.Touch, evt) + } else if (evt instanceof TouchEvent) { + const { top } = getWindowOffset() + ;(res as any).touches = normalizeTouchEvent(evt.touches, top) + ;(res as any).changedTouches = normalizeTouchEvent(evt.changedTouches, top) } return res @@ -85,3 +90,19 @@ function createTouchEvent(evt: MouseEvent) { pageY: evt.pageY, } } + +function normalizeTouchEvent(touches: TouchList, top: number) { + const res = [] + for (let i = 0; i < touches.length; i++) { + const { identifier, pageX, pageY, clientX, clientY, force } = touches[i] + res.push({ + identifier, + pageX, + pageY: pageY - top, + clientX: clientX, + clientY: clientY - top, + force: force || 0, + }) + } + return res +} diff --git a/packages/uni-h5/dist/uni-h5.esm.js b/packages/uni-h5/dist/uni-h5.esm.js index 7c1d0480735b49ce11955875f362261101975774..a6e64d1fc7f987af7efb53c451a3844a913edac6 100644 --- a/packages/uni-h5/dist/uni-h5.esm.js +++ b/packages/uni-h5/dist/uni-h5.esm.js @@ -1,6 +1,6 @@ import {isFunction, extend, isPlainObject, isString, invokeArrayFns as invokeArrayFns$1, hyphenate, isArray, hasOwn as hasOwn$1, isObject as isObject$1, capitalize, toRawType, makeMap as makeMap$1, isPromise} from "@vue/shared"; import {injectHook, createVNode, inject, provide, reactive, computed, nextTick, getCurrentInstance, onBeforeMount, onMounted, onBeforeActivate, onBeforeDeactivate, openBlock, createBlock, mergeProps, toDisplayString, ref, defineComponent, resolveComponent, toHandlers, renderSlot, watch, onActivated, onBeforeUnmount, withModifiers, withDirectives, vShow, vModelDynamic, createCommentVNode, createTextVNode, Fragment, renderList, vModelText, watchEffect, withCtx, KeepAlive, resolveDynamicComponent} from "vue"; -import {once, passive, normalizeTarget, invokeArrayFns, NAVBAR_HEIGHT, parseQuery, decodedQuery, plusReady, debounce, PRIMARY_COLOR as PRIMARY_COLOR$1, removeLeadingSlash, getLen, updateElementStyle} from "@dcloudio/uni-shared"; +import {once, passive, normalizeTarget, invokeArrayFns, NAVBAR_HEIGHT, parseQuery, decodedQuery, plusReady, debounce, PRIMARY_COLOR as PRIMARY_COLOR$1, removeLeadingSlash, getLen, updateElementStyle, addFont} from "@dcloudio/uni-shared"; import {useRoute, createRouter, createWebHistory, createWebHashHistory, isNavigationFailure, RouterView} from "vue-router"; function applyOptions(options, instance2, publicThis) { Object.keys(options).forEach((name) => { @@ -633,6 +633,10 @@ function $normalizeNativeEvent(evt) { normalizeClickEvent(res, evt); } else if (isMouseEvent(evt)) { normalizeMouseEvent(res, evt); + } else if (evt instanceof TouchEvent) { + const {top} = getWindowOffset(); + res.touches = normalizeTouchEvent(evt.touches, top); + res.changedTouches = normalizeTouchEvent(evt.changedTouches, top); } return res; } @@ -682,6 +686,21 @@ function createTouchEvent(evt) { pageY: evt.pageY }; } +function normalizeTouchEvent(touches, top) { + const res = []; + for (let i2 = 0; i2 < touches.length; i2++) { + const {identifier, pageX, pageY, clientX, clientY, force} = touches[i2]; + res.push({ + identifier, + pageX, + pageY: pageY - top, + clientX, + clientY: clientY - top, + force: force || 0 + }); + } + return res; +} var instance = /* @__PURE__ */ Object.freeze({ __proto__: null, [Symbol.toStringTag]: "Module", @@ -4925,6 +4944,18 @@ function createNormalizeUrl(type) { } }; } +const API_LOAD_FONT_FACE = "loadFontFace"; +const LoadFontFaceProtocol = { + family: { + type: String, + required: true + }, + source: { + type: String, + required: true + }, + desc: Object +}; const FRONT_COLORS = ["#ffffff", "#000000"]; const API_SET_NAVIGATION_BAR_COLOR = "setNavigationBarColor"; const SetNavigationBarColorOptions = { @@ -5861,13 +5892,11 @@ var index$3 = /* @__PURE__ */ defineComponent({ const state = useImageState(rootRef, props2); const trigger = useCustomEvent(rootRef, emit); const { - fixSize, - resetSize + fixSize } = useImageSize(rootRef, props2, state); useImageLoader(state, { trigger, - fixSize, - resetSize + fixSize }); return () => { const { @@ -5928,16 +5957,18 @@ function useImageState(rootRef, props2) { } function useImageLoader(state, { trigger, - fixSize, - resetSize + fixSize }) { let img; + const setState = (width = 0, height = 0, imgSrc = "") => { + state.origWidth = width; + state.origHeight = height; + state.imgSrc = imgSrc; + }; const loadImage = (src) => { if (!src) { resetImage(); - state.origWidth = 0; - state.origHeight = 0; - state.imgSrc = ""; + setState(); return; } if (!img) { @@ -5948,9 +5979,7 @@ function useImageLoader(state, { width, height } = img; - state.origWidth = width; - state.origHeight = height; - state.imgSrc = src; + setState(width, height, src); fixSize(); resetImage(); trigger("load", evt, { @@ -5959,15 +5988,10 @@ function useImageLoader(state, { }); }; img.onerror = (evt) => { - const { - src: src2 - } = state; - state.origWidth = 0; - state.origHeight = 0; - state.imgSrc = ""; + setState(); resetImage(); trigger("error", evt, { - errMsg: `GET ${src2} 404 (Not Found)` + errMsg: `GET ${state.src} 404 (Not Found)` }); }; img.src = src; @@ -12246,6 +12270,13 @@ function getTabBarPageId(url) { const switchTab = defineAsyncApi(API_SWITCH_TAB, ({url}, {resolve, reject}) => { return removeNonTabBarPages(), navigate(API_SWITCH_TAB, url, getTabBarPageId(url)).then(resolve).catch(reject); }, SwitchTabProtocol, SwitchTabOptions); +const loadFontFace = defineAsyncApi(API_LOAD_FONT_FACE, ({family, source, desc}, {resolve, reject}) => { + addFont(family, source, desc).then(() => { + resolve(); + }).catch((err) => { + reject(`loadFontFace:fail ${err}`); + }); +}, LoadFontFaceProtocol); function setNavigationBar(pageMeta, type, args, resolve, reject) { if (!pageMeta) { return reject("page not found"); @@ -12474,6 +12505,7 @@ var api = /* @__PURE__ */ Object.freeze({ redirectTo, reLaunch, switchTab, + loadFontFace, setNavigationBarColor, showNavigationBarLoading, hideNavigationBarLoading, @@ -13523,4 +13555,4 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { ]); } _sfc_main.render = _sfc_render; -export {_sfc_main$1 as AsyncErrorComponent, _sfc_main as AsyncLoadingComponent, _sfc_main$l as Audio, index$5 as Button, _sfc_main$k as Canvas, _sfc_main$j as Checkbox, _sfc_main$i as CheckboxGroup, _sfc_main$h as Editor, index$6 as Form, index$4 as Icon, index$3 as Image, _sfc_main$g as Input, _sfc_main$f as Label, LayoutComponent, _sfc_main$e as MovableView, _sfc_main$d as Navigator, index as PageComponent, _sfc_main$c as Progress, _sfc_main$b as Radio, _sfc_main$a as RadioGroup, ResizeSensor, _sfc_main$9 as RichText, _sfc_main$8 as ScrollView, _sfc_main$7 as Slider, _sfc_main$6 as SwiperItem, _sfc_main$5 as Switch, index$2 as Text, _sfc_main$4 as Textarea, UniServiceJSBridge$1 as UniServiceJSBridge, UniViewJSBridge$1 as UniViewJSBridge, _sfc_main$3 as Video, index$1 as View, addInterceptor, arrayBufferToBase64, base64ToArrayBuffer, canIUse, chooseFile, chooseImage, chooseVideo, clearStorage, clearStorageSync, closeSocket, connectSocket, createInnerAudioContext, createIntersectionObserver, createSelectorQuery, createVideoContext, cssBackdropFilter, cssConstant, cssEnv, cssVar, downloadFile, getApp$1 as getApp, getCurrentPages$1 as getCurrentPages, getFileInfo, getImageInfo, getLocation, getNetworkType, getStorage, getStorageInfo, getStorageInfoSync, getStorageSync, getSystemInfo, getSystemInfoSync, getVideoInfo, hideKeyboard, hideLoading, hideNavigationBarLoading, hideTabBar, hideTabBarRedDot, hideToast, makePhoneCall, navigateBack, navigateTo, offAccelerometerChange, offCompassChange, offNetworkStatusChange, onAccelerometerChange, onCompassChange, onNetworkStatusChange, onSocketClose, onSocketError, onSocketMessage, onSocketOpen, onTabBarMidButtonTap, openDocument, index$7 as plugin, promiseInterceptor, reLaunch, redirectTo, removeInterceptor, removeStorage, removeStorageSync, removeTabBarBadge, request, sendSocketMessage, setNavigationBarColor, setNavigationBarTitle, setStorage, setStorageSync, setTabBarBadge, setTabBarItem, setTabBarStyle, setupApp, setupPage, showActionSheet, showLoading, showModal, showNavigationBarLoading, showTabBar, showTabBarRedDot, showToast, startAccelerometer, startCompass, stopAccelerometer, stopCompass, switchTab, uni$1 as uni, uploadFile, upx2px, useCustomEvent, usePageRoute, useSubscribe, vibrateLong, vibrateShort}; +export {_sfc_main$1 as AsyncErrorComponent, _sfc_main as AsyncLoadingComponent, _sfc_main$l as Audio, index$5 as Button, _sfc_main$k as Canvas, _sfc_main$j as Checkbox, _sfc_main$i as CheckboxGroup, _sfc_main$h as Editor, index$6 as Form, index$4 as Icon, index$3 as Image, _sfc_main$g as Input, _sfc_main$f as Label, LayoutComponent, _sfc_main$e as MovableView, _sfc_main$d as Navigator, index as PageComponent, _sfc_main$c as Progress, _sfc_main$b as Radio, _sfc_main$a as RadioGroup, ResizeSensor, _sfc_main$9 as RichText, _sfc_main$8 as ScrollView, _sfc_main$7 as Slider, _sfc_main$6 as SwiperItem, _sfc_main$5 as Switch, index$2 as Text, _sfc_main$4 as Textarea, UniServiceJSBridge$1 as UniServiceJSBridge, UniViewJSBridge$1 as UniViewJSBridge, _sfc_main$3 as Video, index$1 as View, addInterceptor, arrayBufferToBase64, base64ToArrayBuffer, canIUse, chooseFile, chooseImage, chooseVideo, clearStorage, clearStorageSync, closeSocket, connectSocket, createInnerAudioContext, createIntersectionObserver, createSelectorQuery, createVideoContext, cssBackdropFilter, cssConstant, cssEnv, cssVar, downloadFile, getApp$1 as getApp, getCurrentPages$1 as getCurrentPages, getFileInfo, getImageInfo, getLocation, getNetworkType, getStorage, getStorageInfo, getStorageInfoSync, getStorageSync, getSystemInfo, getSystemInfoSync, getVideoInfo, hideKeyboard, hideLoading, hideNavigationBarLoading, hideTabBar, hideTabBarRedDot, hideToast, loadFontFace, makePhoneCall, navigateBack, navigateTo, offAccelerometerChange, offCompassChange, offNetworkStatusChange, onAccelerometerChange, onCompassChange, onNetworkStatusChange, onSocketClose, onSocketError, onSocketMessage, onSocketOpen, onTabBarMidButtonTap, openDocument, index$7 as plugin, promiseInterceptor, reLaunch, redirectTo, removeInterceptor, removeStorage, removeStorageSync, removeTabBarBadge, request, sendSocketMessage, setNavigationBarColor, setNavigationBarTitle, setStorage, setStorageSync, setTabBarBadge, setTabBarItem, setTabBarStyle, setupApp, setupPage, showActionSheet, showLoading, showModal, showNavigationBarLoading, showTabBar, showTabBarRedDot, showToast, startAccelerometer, startCompass, stopAccelerometer, stopCompass, switchTab, uni$1 as uni, uploadFile, upx2px, useCustomEvent, usePageRoute, useSubscribe, vibrateLong, vibrateShort}; diff --git a/packages/uni-h5/src/service/api/index.ts b/packages/uni-h5/src/service/api/index.ts index cdfe688956eea69089487bd68cea15c58fba9faf..31b97661df59a11c6e7d93a3be9439145e565356 100644 --- a/packages/uni-h5/src/service/api/index.ts +++ b/packages/uni-h5/src/service/api/index.ts @@ -36,6 +36,7 @@ export * from './route/redirectTo' export * from './route/reLaunch' export * from './route/switchTab' +export * from './ui/loadFontFace' export * from './ui/navigationBar' export * from './ui/popup' export * from './ui/tabBar' diff --git a/packages/uni-h5/src/service/api/ui/loadFontFace.ts b/packages/uni-h5/src/service/api/ui/loadFontFace.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f34fa048ae6a1c8946d55e05b8f89fd0b60d2e0 --- /dev/null +++ b/packages/uni-h5/src/service/api/ui/loadFontFace.ts @@ -0,0 +1,21 @@ +import { + API_LOAD_FONT_FACE, + API_TYPE_LOAD_FONT_FACE, + defineAsyncApi, + LoadFontFaceProtocol, +} from '@dcloudio/uni-api' +import { addFont } from '@dcloudio/uni-shared' + +export const loadFontFace = defineAsyncApi( + API_LOAD_FONT_FACE, + ({ family, source, desc }, { resolve, reject }) => { + addFont(family, source, desc) + .then(() => { + resolve() + }) + .catch((err) => { + reject(`loadFontFace:fail ${err}`) + }) + }, + LoadFontFaceProtocol +) diff --git a/packages/uni-shared/dist/uni-shared.cjs.js b/packages/uni-shared/dist/uni-shared.cjs.js index 8702ef3838483cc3262a87ffc5e0331d514074ae..a792b325f2cee8f7292171cacda6dfb8adb9dc20 100644 --- a/packages/uni-shared/dist/uni-shared.cjs.js +++ b/packages/uni-shared/dist/uni-shared.cjs.js @@ -19,6 +19,31 @@ function normalizeTarget(el) { offsetTop, offsetLeft, }; +} +function addFont(family, source, desc) { + const fonts = document.fonts; + if (fonts) { + const fontFace = new FontFace(family, source, desc); + return fontFace.load().then(() => { + fonts.add(fontFace); + }); + } + return new Promise((resolve) => { + const style = document.createElement('style'); + const values = []; + if (desc) { + const { style, weight, stretch, unicodeRange, variant, featureSettings, } = desc; + style && values.push(`font-style:${style}`); + weight && values.push(`font-weight:${weight}`); + stretch && values.push(`font-stretch:${stretch}`); + unicodeRange && values.push(`unicode-range:${unicodeRange}`); + variant && values.push(`font-variant:${variant}`); + featureSettings && values.push(`font-feature-settings:${featureSettings}`); + } + style.innerText = `@font-face{font-family:"${family}";src:${source};${values.join(';')}}`; + document.head.appendChild(style); + resolve(); + }); } function plusReady(callback) { @@ -247,6 +272,7 @@ exports.PRIMARY_COLOR = PRIMARY_COLOR; exports.RESPONSIVE_MIN_WIDTH = RESPONSIVE_MIN_WIDTH; exports.TABBAR_HEIGHT = TABBAR_HEIGHT; exports.TAGS = TAGS; +exports.addFont = addFont; exports.debounce = debounce; exports.decode = decode; exports.decodedQuery = decodedQuery; diff --git a/packages/uni-shared/dist/uni-shared.d.ts b/packages/uni-shared/dist/uni-shared.d.ts index 1d68f13202a3046dc38c20f28a765371a65c4f4d..beeff4bb7b6edd0ce1ca202fab958d9b3b2aa05a 100644 --- a/packages/uni-shared/dist/uni-shared.d.ts +++ b/packages/uni-shared/dist/uni-shared.d.ts @@ -1,3 +1,6 @@ +import { FontFaceDescriptors } from 'css-font-loading-module'; + +export declare function addFont(family: string, source: string, desc?: FontFaceDescriptors): Promise; export declare const BUILT_IN_TAGS: string[]; diff --git a/packages/uni-shared/dist/uni-shared.esm.js b/packages/uni-shared/dist/uni-shared.esm.js index f9070617f7511389708affd55ef2784852727a4a..9b9044591e971ea8a1899b0875b211a7bc09e8c4 100644 --- a/packages/uni-shared/dist/uni-shared.esm.js +++ b/packages/uni-shared/dist/uni-shared.esm.js @@ -15,6 +15,31 @@ function normalizeTarget(el) { offsetTop, offsetLeft, }; +} +function addFont(family, source, desc) { + const fonts = document.fonts; + if (fonts) { + const fontFace = new FontFace(family, source, desc); + return fontFace.load().then(() => { + fonts.add(fontFace); + }); + } + return new Promise((resolve) => { + const style = document.createElement('style'); + const values = []; + if (desc) { + const { style, weight, stretch, unicodeRange, variant, featureSettings, } = desc; + style && values.push(`font-style:${style}`); + weight && values.push(`font-weight:${weight}`); + stretch && values.push(`font-stretch:${stretch}`); + unicodeRange && values.push(`unicode-range:${unicodeRange}`); + variant && values.push(`font-variant:${variant}`); + featureSettings && values.push(`font-feature-settings:${featureSettings}`); + } + style.innerText = `@font-face{font-family:"${family}";src:${source};${values.join(';')}}`; + document.head.appendChild(style); + resolve(); + }); } function plusReady(callback) { @@ -233,4 +258,4 @@ const RESPONSIVE_MIN_WIDTH = 768; const COMPONENT_NAME_PREFIX = 'VUni'; const PRIMARY_COLOR = '#007aff'; -export { BUILT_IN_TAGS, COMPONENT_NAME_PREFIX, COMPONENT_PREFIX, COMPONENT_SELECTOR_PREFIX, NAVBAR_HEIGHT, PLUS_RE, PRIMARY_COLOR, RESPONSIVE_MIN_WIDTH, TABBAR_HEIGHT, TAGS, debounce, decode, decodedQuery, getLen, invokeArrayFns, isBuiltInComponent, isCustomElement, isNativeTag, normalizeDataset, normalizeTarget, once, parseQuery, passive, plusReady, removeLeadingSlash, stringifyQuery, updateElementStyle }; +export { BUILT_IN_TAGS, COMPONENT_NAME_PREFIX, COMPONENT_PREFIX, COMPONENT_SELECTOR_PREFIX, NAVBAR_HEIGHT, PLUS_RE, PRIMARY_COLOR, RESPONSIVE_MIN_WIDTH, TABBAR_HEIGHT, TAGS, addFont, debounce, decode, decodedQuery, getLen, invokeArrayFns, isBuiltInComponent, isCustomElement, isNativeTag, normalizeDataset, normalizeTarget, once, parseQuery, passive, plusReady, removeLeadingSlash, stringifyQuery, updateElementStyle }; diff --git a/packages/uni-shared/src/dom.ts b/packages/uni-shared/src/dom.ts index 3570d71757545bc4180db6b51963ba46f40af54d..d6b1ecfcf34efcbd7a1b617443cc58bb70ad1f51 100644 --- a/packages/uni-shared/src/dom.ts +++ b/packages/uni-shared/src/dom.ts @@ -1,3 +1,5 @@ +import { FontFaceDescriptors } from 'css-font-loading-module' + export function passive(passive: boolean) { return { passive } } @@ -16,3 +18,42 @@ export function normalizeTarget(el: HTMLElement) { offsetLeft, } } + +export function addFont( + family: string, + source: string, + desc?: FontFaceDescriptors +): Promise { + const fonts = document.fonts + if (fonts) { + const fontFace = new FontFace(family, source, desc) + return fontFace.load().then(() => { + fonts.add(fontFace) + }) + } + return new Promise((resolve) => { + const style = document.createElement('style') + const values = [] + if (desc) { + const { + style, + weight, + stretch, + unicodeRange, + variant, + featureSettings, + } = desc as FontFaceDescriptors + style && values.push(`font-style:${style}`) + weight && values.push(`font-weight:${weight}`) + stretch && values.push(`font-stretch:${stretch}`) + unicodeRange && values.push(`unicode-range:${unicodeRange}`) + variant && values.push(`font-variant:${variant}`) + featureSettings && values.push(`font-feature-settings:${featureSettings}`) + } + style.innerText = `@font-face{font-family:"${family}";src:${source};${values.join( + ';' + )}}` + document.head.appendChild(style) + resolve() + }) +} diff --git a/tsconfig.json b/tsconfig.json index 537b7524d31ac4123e1a3b7fb87a7c1975e0ef3e..90e19013e43b1fb692bf088127e73e2610ad371b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,7 +22,8 @@ "node", "@dcloudio/types", "vue", - "miniprogram-api-typings" + "miniprogram-api-typings", + "css-font-loading-module" ], "rootDir": ".", "paths": { diff --git a/yarn.lock b/yarn.lock index 0cf8a009a362a4c0536ec18db850db92b92f5fdf..ec121eb211de801868bde9858ec0b50b559505c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -767,6 +767,11 @@ dependencies: "@babel/types" "^7.3.0" +"@types/css-font-loading-module@^0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@types/css-font-loading-module/-/css-font-loading-module-0.0.4.tgz#94a835e27d1af444c65cba88523533c174463d64" + integrity sha512-ENdXf7MW4m9HeDojB2Ukbi7lYMIuQNBHVf98dbzaiG4EEJREBd6oleVAjrLRCrp7dm6CK1mmdmU9tcgF61acbw== + "@types/debug@^4.1.5": version "4.1.5" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd"