From 1dcca1376f5ed01f18743da2a99df406484a27c6 Mon Sep 17 00:00:00 2001 From: zhangyuheng Date: Wed, 18 Mar 2026 18:08:51 +0800 Subject: [PATCH] feat: enhance SEO and site structure with new meta tags, sitemap updates, and route SEO management --- index.html | 38 +++- public/robots.txt | 1 + public/sitemap.xml | 58 +++++- src/main.js | 14 +- src/router.js | 23 ++- src/utils/seo.js | 429 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 553 insertions(+), 10 deletions(-) create mode 100644 src/utils/seo.js diff --git a/index.html b/index.html index bddca53..b998738 100644 --- a/index.html +++ b/index.html @@ -7,8 +7,12 @@ - - + + + + + + @@ -17,19 +21,21 @@ - + + - + + @@ -48,7 +54,7 @@ "@type": "GameServer", "name": "白鹿原 Minecraft 服务器", "description": "永不换档的纯净原版生存Minecraft服务器,支持Java版和基岩版互通", - "url": "https://mcpure.lunadeer.cn/", + "url": "https://bailuyuan.lunadeer.cn/", "logo": "https://img.lunadeer.cn/i/2024/04/22/6625ce6c8ddc1.png", "image": "https://img.lunadeer.cn/i/2025/11/26/69267755e14e3.png", "game": { @@ -74,10 +80,10 @@ "@context": "https://schema.org", "@type": "WebSite", "name": "白鹿原 Minecraft 服务器", - "url": "https://mcpure.lunadeer.cn/", + "url": "https://bailuyuan.lunadeer.cn/", "potentialAction": { "@type": "SearchAction", - "target": "https://mcpure.lunadeer.cn/stats?q={search_term_string}", + "target": "https://bailuyuan.lunadeer.cn/stats?q={search_term_string}", "query-input": "required name=search_term_string" } } @@ -98,6 +104,24 @@ }(window.location)) 跳转到主内容 +
diff --git a/public/robots.txt b/public/robots.txt index 34d374c..57d18b3 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,5 +1,6 @@ User-agent: * Allow: / Disallow: /stats/*.json +Disallow: /stats/*.json$ Sitemap: https://bailuyuan.lunadeer.cn/sitemap.xml \ No newline at end of file diff --git a/public/sitemap.xml b/public/sitemap.xml index d41b630..0f4aaf9 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -1,9 +1,65 @@ - + https://bailuyuan.lunadeer.cn/ 2026-03-18 weekly 1.0 + + https://bailuyuan.lunadeer.cn/join + 2026-03-18 + monthly + 0.9 + + + https://bailuyuan.lunadeer.cn/stats + 2026-03-18 + daily + 0.85 + + + https://bailuyuan.lunadeer.cn/announcements + 2026-03-18 + weekly + 0.8 + + + https://bailuyuan.lunadeer.cn/facilities + 2026-03-18 + weekly + 0.8 + + + https://bailuyuan.lunadeer.cn/towns + 2026-03-18 + weekly + 0.75 + + + https://bailuyuan.lunadeer.cn/sponsor + 2026-03-18 + weekly + 0.7 + + + https://bailuyuan.lunadeer.cn/doc + 2026-03-18 + monthly + 0.6 + + + https://bailuyuan.lunadeer.cn/map + 2026-03-18 + monthly + 0.55 + + + https://bailuyuan.lunadeer.cn/photo + 2026-03-18 + weekly + 0.55 + \ No newline at end of file diff --git a/src/main.js b/src/main.js index 6b3b98e..8eadfef 100644 --- a/src/main.js +++ b/src/main.js @@ -2,5 +2,17 @@ import { createApp } from 'vue'; import App from './App.vue'; import router from './router'; import './styles.css'; +import { applyRouteSeo } from './utils/seo'; -createApp(App).use(router).mount('#app'); \ No newline at end of file +const app = createApp(App); + +router.afterEach((to) => { + applyRouteSeo(to); +}); + +app.use(router); + +router.isReady().then(() => { + applyRouteSeo(router.currentRoute.value); + app.mount('#app'); +}); \ No newline at end of file diff --git a/src/router.js b/src/router.js index f092ea8..ed44662 100644 --- a/src/router.js +++ b/src/router.js @@ -1,55 +1,76 @@ import { createRouter, createWebHistory } from 'vue-router'; +import { routeSeo } from './utils/seo'; -const routes = [ +export const routes = [ { path: '/', + alias: ['/index.html'], name: 'home', component: () => import('./pages/HomePage.vue'), + meta: { seo: routeSeo.home }, }, { path: '/announcements', + alias: ['/announcements.html'], name: 'announcements', component: () => import('./pages/AnnouncementsPage.vue'), + meta: { seo: routeSeo.announcements }, }, { path: '/facilities', + alias: ['/facilities.html'], name: 'facilities', component: () => import('./pages/FacilitiesPage.vue'), + meta: { seo: routeSeo.facilities }, }, { path: '/towns', + alias: ['/towns.html'], name: 'towns', component: () => import('./pages/TownsPage.vue'), + meta: { seo: routeSeo.towns }, }, { path: '/stats', + alias: ['/stats.html'], name: 'stats', component: () => import('./pages/StatsPage.vue'), + meta: { seo: routeSeo.stats }, }, { path: '/sponsor', + alias: ['/sponsor.html'], name: 'sponsor', component: () => import('./pages/SponsorPage.vue'), + meta: { seo: routeSeo.sponsor }, }, { path: '/join', + alias: ['/join.html'], name: 'join', component: () => import('./pages/JoinPage.vue'), + meta: { seo: routeSeo.join }, }, { path: '/doc', + alias: ['/doc.html'], name: 'doc', component: () => import('./pages/DocPage.vue'), + meta: { seo: routeSeo.doc }, }, { path: '/map', + alias: ['/map.html'], name: 'map', component: () => import('./pages/MapPage.vue'), + meta: { seo: routeSeo.map }, }, { path: '/photo', + alias: ['/photo.html'], name: 'photo', component: () => import('./pages/PhotoPage.vue'), + meta: { seo: routeSeo.photo }, }, ]; diff --git a/src/utils/seo.js b/src/utils/seo.js new file mode 100644 index 0000000..2a799f1 --- /dev/null +++ b/src/utils/seo.js @@ -0,0 +1,429 @@ +const SITE_URL = 'https://bailuyuan.lunadeer.cn'; +const SITE_NAME = '白鹿原 Minecraft 服务器'; +const SITE_DESCRIPTION = '白鹿原是一个永不换档的纯净原版生存 Minecraft 服务器,支持 Java 版与基岩版互通。提供免费圈地保护、自研管理插件,紧跟最新游戏版本更新。'; +const DEFAULT_OG_IMAGE = 'https://img.lunadeer.cn/i/2024/04/22/6625ce6c8ddc1.png'; +const HOME_OG_IMAGE = 'https://img.lunadeer.cn/i/2025/11/26/69267755e14e3.png'; +const ROBOTS_CONTENT = 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1'; + +const siteNavigation = [ + { name: '首页', path: '/' }, + { name: '活动公告', path: '/announcements' }, + { name: '共享资源', path: '/facilities' }, + { name: '城镇介绍', path: '/towns' }, + { name: '玩家数据统计', path: '/stats' }, + { name: '赞助榜', path: '/sponsor' }, + { name: '加入游戏指引', path: '/join' }, + { name: '文档', path: '/doc' }, + { name: '在线地图', path: '/map' }, + { name: '服务器相册', path: '/photo' }, +]; + +function toAbsoluteUrl(path = '/') { + return new URL(path, SITE_URL).toString(); +} + +function createBreadcrumbList(name, path) { + if (path === '/') { + return null; + } + + return { + '@context': 'https://schema.org', + '@type': 'BreadcrumbList', + itemListElement: [ + { + '@type': 'ListItem', + position: 1, + name: '首页', + item: SITE_URL, + }, + { + '@type': 'ListItem', + position: 2, + name, + item: toAbsoluteUrl(path), + }, + ], + }; +} + +function createWebPageSchema(type, name, description, path) { + return { + '@context': 'https://schema.org', + '@type': type, + name, + description, + url: toAbsoluteUrl(path), + inLanguage: 'zh-CN', + isPartOf: { + '@type': 'WebSite', + name: SITE_NAME, + url: SITE_URL, + }, + primaryImageOfPage: DEFAULT_OG_IMAGE, + }; +} + +function createCollectionPageSchema(name, description, path) { + return createWebPageSchema('CollectionPage', name, description, path); +} + +function createBaseStructuredData() { + return [ + { + '@context': 'https://schema.org', + '@type': 'Organization', + '@id': `${SITE_URL}/#organization`, + name: SITE_NAME, + url: SITE_URL, + logo: DEFAULT_OG_IMAGE, + image: DEFAULT_OG_IMAGE, + description: SITE_DESCRIPTION, + }, + { + '@context': 'https://schema.org', + '@type': 'WebSite', + '@id': `${SITE_URL}/#website`, + name: SITE_NAME, + url: SITE_URL, + inLanguage: 'zh-CN', + description: SITE_DESCRIPTION, + publisher: { + '@id': `${SITE_URL}/#organization`, + }, + potentialAction: { + '@type': 'SearchAction', + target: `${SITE_URL}/stats?q={search_term_string}`, + 'query-input': 'required name=search_term_string', + }, + }, + ...siteNavigation.map((item) => ({ + '@context': 'https://schema.org', + '@type': 'SiteNavigationElement', + name: item.name, + url: toAbsoluteUrl(item.path), + })), + ]; +} + +export const routeSeo = { + home: { + path: '/', + title: '白鹿原 Minecraft 服务器 - 永不换档的纯净原版生存Minecraft服务器', + description: '白鹿原是一个永不换档的纯净原版生存Minecraft我的世界服务器,支持Java版与基岩版互通。提供免费圈地保护、自研管理插件,紧跟最新游戏版本更新。物理工作站保障7×24小时稳定运行,实时查看服务器在线状态与众筹进展。立即加入白鹿原,开启纯净原版生存冒险之旅!服务器地址:mcpure.lunadeer.cn', + keywords: '白鹿原Minecraft,白鹿原我的世界,白鹿原mc,Minecraft服务器,我的世界,我的世界服务器,纯净服务器,原版服务器,纯净生存,基岩互通,白鹿原,MC服务器,永不换档,免费圈地,Minecraft中国', + ogImage: HOME_OG_IMAGE, + ogImageAlt: '白鹿原 Minecraft 服务器主页视觉图', + twitterCard: 'summary_large_image', + type: 'website', + structuredData: () => [ + createWebPageSchema('WebPage', SITE_NAME, '白鹿原 Minecraft 服务器首页,展示服务器特色、实时状态、赞助名单与众筹进度。', '/'), + { + '@context': 'https://schema.org', + '@type': 'GameServer', + name: SITE_NAME, + description: '永不换档的纯净原版生存 Minecraft 服务器,支持 Java 版和基岩版互通。', + url: SITE_URL, + logo: DEFAULT_OG_IMAGE, + image: HOME_OG_IMAGE, + serverStatus: 'Online', + game: { + '@type': 'VideoGame', + name: 'Minecraft', + gamePlatform: ['Java Edition', 'Bedrock Edition'], + }, + offers: { + '@type': 'Offer', + price: '0', + priceCurrency: 'CNY', + availability: 'https://schema.org/InStock', + }, + }, + ], + }, + announcements: { + path: '/announcements', + title: '活动公告 - 白鹿原 Minecraft 服务器', + description: '白鹿原Minecraft服务器活动公告,了解最新的服务器活动、维护通知和重要公告信息。', + keywords: 'Minecraft公告,MC活动,白鹿原公告,服务器活动,维护通知', + ogImageAlt: '白鹿原 Minecraft 服务器活动公告页面', + type: 'website', + structuredData: () => { + const name = '活动公告'; + const description = '白鹿原Minecraft服务器活动公告,了解最新的服务器活动、维护通知和重要公告信息。'; + return [ + createCollectionPageSchema(name, description, '/announcements'), + createBreadcrumbList(name, '/announcements'), + ].filter(Boolean); + }, + }, + facilities: { + path: '/facilities', + title: '共享资源 - 白鹿原 Minecraft 服务器', + description: '白鹿原Minecraft服务器全服共享公共设施资源一览,包含各类自动化农场、刷怪塔、交易所等实用设施。支持按类型筛选和关键词搜索,查看设施坐标位置、详细使用说明与视频教程。共同建设共同分享,让纯净原版生存更加便捷轻松。', + keywords: 'Minecraft共享资源,MC公共设施,白鹿原设施,Minecraft农场,服务器公共资源', + ogImageAlt: '白鹿原 Minecraft 服务器共享资源页面', + type: 'website', + structuredData: () => { + const name = '全服共享资源'; + const description = '白鹿原Minecraft服务器全服共享资源一览,包含各类自动化农场、刷怪塔、交易所等公共设施。'; + return [ + createCollectionPageSchema(name, description, '/facilities'), + createBreadcrumbList(name, '/facilities'), + ].filter(Boolean); + }, + }, + towns: { + path: '/towns', + title: '城镇介绍 - 白鹿原 Minecraft 服务器', + description: '白鹿原Minecraft服务器城镇一览,查看各个城镇的坐标位置、规模类型、招募状态、创始人与成员信息,以及城镇详细介绍与风貌展示。加入一个城镇,开启你的冒险之旅。', + keywords: 'Minecraft城镇,MC城镇介绍,白鹿原城镇,Minecraft社区,服务器城镇', + ogImageAlt: '白鹿原 Minecraft 服务器城镇介绍页面', + type: 'website', + structuredData: () => { + const name = '城镇介绍'; + const description = '白鹿原Minecraft服务器城镇一览,查看规模类型、招募状态与详细介绍。'; + return [ + createCollectionPageSchema(name, description, '/towns'), + createBreadcrumbList(name, '/towns'), + ].filter(Boolean); + }, + }, + stats: { + path: '/stats', + title: '玩家数据统计 - 白鹿原 Minecraft 服务器', + description: '查看白鹿原Minecraft服务器全面的玩家数据统计与排行榜,包括总游戏时长、方块放置与破坏数、击杀数、死亡数等多项数据指标。搜索玩家名称查看个人详细统计信息,实时了解服务器玩家活跃度与数据榜单,发现白鹿原最活跃的冒险家们。', + keywords: 'Minecraft玩家数据,服务器统计,玩家排行榜,白鹿原数据,MC统计,游戏时长排行', + ogImageAlt: '白鹿原 Minecraft 服务器玩家数据统计页面', + type: 'website', + structuredData: () => { + const name = '玩家数据统计'; + const description = '白鹿原Minecraft服务器玩家数据统计与排行榜页面。'; + return [ + createCollectionPageSchema(name, description, '/stats'), + createBreadcrumbList(name, '/stats'), + ].filter(Boolean); + }, + }, + sponsor: { + path: '/sponsor', + title: '赞助榜 - 白鹿原 Minecraft 服务器', + description: '查看白鹿原Minecraft服务器赞助者列表与众筹进度,感谢每一位赞助者的慷慨支持!了解服务器年度运营费用与当前筹集情况,支持搜索和筛选赞助记录。如果您也热爱白鹿原,欢迎通过赞助帮助服务器持续稳定运营,共同守护这片纯净的Minecraft世界。', + keywords: '白鹿原赞助,Minecraft服务器赞助,MC服务器支持,白鹿原捐赠,服务器众筹', + ogImageAlt: '白鹿原 Minecraft 服务器赞助榜页面', + type: 'website', + structuredData: () => { + const name = '赞助榜'; + const description = '白鹿原Minecraft服务器赞助者列表与众筹进度页面。'; + return [ + createCollectionPageSchema(name, description, '/sponsor'), + createBreadcrumbList(name, '/sponsor'), + ].filter(Boolean); + }, + }, + join: { + path: '/join', + title: '加入游戏指引 - 白鹿原 Minecraft 服务器', + description: '白鹿原Minecraft服务器新手加入指南,支持Java版与基岩版互通,四步轻松入服:阅读服务器公约、同意规则条款、选择游戏设备、跟随配置教程完成设置。无论您使用电脑还是手机平板,都能快速加入白鹿原开启纯净原版生存冒险之旅。', + keywords: 'Minecraft加入服务器,MC怎么进服,白鹿原加入,Minecraft教程,基岩版加入,Java版加入', + ogImageAlt: '白鹿原 Minecraft 服务器加入游戏指引页面', + type: 'website', + structuredData: () => { + const name = '加入游戏指引'; + return [ + createBreadcrumbList(name, '/join'), + { + '@context': 'https://schema.org', + '@type': 'HowTo', + name: '加入白鹿原Minecraft服务器', + description: '白鹿原Minecraft服务器加入指南,支持Java版与基岩版互通。', + url: toAbsoluteUrl('/join'), + inLanguage: 'zh-CN', + step: [ + { + '@type': 'HowToStep', + position: 1, + name: '服务器公约', + text: '阅读并同意服务器公约。', + }, + { + '@type': 'HowToStep', + position: 2, + name: '选择设备', + text: '选择您所使用的设备和版本。', + }, + { + '@type': 'HowToStep', + position: 3, + name: '配置启动', + text: '配置服务器地址并启动游戏。', + }, + { + '@type': 'HowToStep', + position: 4, + name: '开始冒险', + text: '选择适合您的玩法并开始冒险。', + }, + ], + isPartOf: { + '@type': 'WebSite', + name: SITE_NAME, + url: SITE_URL, + }, + }, + ].filter(Boolean); + }, + }, + doc: { + path: '/doc', + title: '文档 - 白鹿原 Minecraft 服务器', + description: '白鹿原Minecraft服务器文档中心,提供全面的服务器使用指南与参考资料。包含服务器规则详解、特色玩法说明、自研插件使用教程等详细文档,帮助新老玩家快速了解服务器功能与机制,轻松上手白鹿原纯净原版Minecraft生存体验。', + keywords: '白鹿原文档,Minecraft服务器文档,MC服务器规则,白鹿原指南,服务器帮助', + ogImageAlt: '白鹿原 Minecraft 服务器文档中心页面', + type: 'website', + structuredData: () => { + const name = '文档'; + const description = '白鹿原Minecraft服务器文档中心,包含服务器规则、玩法说明和插件使用指南。'; + return [ + createWebPageSchema('WebPage', '白鹿原服务器文档中心', description, '/doc'), + createBreadcrumbList(name, '/doc'), + ].filter(Boolean); + }, + }, + map: { + path: '/map', + title: '在线地图 - 白鹿原 Minecraft 服务器', + description: '白鹿原Minecraft服务器在线实时3D动态地图,全方位俯瞰服务器世界全貌。探索玩家精心建造的建筑作品,浏览多样化的自然地形地貌,实时查看服务器世界的最新变化。通过交互式地图发现白鹿原中的精彩角落,感受玩家们的创造力与冒险足迹。', + keywords: 'Minecraft在线地图,MC服务器地图,白鹿原地图,Minecraft 3D地图,服务器世界', + ogImageAlt: '白鹿原 Minecraft 服务器在线地图页面', + type: 'website', + structuredData: () => { + const name = '在线地图'; + const description = '白鹿原Minecraft服务器在线实时3D地图页面。'; + return [ + createWebPageSchema('WebPage', '白鹿原服务器在线地图', description, '/map'), + createBreadcrumbList(name, '/map'), + ].filter(Boolean); + }, + }, + photo: { + path: '/photo', + title: '服务器相册 - 白鹿原 Minecraft 服务器', + description: '白鹿原Minecraft服务器精美截图相册,记录服务器中玩家精心建造的建筑作品、壮丽的自然风景与难忘的游戏精彩瞬间。浏览白鹿原最美的光影截图,感受纯净原版Minecraft世界中玩家们的无限创造力与冒险故事,一起欣赏这片美丽的虚拟世界。', + keywords: 'Minecraft截图,MC服务器相册,白鹿原截图,Minecraft建筑,服务器风景', + ogImageAlt: '白鹿原 Minecraft 服务器相册页面', + type: 'website', + structuredData: () => { + const name = '服务器相册'; + const description = '白鹿原Minecraft服务器精美截图相册,记录玩家建筑和服务器精彩瞬间。'; + return [ + { + '@context': 'https://schema.org', + '@type': 'ImageGallery', + name: '白鹿原Minecraft服务器相册', + description, + url: toAbsoluteUrl('/photo'), + inLanguage: 'zh-CN', + isPartOf: { + '@type': 'WebSite', + name: SITE_NAME, + url: SITE_URL, + }, + }, + createBreadcrumbList(name, '/photo'), + ].filter(Boolean); + }, + }, +}; + +function getActiveSeo(route) { + return route?.meta?.seo || routeSeo.home; +} + +function ensureMeta(definition, content) { + const key = definition.name ? 'name' : 'property'; + const value = definition[key]; + const selector = `meta[${key}="${value}"]`; + let node = document.head.querySelector(selector); + + if (!node) { + node = document.createElement('meta'); + node.setAttribute(key, value); + node.setAttribute('data-route-seo', 'true'); + document.head.appendChild(node); + } + + node.setAttribute('content', content); +} + +function ensureLink(definition, href) { + const selector = `link[rel="${definition.rel}"]`; + let node = document.head.querySelector(selector); + + if (!node) { + node = document.createElement('link'); + node.setAttribute('rel', definition.rel); + node.setAttribute('data-route-seo', 'true'); + document.head.appendChild(node); + } + + if (definition.type) { + node.setAttribute('type', definition.type); + } + + node.setAttribute('href', href); +} + +function replaceJsonLdScripts(structuredData) { + document.head.querySelectorAll('script[data-route-seo="json-ld"]').forEach((node) => node.remove()); + + structuredData.forEach((entry) => { + const script = document.createElement('script'); + script.type = 'application/ld+json'; + script.setAttribute('data-route-seo', 'json-ld'); + script.textContent = JSON.stringify(entry); + document.head.appendChild(script); + }); +} + +export function applyRouteSeo(route) { + if (typeof document === 'undefined') { + return; + } + + const seo = getActiveSeo(route); + const canonicalUrl = toAbsoluteUrl(seo.path); + const ogImage = seo.ogImage || DEFAULT_OG_IMAGE; + const ogImageAlt = seo.ogImageAlt || `${SITE_NAME} 页面预览图`; + + document.documentElement.lang = 'zh-CN'; + document.title = seo.title; + + ensureMeta({ name: 'description' }, seo.description); + ensureMeta({ name: 'keywords' }, seo.keywords); + ensureMeta({ name: 'author' }, SITE_NAME); + ensureMeta({ name: 'robots' }, ROBOTS_CONTENT); + ensureMeta({ name: 'application-name' }, SITE_NAME); + ensureMeta({ name: 'apple-mobile-web-app-title' }, SITE_NAME); + ensureMeta({ property: 'og:type' }, seo.type || 'website'); + ensureMeta({ property: 'og:url' }, canonicalUrl); + ensureMeta({ property: 'og:title' }, seo.title); + ensureMeta({ property: 'og:description' }, seo.description); + ensureMeta({ property: 'og:image' }, ogImage); + ensureMeta({ property: 'og:image:alt' }, ogImageAlt); + ensureMeta({ property: 'og:site_name' }, SITE_NAME); + ensureMeta({ property: 'og:locale' }, 'zh_CN'); + ensureMeta({ property: 'twitter:card' }, seo.twitterCard || 'summary'); + ensureMeta({ property: 'twitter:url' }, canonicalUrl); + ensureMeta({ property: 'twitter:title' }, seo.title); + ensureMeta({ property: 'twitter:description' }, seo.description); + ensureMeta({ property: 'twitter:image' }, ogImage); + ensureMeta({ property: 'twitter:image:alt' }, ogImageAlt); + ensureLink({ rel: 'canonical' }, canonicalUrl); + + const structuredData = [ + ...createBaseStructuredData(), + ...(typeof seo.structuredData === 'function' ? seo.structuredData() : []), + ].filter(Boolean); + replaceJsonLdScripts(structuredData); +}