feat: 处理nuxt部分样式问题 & 跳转问题

This commit is contained in:
Tim
2025-08-08 11:24:52 +08:00
parent 2b1958a603
commit 44daa255c8
8 changed files with 107 additions and 108 deletions

View File

@@ -26,7 +26,7 @@ export default {
components: { HeaderComponent, MenuComponent, GlobalPopups }, components: { HeaderComponent, MenuComponent, GlobalPopups },
data() { data() {
return { return {
menuVisible: process.client ? window.innerWidth > 768 : false menuVisible: true
} }
}, },
computed: { computed: {
@@ -45,7 +45,9 @@ export default {
} }
}, },
async mounted() { async mounted() {
// placeholder for future global initializations if (typeof window !== 'undefined') {
this.menuVisible = window.innerWidth > 768
}
}, },
methods: {} methods: {}
} }

View File

@@ -69,6 +69,8 @@ export default {
.dropdown-menu-container { .dropdown-menu-container {
position: absolute; position: absolute;
top: 100%;
right: 0;
background-color: var(--menu-background-color); background-color: var(--menu-background-color);
border: 1px solid var(--normal-border-color); border: 1px solid var(--normal-border-color);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);

View File

@@ -15,27 +15,29 @@
</div> </div>
</div> </div>
<div v-if="isLogin" class="header-content-right"> <ClientOnly>
<div v-if="isMobile" class="search-icon" @click="search"> <div v-if="isLogin" class="header-content-right">
<i class="fas fa-search"></i> <div v-if="isMobile" class="search-icon" @click="search">
<i class="fas fa-search"></i>
</div>
<DropdownMenu ref="userMenu" :items="headerMenuItems">
<template #trigger>
<div class="avatar-container">
<img class="avatar-img" :src="avatar" alt="avatar">
<i class="fas fa-caret-down dropdown-icon"></i>
</div>
</template>
</DropdownMenu>
</div> </div>
<DropdownMenu ref="userMenu" :items="headerMenuItems">
<template #trigger>
<div class="avatar-container">
<img class="avatar-img" :src="avatar" alt="avatar">
<i class="fas fa-caret-down dropdown-icon"></i>
</div>
</template>
</DropdownMenu>
</div>
<div v-else class="header-content-right"> <div v-else class="header-content-right">
<div v-if="isMobile" class="search-icon" @click="search"> <div v-if="isMobile" class="search-icon" @click="search">
<i class="fas fa-search"></i> <i class="fas fa-search"></i>
</div>
<div class="header-content-item-main" @click="goToLogin">登录</div>
<div class="header-content-item-secondary" @click="goToSignup">注册</div>
</div> </div>
<div class="header-content-item-main" @click="goToLogin">登录</div> </ClientOnly>
<div class="header-content-item-secondary" @click="goToSignup">注册</div>
</div>
<SearchDropdown ref="searchDropdown" v-if="isMobile && showSearch" @close="closeSearch" /> <SearchDropdown ref="searchDropdown" v-if="isMobile && showSearch" @close="closeSearch" />
</div> </div>
@@ -49,6 +51,7 @@ import { fetchUnreadCount, notificationState } from '~/utils/notification'
import DropdownMenu from '~/components/DropdownMenu.vue' import DropdownMenu from '~/components/DropdownMenu.vue'
import SearchDropdown from '~/components/SearchDropdown.vue' import SearchDropdown from '~/components/SearchDropdown.vue'
import { isMobile } from '~/utils/screen' import { isMobile } from '~/utils/screen'
import { ClientOnly } from '#components'
export default { export default {
name: 'HeaderComponent', name: 'HeaderComponent',
@@ -62,27 +65,82 @@ export default {
data() { data() {
return { return {
avatar: '', avatar: '',
showSearch: false showSearch: false,
searchDropdown: null
} }
}, },
computed: { setup() {
isLogin() { const isLogin = computed(() => authState.loggedIn)
return authState.loggedIn const isMobile = computed(() => isMobile.value)
}, const unreadCount = computed(() => notificationState.unreadCount)
isMobile() { const router = useRouter()
return isMobile.value
}, const goToHome = () => {
headerMenuItems() { router.push('/')
return [ }
{ text: '设置', onClick: this.goToSettings }, const search = () => {
{ text: '个人主页', onClick: this.goToProfile }, showSearch.value = true
{ text: '退出', onClick: this.goToLogout } nextTick(() => {
] searchDropdown.value.toggle()
}, })
unreadCount() { }
return notificationState.unreadCount const closeSearch = () => {
nextTick(() => {
showSearch.value = false
})
}
const goToLogin = () => {
router.push('/login')
}
const goToSettings = () => {
router.push('/settings')
}
const goToProfile = async () => {
if (!authState.loggedIn) {
router.push('/login')
return
}
let id = authState.username || authState.userId
if (!id) {
const user = await loadCurrentUser()
if (user) {
id = user.username || user.id
}
}
if (id) {
router.push(`/users/${id}`)
}
}
const goToSignup = () => {
router.push('/signup')
}
const goToLogout = () => {
clearToken()
this.$router.push('/login')
}
const headerMenuItems = computed(() => [
{ text: '设置', onClick: goToSettings },
{ text: '个人主页', onClick: goToProfile },
{ text: '退出', onClick: goToLogout }
])
return {
isLogin,
isMobile,
headerMenuItems,
unreadCount,
goToHome,
search,
closeSearch,
goToLogin,
goToSettings,
goToProfile,
goToSignup,
goToLogout
} }
}, },
async mounted() { async mounted() {
const updateAvatar = async () => { const updateAvatar = async () => {
if (authState.loggedIn) { if (authState.loggedIn) {
@@ -113,57 +171,6 @@ export default {
this.showSearch = false this.showSearch = false
}) })
}, },
methods: {
goToHome() {
this.$router.push('/').then(() => {
window.location.reload()
})
},
search() {
this.showSearch = true
nextTick(() => {
this.$refs.searchDropdown.toggle()
})
},
closeSearch() {
nextTick(() => {
this.showSearch = false
})
},
goToLogin() {
this.$router.push('/login')
},
goToSettings() {
this.$router.push('/settings')
},
async goToProfile() {
if (!authState.loggedIn) {
this.$router.push('/login')
return
}
let id = authState.username || authState.userId
if (!id) {
const user = await loadCurrentUser()
if (user) {
id = user.username || user.id
}
}
if (id) {
this.$router.push(`/users/${id}`).then(() => {
window.location.reload()
})
}
},
goToSignup() {
this.$router.push('/signup')
},
goToLogout() {
clearToken()
this.$router.push('/login')
}
}
} }
</script> </script>

View File

@@ -246,18 +246,12 @@ export default {
const value = encodeURIComponent(c.id ?? c.name) const value = encodeURIComponent(c.id ?? c.name)
this.$router this.$router
.push({ path: '/', query: { category: value } }) .push({ path: '/', query: { category: value } })
.then(() => {
window.location.reload()
})
this.handleItemClick() this.handleItemClick()
}, },
gotoTag(t) { gotoTag(t) {
const value = encodeURIComponent(t.id ?? t.name) const value = encodeURIComponent(t.id ?? t.name)
this.$router this.$router
.push({ path: '/', query: { tags: value } }) .push({ path: '/', query: { tags: value } })
.then(() => {
window.location.reload()
})
this.handleItemClick() this.handleItemClick()
} }
} }

View File

@@ -92,13 +92,9 @@ export default {
router.push(`/posts/${opt.postId}#comment-${opt.id}`) router.push(`/posts/${opt.postId}#comment-${opt.id}`)
} }
} else if (opt.type === 'category') { } else if (opt.type === 'category') {
router.push({ path: '/', query: { category: opt.id } }).then(() => { router.push({ path: '/', query: { category: opt.id } })
window.location.reload()
})
} else if (opt.type === 'tag') { } else if (opt.type === 'tag') {
router.push({ path: '/', query: { tags: opt.id } }).then(() => { router.push({ path: '/', query: { tags: opt.id } })
window.location.reload()
})
} }
selected.value = null selected.value = null
keyword.value = '' keyword.value = ''

View File

@@ -22,9 +22,7 @@ export default {
}, },
methods: { methods: {
handleUserClick(user) { handleUserClick(user) {
this.$router.push(`/users/${user.id}`).then(() => { this.$router.push(`/users/${user.id}`)
window.location.reload()
})
} }
} }
} }

View File

@@ -431,9 +431,7 @@ export default {
const gotoTag = tag => { const gotoTag = tag => {
const value = encodeURIComponent(tag.id ?? tag.name) const value = encodeURIComponent(tag.id ?? tag.name)
router.push({ path: '/', query: { tags: value } }).then(() => { router.push({ path: '/', query: { tags: value } })
window.location.reload()
})
} }
const init = async () => { const init = async () => {

View File

@@ -1,12 +1,14 @@
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
const width = ref(0) const width = ref(0)
const isClient = ref(false)
if (process.client) { if (typeof window !== 'undefined') {
isClient.value = true
width.value = window.innerWidth width.value = window.innerWidth
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
width.value = window.innerWidth width.value = window.innerWidth
}) })
} }
export const isMobile = computed(() => width.value <= 768) export const isMobile = computed(() => isClient.value && width.value <= 768)