diff --git a/packages/uni-api/src/service/context/canvas.ts b/packages/uni-api/src/service/context/canvas.ts index 4e5a606bb6856b2d990fa876804eb75a97ffab86..3d2445070e2ac82f3d8fc6c3de07347da5cbf18c 100644 --- a/packages/uni-api/src/service/context/canvas.ts +++ b/packages/uni-api/src/service/context/canvas.ts @@ -43,31 +43,27 @@ import { TEMP_PATH } from '@dcloudio/uni-platform' //#region UniServiceJSBridge const canvasEventCallbacks = createCallbacks('canvasEvent') -const onCanvasMethodCallback = /*#__PURE__*/ once(() => { - UniServiceJSBridge.subscribe( - 'onCanvasMethodCallback', - ({ callbackId, data }: { callbackId: number | string; data: any }) => { - const callback = canvasEventCallbacks.pop(callbackId) - if (callback) { - callback(data) - } - } - ) -}) - function operateCanvas( canvasId: string, pageId: number, type: unknown, data: any ) { - UniServiceJSBridge.publishHandler( - 'canvas.' + canvasId, + UniServiceJSBridge.invokeViewMethod< + {}, + { callbackId: number | string; data: any } + >( + `canvas.${canvasId}`, { - canvasId, type, data, }, + ({ callbackId, data }) => { + const callback = canvasEventCallbacks.pop(callbackId) + if (callback) { + callback(data) + } + }, pageId ) } @@ -1046,7 +1042,7 @@ export const canvasGetImageData = defineAsyncApi( API_CANVAS_GET_IMAGE_DATA, ({ canvasId, x, y, width, height }, { resolve, reject }) => { - onCanvasMethodCallback() + // onCanvasMethodCallback() const pageId = getPageIdByVm(getCurrentPageVm()!)! if (!pageId) { reject() @@ -1085,7 +1081,7 @@ export const canvasPutImageData = defineAsyncApi( API_CANVAS_PUT_IMAGE_DATA, ({ canvasId, data, x, y, width, height }, { resolve, reject }) => { - onCanvasMethodCallback() + // onCanvasMethodCallback() var pageId = getPageIdByVm(getCurrentPageVm()!)! if (!pageId) { reject() @@ -1144,7 +1140,7 @@ export const canvasToTempFilePath = }, { resolve, reject } ) => { - onCanvasMethodCallback() + // onCanvasMethodCallback() var pageId = getPageIdByVm(getCurrentPageVm()!)! if (!pageId) { reject() diff --git a/packages/uni-components/src/components/canvas/index.tsx b/packages/uni-components/src/components/canvas/index.tsx index c652911385a2c40693d944dcf347c7e3b044a975..de10e81468d20e5260a310f160c1058920e74ed5 100644 --- a/packages/uni-components/src/components/canvas/index.tsx +++ b/packages/uni-components/src/components/canvas/index.tsx @@ -8,7 +8,7 @@ import { withWebEvent, defineBuiltInComponent, } from '@dcloudio/uni-components' -import { getCurrentPageId, onEventPrevent } from '@dcloudio/uni-core' +import { onEventPrevent } from '@dcloudio/uni-core' import { saveImage, getSameOriginUrl, @@ -67,6 +67,11 @@ const props = { } type Props = ExtractPropTypes +type triggerMethodsName = + | 'actionsChanged' + | 'getImageData' + | 'putImageData' + | 'toTempFilePath' export default /*#__PURE__*/ defineBuiltInComponent({ inheritAttrs: false, @@ -94,11 +99,20 @@ export default /*#__PURE__*/ defineBuiltInComponent({ const { _handleSubscribe, _resize } = useMethods(canvas, actionsWaiting) useSubscribe( - _handleSubscribe as (type: string, data: unknown) => void, + _handleSubscribe as ( + type: string, + data: unknown, + resolve: (res: any) => void + ) => void, useContextInfo(props.canvasId), true ) + /* registerViewMethod< + { type: triggerMethodsName; data: any }, + { callbackId: number; data: any } + >(getCurrentPageId(), `canvas.${props.canvasId}`, _handleSubscribe) */ + onMounted(() => { _resize() }) @@ -214,15 +228,18 @@ function useMethods( wrapper(canvas) } } - function actionsChanged({ - actions, - reserve, - callbackId, - }: { - actions: Actions - reserve: boolean - callbackId: number - }) { + function actionsChanged( + { + actions, + reserve, + callbackId, + }: { + actions: Actions + reserve: boolean + callbackId: number + }, + resolve: (res: { callbackId: number; data: any }) => void + ) { if (!actions) { return } @@ -284,6 +301,7 @@ function useMethods( data[1] as string, actions.slice(index + 1), callbackId, + resolve, function (image) { if (image) { c2d[method1] = c2d.createPattern(image, data[2] as string)! @@ -357,6 +375,7 @@ function useMethods( url, actions.slice(index + 1), callbackId, + resolve, function (image) { if (image) { c2d.drawImage.apply( @@ -391,16 +410,12 @@ function useMethods( } } if (!actionsWaiting.value && callbackId) { - UniViewJSBridge.publishHandler( - 'onCanvasMethodCallback', - { - callbackId, - data: { - errMsg: 'drawCanvas:ok', - }, + resolve({ + callbackId, + data: { + errMsg: 'drawCanvas:ok', }, - getCurrentPageId() - ) + }) } } function preloadImage(actions: Actions) { @@ -453,6 +468,7 @@ function useMethods( src: string, actions: Actions, callbackId: number, + resolve: (res: { callbackId: number; data: any }) => void, fn: (a: CanvasImageSource) => void ) { var image = _images[src] @@ -469,42 +485,48 @@ function useMethods( var actions = _actionsDefer.slice(0) _actionsDefer = [] for (var action = actions.shift(); action; ) { - actionsChanged({ - actions: action[0], - reserve: action[1], - callbackId, - }) + actionsChanged( + { + callbackId, + actions: action[0], + reserve: action[1], + }, + resolve + ) action = actions.shift() } } return false } } - function getImageData({ - x = 0, - y = 0, - width, - height, - destWidth, - destHeight, - hidpi = true, - dataType, - quality = 1, - type = 'png', - callbackId, - }: { - x: number - y: number - width: number - height: number - destWidth: number - destHeight: number - hidpi: boolean - dataType: string - quality: number - type: string - callbackId?: number - }) { + function getImageData( + { + x = 0, + y = 0, + width, + height, + destWidth, + destHeight, + hidpi = true, + dataType, + quality = 1, + type = 'png', + callbackId, + }: { + x: number + y: number + width: number + height: number + destWidth: number + destHeight: number + hidpi: boolean + dataType: string + quality: number + type: string + callbackId?: number + }, + resolve?: (res: { callbackId: number; data: any }) => void + ) { const canvas = canvasRef.value! let data: string | number[] const maxWidth = canvas.offsetWidth - x @@ -580,33 +602,33 @@ function useMethods( if (!callbackId) { return result } else { - UniViewJSBridge.publishHandler( - 'onCanvasMethodCallback', - { + resolve && + resolve({ callbackId, data: result, - }, - getCurrentPageId() - ) + }) } } - function putImageData({ - data, - x, - y, - width, - height, - compressed, - callbackId, - }: { - data: Array - x: number - y: number - width: number - height: number - compressed: boolean - callbackId: number - }) { + function putImageData( + { + data, + x, + y, + width, + height, + compressed, + callbackId, + }: { + data: Array + x: number + y: number + width: number + height: number + compressed: boolean + callbackId: number + }, + resolve: (res: { callbackId: number; data: any }) => void + ) { try { if (!height) { height = Math.round(data.length / 4 / width) @@ -625,52 +647,47 @@ function useMethods( canvasRef.value!.getContext('2d')!.drawImage(canvas, x, y, width, height) canvas.height = canvas.width = 0 } catch (error) { - UniViewJSBridge.publishHandler( - 'onCanvasMethodCallback', - { - callbackId, - data: { - errMsg: 'canvasPutImageData:fail', - }, - }, - getCurrentPageId() - ) - return - } - UniViewJSBridge.publishHandler( - 'onCanvasMethodCallback', - { + resolve({ callbackId, data: { - errMsg: 'canvasPutImageData:ok', + errMsg: 'canvasPutImageData:fail', }, + }) + return + } + resolve({ + callbackId, + data: { + errMsg: 'canvasPutImageData:ok', }, - getCurrentPageId() - ) + }) } - function toTempFilePath({ - x = 0, - y = 0, - width, - height, - destWidth, - destHeight, - fileType, - quality, - dirname, - callbackId, - }: { - x: number - y: number - width: number - height: number - destWidth: number - destHeight: number - fileType: string - quality: number - dirname: string - callbackId: number - }) { + function toTempFilePath( + { + x = 0, + y = 0, + width, + height, + destWidth, + destHeight, + fileType, + quality, + dirname, + callbackId, + }: { + x: number + y: number + width: number + height: number + destWidth: number + destHeight: number + fileType: string + quality: number + dirname: string + callbackId: number + }, + resolve: (res: { callbackId: number; data: any }) => void + ) { const res = getImageData({ x, y, @@ -684,16 +701,12 @@ function useMethods( quality, })! if (!res.data || !res.data.length) { - UniViewJSBridge.publishHandler( - 'onCanvasMethodCallback', - { - callbackId, - data: { - errMsg: res!.errMsg.replace('canvasPutImageData', 'toTempFilePath'), - }, + resolve({ + callbackId, + data: { + errMsg: res!.errMsg.replace('canvasPutImageData', 'toTempFilePath'), }, - getCurrentPageId() - ) + }) return } saveImage(res.data as string, dirname, (error, tempFilePath) => { @@ -701,17 +714,13 @@ function useMethods( if (error) { errMsg += ` ${error.message}` } - UniViewJSBridge.publishHandler( - 'onCanvasMethodCallback', - { - callbackId, - data: { - errMsg, - tempFilePath: tempFilePath, - }, + resolve({ + callbackId, + data: { + errMsg, + tempFilePath: tempFilePath, }, - getCurrentPageId() - ) + }) }) } @@ -722,10 +731,14 @@ function useMethods( toTempFilePath, } - function _handleSubscribe(type: keyof typeof methods, data = {}) { + function _handleSubscribe( + type: triggerMethodsName, + data: any, + resolve: (res: { callbackId: number; data: any }) => void + ) { let method = methods[type] if (type.indexOf('_') !== 0 && typeof method === 'function') { - method(data as any) + method(data as any, resolve) } } diff --git a/packages/uni-components/src/components/editor/quill/index.ts b/packages/uni-components/src/components/editor/quill/index.ts index 2070827fe4a728fd339261df5245194e9a30657e..3d4c655e5a6da30984cc6cb61e7cea23014c77de 100644 --- a/packages/uni-components/src/components/editor/quill/index.ts +++ b/packages/uni-components/src/components/editor/quill/index.ts @@ -6,9 +6,8 @@ import QuillClass, { RangeStatic, StringMap, } from 'quill' -import { useContextInfo } from '@dcloudio/uni-components' +import { useContextInfo, useSubscribe } from '@dcloudio/uni-components' import { getRealPath } from '@dcloudio/uni-platform' -import { getCurrentPageId, registerViewMethod } from '@dcloudio/uni-core' import { CustomEventTrigger } from '../../../helpers/useEvent' import HTMLParser from '../../../helpers/html-parser' import loadScript from './loadScript' @@ -56,7 +55,6 @@ interface WindowExt extends Window { export function useQuill( props: { - id: string readOnly?: any placeholder?: any showImgSize?: any @@ -257,169 +255,168 @@ export function useQuill( } }) }) - registerViewMethod< - { - type: string - data: { callbackId?: string; options: any } - }, - { callbackId: string; data: any } - >(getCurrentPageId(), `editor.${props.id}`, ({ type, data }, resolve) => { - const { options, callbackId } = data - let res - let range: RangeStatic | undefined - let errMsg - if (quillReady) { - const Quill = (window as WindowExt).Quill as typeof QuillClass - switch (type) { - case 'format': - { - let { name = '', value = false } = options - range = quill.getSelection(true) - let format = quill.getFormat(range)[name] || false - if ( - ['bold', 'italic', 'underline', 'strike', 'ins'].includes(name) - ) { - value = !format - } else if (name === 'direction') { - value = value === 'rtl' && format ? false : value - const align = quill.getFormat(range).align - if (value === 'rtl' && !align) { - quill.format('align', 'right', 'user') - } else if (!value && align === 'right') { - quill.format('align', false, 'user') - } - } else if (name === 'indent') { - const rtl = quill.getFormat(range).direction === 'rtl' - value = value === '+1' - if (rtl) { - value = !value - } - value = value ? '+1' : '-1' - } else { - if (name === 'list') { - value = value === 'check' ? 'unchecked' : value - format = format === 'checked' ? 'unchecked' : format + const id = useContextInfo() + useSubscribe<{ callbackId: string; data: any }>( + (type, data: any, resolve) => { + const { options, callbackId } = data + let res + let range: RangeStatic | undefined + let errMsg + if (quillReady) { + const Quill = (window as WindowExt).Quill as typeof QuillClass + switch (type) { + case 'format': + { + let { name = '', value = false } = options + range = quill.getSelection(true) + let format = quill.getFormat(range)[name] || false + if ( + ['bold', 'italic', 'underline', 'strike', 'ins'].includes(name) + ) { + value = !format + } else if (name === 'direction') { + value = value === 'rtl' && format ? false : value + const align = quill.getFormat(range).align + if (value === 'rtl' && !align) { + quill.format('align', 'right', 'user') + } else if (!value && align === 'right') { + quill.format('align', false, 'user') + } + } else if (name === 'indent') { + const rtl = quill.getFormat(range).direction === 'rtl' + value = value === '+1' + if (rtl) { + value = !value + } + value = value ? '+1' : '-1' + } else { + if (name === 'list') { + value = value === 'check' ? 'unchecked' : value + format = format === 'checked' ? 'unchecked' : format + } + value = + (format && format !== (value || false)) || (!format && value) + ? value + : !format } - value = - (format && format !== (value || false)) || (!format && value) - ? value - : !format + quill.format(name, value, 'user') } - quill.format(name, value, 'user') - } - break - case 'insertDivider': - range = quill.getSelection(true) - quill.insertText(range.index, '\n', 'user') - quill.insertEmbed(range.index + 1, 'divider', true, 'user') - quill.setSelection(range.index + 2, 0, 'silent') - break - case 'insertImage': - { - range = quill.getSelection(true) - const { - src = '', - alt = '', - width = '', - height = '', - extClass = '', - data = {}, - } = options - const path = getRealPath(src) - quill.insertEmbed(range.index, 'image', path, 'user') - const local = /^(file|blob):/.test(path) ? path : false - textChanging = true - quill.formatText(range.index, 1, 'data-local', local) - quill.formatText(range.index, 1, 'alt', alt) - quill.formatText(range.index, 1, 'width', width) - quill.formatText(range.index, 1, 'height', height) - quill.formatText(range.index, 1, 'class', extClass) - textChanging = false - quill.formatText( - range.index, - 1, - 'data-custom', - Object.keys(data) - .map((key) => `${key}=${data[key]}`) - .join('&') - ) - quill.setSelection(range.index + 1, 0, 'silent') - } - break - case 'insertText': - { + break + case 'insertDivider': range = quill.getSelection(true) - const { text = '' } = options - quill.insertText(range.index, text, 'user') - quill.setSelection(range.index + text.length, 0, 'silent') - } - break - case 'setContents': - { - const { delta, html } = options - if (typeof delta === 'object') { - quill.setContents(delta, 'silent') - } else if (typeof html === 'string') { - quill.setContents(html2delta(html), 'silent') - } else { - errMsg = 'contents is missing' + quill.insertText(range.index, '\n', 'user') + quill.insertEmbed(range.index + 1, 'divider', true, 'user') + quill.setSelection(range.index + 2, 0, 'silent') + break + case 'insertImage': + { + range = quill.getSelection(true) + const { + src = '', + alt = '', + width = '', + height = '', + extClass = '', + data = {}, + } = options + const path = getRealPath(src) + quill.insertEmbed(range.index, 'image', path, 'user') + const local = /^(file|blob):/.test(path) ? path : false + textChanging = true + quill.formatText(range.index, 1, 'data-local', local) + quill.formatText(range.index, 1, 'alt', alt) + quill.formatText(range.index, 1, 'width', width) + quill.formatText(range.index, 1, 'height', height) + quill.formatText(range.index, 1, 'class', extClass) + textChanging = false + quill.formatText( + range.index, + 1, + 'data-custom', + Object.keys(data) + .map((key) => `${key}=${data[key]}`) + .join('&') + ) + quill.setSelection(range.index + 1, 0, 'silent') } - } - break - case 'getContents': - res = getContents() - break - case 'clear': - quill.setText('') - break - case 'removeFormat': - { - range = quill.getSelection(true) - const parchment = Quill.import('parchment') - if (range.length) { - quill.removeFormat(range.index, range.length, 'user') - } else { - Object.keys(quill.getFormat(range)).forEach((key) => { - if (parchment.query(key, parchment.Scope.INLINE)) { - quill.format(key, false) - } - }) + break + case 'insertText': + { + range = quill.getSelection(true) + const { text = '' } = options + quill.insertText(range.index, text, 'user') + quill.setSelection(range.index + text.length, 0, 'silent') } - } - break - case 'undo': - quill.history.undo() - break - case 'redo': - quill.history.redo() - break - case 'blur': - quill.blur() - break - case 'getSelectionText': - range = quill.selection.savedRange - res = { text: '' } - if (range && range.length !== 0) { - res.text = quill.getText(range.index, range.length) - } - break - case 'scrollIntoView': - quill.scrollIntoView() - break - default: - break + break + case 'setContents': + { + const { delta, html } = options + if (typeof delta === 'object') { + quill.setContents(delta, 'silent') + } else if (typeof html === 'string') { + quill.setContents(html2delta(html), 'silent') + } else { + errMsg = 'contents is missing' + } + } + break + case 'getContents': + res = getContents() + break + case 'clear': + quill.setText('') + break + case 'removeFormat': + { + range = quill.getSelection(true) + const parchment = Quill.import('parchment') + if (range.length) { + quill.removeFormat(range.index, range.length, 'user') + } else { + Object.keys(quill.getFormat(range)).forEach((key) => { + if (parchment.query(key, parchment.Scope.INLINE)) { + quill.format(key, false) + } + }) + } + } + break + case 'undo': + quill.history.undo() + break + case 'redo': + quill.history.redo() + break + case 'blur': + quill.blur() + break + case 'getSelectionText': + range = quill.selection.savedRange + res = { text: '' } + if (range && range.length !== 0) { + res.text = quill.getText(range.index, range.length) + } + break + case 'scrollIntoView': + quill.scrollIntoView() + break + default: + break + } + updateStatus(range) + } else { + errMsg = 'not ready' } - updateStatus(range) - } else { - errMsg = 'not ready' - } - if (callbackId) { - resolve({ - callbackId, - data: extend({}, res, { - errMsg: `${type}:${errMsg ? 'fail ' + errMsg : 'ok'}`, - }), - }) - } - }) + if (callbackId) { + resolve({ + callbackId, + data: extend({}, res, { + errMsg: `${type}:${errMsg ? 'fail ' + errMsg : 'ok'}`, + }), + }) + } + }, + id, + true + ) } diff --git a/packages/uni-components/src/helpers/useContextInfo.ts b/packages/uni-components/src/helpers/useContextInfo.ts index 86a2caddd6991bca973f854539a98d3f0521804e..0eaa0ac5776d400e8abec6d6388c882b0566f639 100644 --- a/packages/uni-components/src/helpers/useContextInfo.ts +++ b/packages/uni-components/src/helpers/useContextInfo.ts @@ -27,7 +27,7 @@ export function useContextInfo(_id?: string) { page, } }) - return `${page}.${type}.${id}` + return `${type}.${id}` } export function getContextInfo(el: HTMLElement | HTMLElementWithContextInfo) { return (el as HTMLElementWithContextInfo).__uniContextInfo diff --git a/packages/uni-components/src/helpers/useSubscribe.ts b/packages/uni-components/src/helpers/useSubscribe.ts index 0d714086aa269bbbc15f352ac7cfb751f7e77a15..ffe5788fd7051eff449d7ab3809aa7edec62c49b 100644 --- a/packages/uni-components/src/helpers/useSubscribe.ts +++ b/packages/uni-components/src/helpers/useSubscribe.ts @@ -5,30 +5,41 @@ import { getCurrentInstance, ComponentPublicInstance, } from 'vue' -import { useCurrentPageId } from '@dcloudio/uni-core' +import { + getCurrentPageId, + registerViewMethod, + unregisterViewMethod, +} from '@dcloudio/uni-core' -function normalizeEvent( - pageId: number, - vm: ComponentPublicInstance, - id?: string -) { +type SubscribeCallbackRes = ( + type: string, + data: unknown, + resolve: (res: Res) => void +) => void + +function normalizeEvent(vm: ComponentPublicInstance, id?: string) { if (!id) { id = (vm as any).id } if (!id) { return } - return pageId + '.' + vm.$options.name!.toLowerCase() + '.' + id + return vm.$options.name!.toLowerCase() + '.' + id } -function addSubscribe(name: string, callback: Function) { +function addSubscribe(name: string, callback: SubscribeCallbackRes) { if (!name) { return } - UniViewJSBridge.subscribe( + + registerViewMethod( + getCurrentPageId(), name, - ({ type, data }: { type: string; data: unknown }) => { - callback(type, data) + ( + { type, data }: { type: string; data: unknown }, + resolve: Parameters[2] + ) => { + callback(type, data, resolve) } ) } @@ -37,31 +48,30 @@ function removeSubscribe(name: string) { if (!name) { return } - UniViewJSBridge.unsubscribe(name) + unregisterViewMethod(getCurrentPageId(), name) } -export function useSubscribe( - callback: (type: string, data: unknown) => void, +export function useSubscribe( + callback: SubscribeCallbackRes, name?: string, multiple?: boolean ) { const instance = getCurrentInstance()! const vm = instance.proxy! - const pageId = multiple || !name ? useCurrentPageId() : 0 onMounted(() => { - addSubscribe(name || normalizeEvent(pageId, vm)!, callback) + addSubscribe(name || normalizeEvent(vm)!, callback) if (multiple || !name) { watch( () => (vm as any).id, (value, oldValue) => { - addSubscribe(normalizeEvent(pageId, vm, value)!, callback) - removeSubscribe(oldValue && normalizeEvent(pageId, vm, oldValue)!) + addSubscribe(normalizeEvent(vm, value)!, callback) + removeSubscribe(oldValue && normalizeEvent(vm, oldValue)!) } ) } }) onBeforeUnmount(() => { - removeSubscribe(name || normalizeEvent(pageId, vm)!) + removeSubscribe(name || normalizeEvent(vm)!) }) } diff --git a/packages/uni-core/src/view/bridge/index.ts b/packages/uni-core/src/view/bridge/index.ts index e18b0006d3378f4b3e123351c12d2fe2e1f1324c..6a3576ff2d1a30c41c146bfc76f0c9795df9e8a1 100644 --- a/packages/uni-core/src/view/bridge/index.ts +++ b/packages/uni-core/src/view/bridge/index.ts @@ -50,6 +50,11 @@ export function registerViewMethod( } } +export function unregisterViewMethod(pageId: number, name: string) { + name = normalizeViewMethodName(pageId, name) + delete viewMethods[name] +} + function onInvokeViewMethod( { id, diff --git a/packages/uni-core/src/view/index.ts b/packages/uni-core/src/view/index.ts index e5f010f8b6d926291e65a3880e82bd30ef636404..0a8b8afa2f3053bbe5944c72c60bdd85b2cba077 100644 --- a/packages/uni-core/src/view/index.ts +++ b/packages/uni-core/src/view/index.ts @@ -3,6 +3,7 @@ export { subscribeViewMethod, unsubscribeViewMethod, registerViewMethod, + unregisterViewMethod, } from './bridge' export { initView } from './init' export { initViewPlugin } from './plugin'