fix: 修复路由缺少 name 和带有动态参数时菜单搜索功能异常问题
This commit is contained in:
parent
5f0e91c5ec
commit
4a27131c6d
@ -28,7 +28,7 @@ const searchResultRef = ref<InstanceType<typeof SearchResult> | null>(null)
|
|||||||
|
|
||||||
const keyword = ref<string>("")
|
const keyword = ref<string>("")
|
||||||
const resultList = shallowRef<RouteRecordRaw[]>([])
|
const resultList = shallowRef<RouteRecordRaw[]>([])
|
||||||
const activeRouteName = ref<RouteRecordName>("")
|
const activeRouteName = ref<RouteRecordName | undefined>(undefined)
|
||||||
/** 是否按下了上键或下键(用于解决和 mouseenter 事件的冲突) */
|
/** 是否按下了上键或下键(用于解决和 mouseenter 事件的冲突) */
|
||||||
const isPressUpOrDown = ref<boolean>(false)
|
const isPressUpOrDown = ref<boolean>(false)
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ const handleSearch = debounce(() => {
|
|||||||
)
|
)
|
||||||
// 默认选中搜索结果的第一项
|
// 默认选中搜索结果的第一项
|
||||||
const length = resultList.value?.length
|
const length = resultList.value?.length
|
||||||
activeRouteName.value = length > 0 ? resultList.value[0].name! : ""
|
activeRouteName.value = length > 0 ? resultList.value[0].name : undefined
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|
||||||
/** 将树形菜单扁平化为一维数组,用于菜单搜索 */
|
/** 将树形菜单扁平化为一维数组,用于菜单搜索 */
|
||||||
@ -89,13 +89,22 @@ const handleUp = () => {
|
|||||||
isPressUpOrDown.value = true
|
isPressUpOrDown.value = true
|
||||||
const { length } = resultList.value
|
const { length } = resultList.value
|
||||||
if (length === 0) return
|
if (length === 0) return
|
||||||
|
// 获取该 name 在菜单中第一次出现的位置
|
||||||
const index = resultList.value.findIndex((item) => item.name === activeRouteName.value)
|
const index = resultList.value.findIndex((item) => item.name === activeRouteName.value)
|
||||||
|
// 如果已处在顶部
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
// 如果已处在顶部,跳转到底部
|
const bottomName = resultList.value[length - 1].name
|
||||||
activeRouteName.value = resultList.value[length - 1].name!
|
// 如果顶部和底部的 bottomName 相同,且长度大于 1,就再跳一个位置(可解决遇到首尾两个相同 name 导致的上键不能生效的问题)
|
||||||
scrollTo(resultList.value.length - 1)
|
if (activeRouteName.value === bottomName && length > 1) {
|
||||||
|
activeRouteName.value = resultList.value[length - 2].name
|
||||||
|
scrollTo(length - 2)
|
||||||
|
} else {
|
||||||
|
// 跳转到底部
|
||||||
|
activeRouteName.value = bottomName
|
||||||
|
scrollTo(length - 1)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
activeRouteName.value = resultList.value[index - 1].name!
|
activeRouteName.value = resultList.value[index - 1].name
|
||||||
scrollTo(index - 1)
|
scrollTo(index - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,13 +114,22 @@ const handleDown = () => {
|
|||||||
isPressUpOrDown.value = true
|
isPressUpOrDown.value = true
|
||||||
const { length } = resultList.value
|
const { length } = resultList.value
|
||||||
if (length === 0) return
|
if (length === 0) return
|
||||||
const index = resultList.value.findIndex((item) => item.name === activeRouteName.value)
|
// 获取该 name 在菜单中最后一次出现的位置(可解决遇到连续两个相同 name 导致的下键不能生效的问题)
|
||||||
|
const index = resultList.value.map((item) => item.name).lastIndexOf(activeRouteName.value)
|
||||||
|
// 如果已处在底部
|
||||||
if (index === length - 1) {
|
if (index === length - 1) {
|
||||||
// 如果已处在底部,跳转到顶部
|
const topName = resultList.value[0].name
|
||||||
activeRouteName.value = resultList.value[0].name!
|
// 如果底部和顶部的 topName 相同,且长度大于 1,就再跳一个位置(可解决遇到首尾两个相同 name 导致的下键不能生效的问题)
|
||||||
scrollTo(0)
|
if (activeRouteName.value === topName && length > 1) {
|
||||||
|
activeRouteName.value = resultList.value[1].name
|
||||||
|
scrollTo(1)
|
||||||
|
} else {
|
||||||
|
// 跳转到顶部
|
||||||
|
activeRouteName.value = topName
|
||||||
|
scrollTo(0)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
activeRouteName.value = resultList.value[index + 1].name!
|
activeRouteName.value = resultList.value[index + 1].name
|
||||||
scrollTo(index + 1)
|
scrollTo(index + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,11 +138,17 @@ const handleDown = () => {
|
|||||||
const handleEnter = () => {
|
const handleEnter = () => {
|
||||||
const { length } = resultList.value
|
const { length } = resultList.value
|
||||||
if (length === 0) return
|
if (length === 0) return
|
||||||
if (!activeRouteName.value) {
|
const name = activeRouteName.value
|
||||||
ElMessage.error("无法通过搜索功能进入该菜单,请为对应的路由设置唯一的 Name")
|
if (!name) {
|
||||||
|
ElMessage.warning("无法通过搜索进入该菜单,请为对应的路由设置唯一的 Name")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
router.push({ name })
|
||||||
|
} catch {
|
||||||
|
ElMessage.error("该菜单有必填的动态参数,无法通过搜索进入")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
router.push({ name: activeRouteName.value })
|
|
||||||
handleClose()
|
handleClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,14 +3,14 @@ import { computed, getCurrentInstance, onBeforeMount, onBeforeUnmount, onMounted
|
|||||||
import { type RouteRecordName, type RouteRecordRaw } from "vue-router"
|
import { type RouteRecordName, type RouteRecordRaw } from "vue-router"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
modelValue: RouteRecordName
|
modelValue: RouteRecordName | undefined
|
||||||
list: RouteRecordRaw[]
|
list: RouteRecordRaw[]
|
||||||
isPressUpOrDown: boolean
|
isPressUpOrDown: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
"update:modelValue": [RouteRecordName]
|
"update:modelValue": [RouteRecordName | undefined]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const instance = getCurrentInstance()
|
const instance = getCurrentInstance()
|
||||||
@ -21,7 +21,7 @@ const activeRouteName = computed({
|
|||||||
get() {
|
get() {
|
||||||
return props.modelValue
|
return props.modelValue
|
||||||
},
|
},
|
||||||
set(value: RouteRecordName) {
|
set(value: RouteRecordName | undefined) {
|
||||||
emit("update:modelValue", value)
|
emit("update:modelValue", value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -39,7 +39,7 @@ const itemStyle = (item: RouteRecordRaw) => {
|
|||||||
const handleMouseenter = (item: RouteRecordRaw) => {
|
const handleMouseenter = (item: RouteRecordRaw) => {
|
||||||
// 如果上键或下键与 mouseenter 事件同时生效,则以上下键为准,不执行该函数的赋值逻辑
|
// 如果上键或下键与 mouseenter 事件同时生效,则以上下键为准,不执行该函数的赋值逻辑
|
||||||
if (props.isPressUpOrDown) return
|
if (props.isPressUpOrDown) return
|
||||||
activeRouteName.value = item.name!
|
activeRouteName.value = item.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 计算滚动可视区高度 */
|
/** 计算滚动可视区高度 */
|
||||||
@ -91,7 +91,7 @@ defineExpose({ getScrollTop })
|
|||||||
<span class="result-item-title">
|
<span class="result-item-title">
|
||||||
{{ item.meta?.title }}
|
{{ item.meta?.title }}
|
||||||
</span>
|
</span>
|
||||||
<SvgIcon v-if="activeRouteName === item.name" name="keyboard-enter" />
|
<SvgIcon v-if="activeRouteName && activeRouteName === item.name" name="keyboard-enter" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -4,7 +4,10 @@ import routeSettings from "@/config/route"
|
|||||||
|
|
||||||
const Layouts = () => import("@/layouts/index.vue")
|
const Layouts = () => import("@/layouts/index.vue")
|
||||||
|
|
||||||
/** 常驻路由 */
|
/**
|
||||||
|
* 常驻路由
|
||||||
|
* 除了 redirect/403/404/login 等隐藏页面,其他页面建议设置 Name 属性
|
||||||
|
*/
|
||||||
export const constantRoutes: RouteRecordRaw[] = [
|
export const constantRoutes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: "/redirect",
|
path: "/redirect",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user