feat: enhance SEO and site structure with new meta tags, sitemap updates, and route SEO management

This commit is contained in:
zhangyuheng
2026-03-18 18:08:51 +08:00
parent 08fd3cc340
commit 1dcca1376f
6 changed files with 553 additions and 10 deletions

View File

@@ -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');
const app = createApp(App);
router.afterEach((to) => {
applyRouteSeo(to);
});
app.use(router);
router.isReady().then(() => {
applyRouteSeo(router.currentRoute.value);
app.mount('#app');
});

View File

@@ -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 },
},
];

429
src/utils/seo.js Normal file
View File

@@ -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);
}