diff --git a/packages/canvas/DesignCanvas/src/DesignCanvas.vue b/packages/canvas/DesignCanvas/src/DesignCanvas.vue index e4bbe4708b..1c0d68d6af 100644 --- a/packages/canvas/DesignCanvas/src/DesignCanvas.vue +++ b/packages/canvas/DesignCanvas/src/DesignCanvas.vue @@ -206,6 +206,35 @@ export default { } })() + function updatePreviewId(previewId, replace = false) { + const url = new URL(window.location.href) + if (previewId) { + if (previewId === url.searchParams.get('previewid')) { + return + } + url.searchParams.set('previewid', previewId) + } else { + url.searchParams.delete('previewid') + } + if (replace) { + window.history.replaceState({}, '', url) + } else { + window.history.pushState({}, '', url) + } + usePage().postLocationHistoryChanged({ previewId }) + } + + // TODO: 待挪到 getBaseInfo + const postUrlChanged = () => { + usePage().postLocationHistoryChanged(Object.fromEntries(new URLSearchParams(window.location.search))) + } + onMounted(() => { + window.addEventListener('popstate', postUrlChanged) + }) + onUnmounted(() => { + window.removeEventListener('popstate', postUrlChanged) + }) + return { removeNode, canvasSrc, @@ -224,6 +253,7 @@ export default { getPageAncestors: usePage().getAncestors, getBaseInfo: () => getMetaApi(META_SERVICE.GlobalService).getBaseInfo(), addHistoryDataChangedCallback, + updatePreviewId, ast }, isBlock, diff --git a/packages/canvas/render/src/RenderMain.ts b/packages/canvas/render/src/RenderMain.ts index ff6a4e303f..3d46e587a8 100644 --- a/packages/canvas/render/src/RenderMain.ts +++ b/packages/canvas/render/src/RenderMain.ts @@ -23,6 +23,7 @@ import { api, setCurrentApi } from './canvas-function/canvas-api' import { getPageAncestors } from './material-function/page-getter' import CanvasEmpty from './canvas-function/CanvasEmpty.vue' import { setCurrentPage } from './canvas-function/page-switcher' +import { useRouterPreview } from './canvas-function/router-preview' const { BROADCAST_CHANNEL } = constants @@ -148,6 +149,7 @@ export default defineComponent({ pageContext.setCssScopeId(props.cssScopeId || (props.entry ? null : `data-te-page-${pageContext.pageId}`)) if (props.entry) { provide('page-ancestors', pageAncestors) + provide('page-preview', useRouterPreview().previewPath) getPageAncestors(pageContext.pageId).then((value) => { pageAncestors.value = value }) diff --git a/packages/canvas/render/src/canvas-function/custom-renderer.ts b/packages/canvas/render/src/canvas-function/custom-renderer.ts index 8b7ba8edfe..6f7ba9c7b5 100644 --- a/packages/canvas/render/src/canvas-function/custom-renderer.ts +++ b/packages/canvas/render/src/canvas-function/custom-renderer.ts @@ -6,6 +6,7 @@ function defaultRenderer(schema, refreshKey, entry, active, isPage = true) { // 渲染画布增加根节点,与出码和预览保持一致 const rootChildrenSchema = { componentName: 'div', + componentType: 'PageSection', // 手动添加一个唯一的属性,后续在画布选中此节点时方便处理额外的逻辑。由于没有修改schema,不会影响出码 props: { ...schema.props, 'data-id': 'root-container', 'data-page-active': active }, children: schema.children diff --git a/packages/canvas/render/src/canvas-function/router-preview.ts b/packages/canvas/render/src/canvas-function/router-preview.ts new file mode 100644 index 0000000000..c04b54ff99 --- /dev/null +++ b/packages/canvas/render/src/canvas-function/router-preview.ts @@ -0,0 +1,79 @@ +import { onUnmounted, ref } from 'vue' +import { getController } from './controller' +import { getPageAncestors } from '../material-function/page-getter' + +export function useRouterPreview() { + const pageId = ref(getController().getBaseInfo().pageId) + const previewId = ref(getController().getBaseInfo().previewId) + const updatePreviewId = getController().updatePreviewId + const previewFullPath = ref([]) + const previewPath = ref([]) + + async function calcNewPreviewFullPath() { + if (!pageId.value) { + if (previewId.value) { + updatePreviewId(undefined, true) + return + } + previewFullPath.value = [] + previewPath.value = [] + return + } + if (!previewId.value) { + previewFullPath.value = await getPageAncestors(pageId.value) + previewPath.value = [] + return + } + + if (previewFullPath.value[previewFullPath.value.length - 1] !== previewId.value) { + // previewId changed + const fullPath = await getPageAncestors(previewId.value) + if (fullPath.includes(pageId.value)) { + previewFullPath.value = fullPath + } else { + updatePreviewId(pageId.value, true) + } + } + + if (previewFullPath.value.includes(pageId.value)) { + // only pageId changed and fast move + const fastJumpIndex = previewFullPath.value.indexOf(pageId.value) + if (fastJumpIndex + 1 < previewFullPath.value.length) { + previewPath.value = previewFullPath.value.slice(fastJumpIndex + 1) + } else { + previewPath.value = [] + } + } else { + previewFullPath.value = await getPageAncestors(pageId.value) + previewPath.value = [] + updatePreviewId(pageId.value, true) + } + } + + const cancel = getController().addHistoryDataChangedCallback(() => { + const newPageId = getController().getBaseInfo().pageId + const newPreviewId = getController().getBaseInfo().previewId + const pageIdChanged = newPageId !== pageId.value + const previewIdChanged = newPreviewId !== previewId.value + if (pageIdChanged) { + pageId.value = newPageId + } + if (previewIdChanged) { + previewId.value = newPreviewId + } + if (previewIdChanged || pageIdChanged) { + calcNewPreviewFullPath() + } + }) + + onUnmounted(() => { + cancel() + }) + + calcNewPreviewFullPath() + + return { + previewPath, + previewFullPath + } +} diff --git a/packages/canvas/render/src/material-function/page-getter.ts b/packages/canvas/render/src/material-function/page-getter.ts index 3abced554a..c0650c074d 100644 --- a/packages/canvas/render/src/material-function/page-getter.ts +++ b/packages/canvas/render/src/material-function/page-getter.ts @@ -84,6 +84,10 @@ export async function getPageAncestors(pageId?: string) { // 如果不支持查询祖先 则返回自己 return [pageId] } - const pageChain = await getController().getPageAncestors(pageId) - return [...pageChain.map((id: number | string) => String(id)), pageId] + try { + const pageChain = await getController().getPageAncestors(pageId) + return [...pageChain.map((id: number | string) => String(id)), pageId] + } catch { + return [] + } } diff --git a/packages/canvas/render/src/render.ts b/packages/canvas/render/src/render.ts index e6c0afbaff..99c393dc99 100644 --- a/packages/canvas/render/src/render.ts +++ b/packages/canvas/render/src/render.ts @@ -77,7 +77,7 @@ const checkGroup = (componentName) => configure[componentName]?.nestingRule?.chi const clickCapture = (componentName) => configure[componentName]?.clickCapture !== false const getBindProps = (schema, scope, context, pageContext) => { - const { id, componentName } = schema + const { id, componentName, componentType } = schema const invalidity = configure[componentName]?.invalidity || [] if (componentName === 'CanvasPlaceholder') { @@ -88,7 +88,7 @@ const getBindProps = (schema, scope, context, pageContext) => { const bindProps = { ...parseData(schema.props, scope, context), ...(cssScopeId ? { [cssScopeId]: '' } : {}), - ...(active ? { [DESIGN_UIDKEY]: id } : {}), + ...(active && componentType !== 'PageSection' ? { [DESIGN_UIDKEY]: id } : {}), [DESIGN_TAGKEY]: componentName } @@ -115,7 +115,7 @@ const getBindProps = (schema, scope, context, pageContext) => { delete bindProps.className // 使画布中元素可拖拽 - if (active) { + if (active && componentType !== 'PageSection') { bindProps.draggable = true } @@ -205,13 +205,16 @@ const getChildren = (schema, mergeScope, pageContext) => { return parseData(renderChildren, mergeScope, pageContext.context) } } + function getRenderPageId(currentPageId, isPageStart) { const pagePathFromRoot = (inject('page-ancestors') as Ref).value + const pagePreviewFromCurrentPageChild = (inject('page-preview') as Ref).value + const fullPath = [...pagePathFromRoot, ...pagePreviewFromCurrentPageChild] function getNextChild(currentPageId) { - const index = pagePathFromRoot.indexOf(currentPageId) - if (index > -1 && index + 1 < pagePathFromRoot.length) { - return pagePathFromRoot[index + 1] + const index = fullPath.indexOf(currentPageId) + if (index > -1 && index + 1 < fullPath.length) { + return fullPath[index + 1] } return null } @@ -251,9 +254,18 @@ export const renderer = defineComponent({ if (ancestors.length && (isPageStart || isRouterView)) { const renderPageId = getRenderPageId(pageContext.pageId, isPageStart) if (renderPageId) { + if (pageContext.active && !isPageStart) { + pageContext.setNode(schema, parent) + } return h(getPage(renderPageId), { key: ancestors, - [DESIGN_TAGKEY]: `${componentName}` + [DESIGN_TAGKEY]: `${componentName}`, + ...(pageContext.active && !isPageStart + ? { + [DESIGN_UIDKEY]: schema.id, + draggable: true + } + : {}) }) } } diff --git a/packages/common/composable/defaultGlobalService.js b/packages/common/composable/defaultGlobalService.js index edb09983c1..9b38de54bc 100644 --- a/packages/common/composable/defaultGlobalService.js +++ b/packages/common/composable/defaultGlobalService.js @@ -6,6 +6,7 @@ const getBaseInfo = () => { const id = paramsMap.get('id') const blockId = paramsMap.get('blockid') const pageId = paramsMap.get('pageid') + const previewId = paramsMap.get('previewid') const type = paramsMap.get('type') const version = paramsMap.get('version') @@ -13,6 +14,7 @@ const getBaseInfo = () => { type: type || 'app', id, pageId, + previewId, blockId, version }