Skip to content
102 changes: 87 additions & 15 deletions packages/canvas/route-bar/src/CanvasRouteBar.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
<template>
<div id="canvas-route-bar" :style="sizeStyle">
<div class="address-bar">
<template v-for="route in routes" :key="route.id">
<template v-for="(route, index) in routes" :key="route.id">
<span class="slash">/</span>
<span :class="[{ route: route.isPage && route.id !== pageId }]" @click="handleClickRoute(route)">{{
route.route
}}</span>
<span
:class="[
{
route: route.isPage && route.id !== pageId,
bold: shouldHighlight(route.id, index),
'is-preview': route.isPreview
}
]"
@click="handleClickRoute(route)"
>{{ route.route }}</span
>
</template>
<tiny-tooltip v-if="existsPreview" type="normal" content="重置路由视图为占位符">
<svg-button name="cross" class="clear-preview" @click="handleClearPreview"></svg-button>
</tiny-tooltip>
</div>
</div>
</template>

<script setup>
import { SvgButton } from '@opentiny/tiny-engine-common'
import { getMetaApi, META_SERVICE, useLayout, useMessage, usePage } from '@opentiny/tiny-engine-meta-register'
import { Tooltip as TinyTooltip } from '@opentiny/vue'
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'

const sizeStyle = computed(() => {
Expand All @@ -22,7 +35,10 @@ const sizeStyle = computed(() => {

const { pageSettingState, getAncestors, switchPageWithConfirm } = usePage()

const pageId = ref(getMetaApi(META_SERVICE.GlobalService).getBaseInfo().pageId)
const baseInfo = getMetaApi(META_SERVICE.GlobalService).getBaseInfo()
const pageId = ref(baseInfo.pageId)
const previewId = ref(baseInfo.previewId)
const existsPreview = ref(false)

const { subscribe, unsubscribe } = useMessage()

Expand All @@ -33,7 +49,10 @@ onMounted(() => {
topic: 'locationHistoryChanged',
callback: (data) => {
if (data.pageId) {
pageId.value = data.pageId
pageId.value = String(data.pageId)
}
if ('previewId' in data) {
Comment thread
gene9831 marked this conversation as resolved.
previewId.value = String(data.previewId)
}
},
subscriber: 'routeBar'
Expand All @@ -51,38 +70,67 @@ onUnmounted(() => {
* @property {string | number} id
* @property {string} route
* @property {boolean} isPage
* @property {boolean} isPreview
*/

/** @type {import('vue').Ref<Route[]>} */
const routes = ref([])

watch(
pageId,
async (value) => {
if (!value) {
[pageId, previewId],
async ([pageId, previewId]) => {
if (!pageId) {
routes.value = []
return
}
const ancestors = (await getAncestors(value, true)) || []

let ancestors = ((await getAncestors(pageId, true)) || []).concat(pageId).map((id) => String(id))

if (previewId) {
const previewAncestors = ((await getAncestors(previewId, true)) || []).concat(previewId).map((id) => String(id))

// previewId是pageId的子孙,那么previewId才有效
if (previewAncestors.includes(pageId)) {
ancestors = previewAncestors
}
}

// currentPageIndex逻辑上不可能为-1,所以后续判断位于数组的位置时,不再需要判断是否为-1
const currentPageIndex = ancestors.indexOf(pageId)

// 如果当前编辑页面不是ancestors数组最后一个元素,说明存在preview页面
existsPreview.value = currentPageIndex < ancestors.length - 1

routes.value = ancestors
.concat(value)
.map((id) => pageSettingState.treeDataMapping[id])
.filter((item) => Boolean(item))
.map((pageData) => {
.map((pageData, index) => {
const { id, route, isPage } = pageData
return {
id,
id: String(id),
route: route
.replace(/\/+/g, '/') // 替换连续的 '/' 为单个 '/'
.replace(/^\/|\/$/g, ''), // 去掉开头和结尾的 '/'
isPage
isPage,
isPreview: index > currentPageIndex
}
})
},
{ immediate: true }
)

const shouldHighlight = (id, index) => {
if (existsPreview.value) {
return id === pageId.value
}

// 没有previewId时,routes长度大于1,最后一个route path显示高亮
if (routes.value.length > 1) {
return index === routes.value.length - 1
}

return false
}

/**
* @param route {Route}
*/
Expand All @@ -92,6 +140,10 @@ const handleClickRoute = (route) => {
}
switchPageWithConfirm(route.id)
}

const handleClearPreview = () => {
getMetaApi(META_SERVICE.GlobalService).updatePreviewId('')
}
</script>

<style lang="less" scoped>
Expand Down Expand Up @@ -125,4 +177,24 @@ const handleClickRoute = (route) => {
color: var(--te-common-text-link);
}
}
.slash {
margin: 0 2px;
}
.bold {
font-weight: var(--te-base-font-weight-bold);
}
.is-preview {
color: var(--te-common-text-weaken);
}
#canvas-route-bar:hover .clear-preview {
visibility: visible;
}
.clear-preview {
border-radius: 50%;
visibility: hidden;
margin-left: 2px;
width: 16px;
height: 16px;
font-size: 12px;
}
</style>