提交 f03c3e07 编写于 作者: fxy060608's avatar fxy060608

feat: add loadFontFace

上级 0fb61a2e
......@@ -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'
......
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<API_TYPE_PAGE_SCROLL_TO> = {
......@@ -11,20 +9,11 @@ export const PageScrollToProtocol: ApiProtocol<API_TYPE_PAGE_SCROLL_TO> = {
type: Number,
},
}
const DEFAULT_DURATION = 400
const DEFAULT_DURATION = 300
export const PageScrollToOptions: ApiOptions<API_TYPE_PAGE_SCROLL_TO> = {
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)
},
},
}
......@@ -35,7 +35,6 @@ const props = {
type ImageProps = ExtractPropTypes<typeof props>
type ImageState = ReturnType<typeof useImageState>
type FixSize = ReturnType<typeof useImageSize>['fixSize']
type ResetSize = ReturnType<typeof useImageSize>['resetSize']
const FIX_MODES = {
widthFix: ['width', 'height'],
......@@ -64,11 +63,10 @@ export default /*#__PURE__*/ defineComponent({
const rootRef = ref<HTMLElement | null>(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
......
......@@ -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
}
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};
......@@ -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'
......
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_TYPE_LOAD_FONT_FACE>(
API_LOAD_FONT_FACE,
({ family, source, desc }, { resolve, reject }) => {
addFont(family, source, desc)
.then(() => {
resolve()
})
.catch((err) => {
reject(`loadFontFace:fail ${err}`)
})
},
LoadFontFaceProtocol
)
......@@ -20,6 +20,31 @@ function normalizeTarget(el) {
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) {
if (typeof callback !== 'function') {
......@@ -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;
......
import { FontFaceDescriptors } from 'css-font-loading-module';
export declare function addFont(family: string, source: string, desc?: FontFaceDescriptors): Promise<void>;
export declare const BUILT_IN_TAGS: string[];
......
......@@ -16,6 +16,31 @@ function normalizeTarget(el) {
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) {
if (typeof callback !== 'function') {
......@@ -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 };
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<void> {
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()
})
}
......@@ -22,7 +22,8 @@
"node",
"@dcloudio/types",
"vue",
"miniprogram-api-typings"
"miniprogram-api-typings",
"css-font-loading-module"
],
"rootDir": ".",
"paths": {
......
......@@ -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"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册