Skip to content

企业官网

使用 VitePress 构建现代化的企业官网,展示公司形象、产品服务、团队实力和企业文化。

项目概述

企业官网是公司对外展示的重要窗口,需要专业的设计和良好的用户体验。VitePress 凭借其灵活的主题定制能力和优秀的性能表现,是构建企业官网的理想选择。

核心特性

  • 🏢 企业形象 - 专业的品牌展示和企业介绍
  • 📦 产品展示 - 丰富的产品介绍和案例展示
  • 👥 团队介绍 - 展示核心团队和企业文化
  • 📰 新闻动态 - 企业资讯和行业动态
  • 📞 联系方式 - 多种联系方式和在线咨询
  • 🌐 多语言 - 支持国际化多语言版本
  • 📱 响应式 - 完美适配各种设备
  • 🚀 高性能 - 快速加载和优秀的SEO

技术架构

核心技术栈

json
{
  "framework": "VitePress",
  "language": "TypeScript",
  "styling": "CSS3 + Tailwind CSS",
  "components": "Vue 3",
  "tools": [
    "Swiper.js",
    "AOS Animation",
    "EmailJS",
    "Google Analytics"
  ]
}

项目结构

company-website/
├── docs/
│   ├── .vitepress/
│   │   ├── config.ts
│   │   ├── theme/
│   │   │   ├── index.ts
│   │   │   ├── Layout.vue
│   │   │   └── components/
│   │   │       ├── Hero.vue
│   │   │       ├── ProductCard.vue
│   │   │       ├── TeamMember.vue
│   │   │       └── ContactForm.vue
│   │   └── public/
│   ├── about/
│   ├── products/
│   ├── team/
│   ├── news/
│   ├── contact/
│   └── index.md
├── assets/
│   ├── images/
│   └── styles/
└── package.json

实现步骤

1. 项目初始化

bash
# 创建项目
npm create vitepress@latest company-website
cd company-website

# 安装依赖
npm install
npm install -D tailwindcss autoprefixer swiper aos emailjs-com

2. 配置 VitePress

typescript
// .vitepress/config.ts
import { defineConfig } from 'vitepress'

export default defineConfig({
  title: '科技创新有限公司',
  description: '专注于前沿技术研发和创新解决方案',
  
  head: [
    ['link', { rel: 'icon', href: '/favicon.ico' }],
    ['meta', { name: 'viewport', content: 'width=device-width, initial-scale=1.0' }],
    ['meta', { property: 'og:type', content: 'website' }],
    ['meta', { property: 'og:title', content: '科技创新有限公司' }],
    ['meta', { property: 'og:description', content: '专注于前沿技术研发和创新解决方案' }],
    ['link', { rel: 'preconnect', href: 'https://fonts.googleapis.com' }],
    ['link', { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }],
    ['link', { href: 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap', rel: 'stylesheet' }]
  ],
  
  themeConfig: {
    logo: '/logo.svg',
    
    nav: [
      { text: '首页', link: '/' },
      { text: '关于我们', link: '/about/' },
      { 
        text: '产品服务',
        items: [
          { text: '产品概览', link: '/products/' },
          { text: '解决方案', link: '/products/solutions' },
          { text: '技术服务', link: '/products/services' }
        ]
      },
      { text: '团队', link: '/team/' },
      { text: '新闻动态', link: '/news/' },
      { text: '联系我们', link: '/contact/' }
    ],
    
    footer: {
      message: '© 2024 科技创新有限公司 版权所有',
      copyright: 'ICP备案号:京ICP备12345678号-1'
    },
    
    socialLinks: [
      { icon: 'github', link: 'https://github.com/company' },
      { icon: 'twitter', link: 'https://twitter.com/company' },
      { icon: 'linkedin', link: 'https://linkedin.com/company/company' }
    ]
  },
  
  // 自定义 CSS
  vite: {
    css: {
      postcss: {
        plugins: [
          require('tailwindcss'),
          require('autoprefixer')
        ]
      }
    }
  }
})

3. 首页布局

vue
<!-- .vitepress/theme/Layout.vue -->
<template>
  <Layout>
    <template #home-hero-before>
      <HeroSection v-if="isHomePage" />
    </template>
    
    <template #home-features-after>
      <div v-if="isHomePage" class="home-content">
        <AboutSection />
        <ProductsSection />
        <TeamSection />
        <NewsSection />
        <ContactSection />
      </div>
    </template>
  </Layout>
</template>

<script setup>
import { computed } from 'vue'
import { useData } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import HeroSection from './components/HeroSection.vue'
import AboutSection from './components/AboutSection.vue'
import ProductsSection from './components/ProductsSection.vue'
import TeamSection from './components/TeamSection.vue'
import NewsSection from './components/NewsSection.vue'
import ContactSection from './components/ContactSection.vue'

const { Layout } = DefaultTheme
const { page } = useData()

const isHomePage = computed(() => {
  return page.value.relativePath === 'index.md'
})
</script>

<style>
.home-content {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 20px;
}

.home-content section {
  margin: 80px 0;
}

@media (max-width: 768px) {
  .home-content {
    padding: 0 15px;
  }
  
  .home-content section {
    margin: 60px 0;
  }
}
</style>

4. 英雄区域组件

vue
<!-- .vitepress/theme/components/HeroSection.vue -->
<template>
  <section class="hero-section">
    <div class="hero-background">
      <div class="hero-overlay"></div>
      <video
        autoplay
        muted
        loop
        class="hero-video"
      >
        <source src="/videos/hero-bg.mp4" type="video/mp4">
      </video>
    </div>
    
    <div class="hero-content">
      <div class="container">
        <h1 class="hero-title" data-aos="fade-up">
          引领科技创新
          <span class="highlight">改变未来</span>
        </h1>
        
        <p class="hero-description" data-aos="fade-up" data-aos-delay="200">
          我们专注于前沿技术研发,为企业提供创新的解决方案,
          助力数字化转型,共创美好未来。
        </p>
        
        <div class="hero-actions" data-aos="fade-up" data-aos-delay="400">
          <a href="/products/" class="btn btn-primary">
            了解产品
          </a>
          <a href="/contact/" class="btn btn-secondary">
            联系我们
          </a>
        </div>
      </div>
    </div>
    
    <div class="hero-scroll">
      <div class="scroll-indicator">
        <span></span>
      </div>
    </div>
  </section>
</template>

<script setup>
import { onMounted } from 'vue'
import AOS from 'aos'

onMounted(() => {
  AOS.init({
    duration: 1000,
    once: true
  })
})
</script>

<style scoped>
.hero-section {
  position: relative;
  height: 100vh;
  min-height: 600px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.hero-background {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
}

.hero-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, rgba(0, 0, 0, 0.7) 0%, rgba(0, 0, 0, 0.3) 100%);
  z-index: 1;
}

.hero-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero-content {
  position: relative;
  z-index: 2;
  text-align: center;
  color: white;
}

.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 20px;
}

.hero-title {
  font-size: 3.5rem;
  font-weight: 700;
  line-height: 1.2;
  margin-bottom: 1.5rem;
}

.highlight {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.hero-description {
  font-size: 1.25rem;
  line-height: 1.6;
  margin-bottom: 2.5rem;
  max-width: 600px;
  margin-left: auto;
  margin-right: auto;
  opacity: 0.9;
}

.hero-actions {
  display: flex;
  gap: 1rem;
  justify-content: center;
  flex-wrap: wrap;
}

.btn {
  display: inline-block;
  padding: 12px 30px;
  border-radius: 50px;
  font-weight: 600;
  text-decoration: none;
  transition: all 0.3s ease;
  border: 2px solid transparent;
}

.btn-primary {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
}

.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3);
}

.btn-secondary {
  background: transparent;
  color: white;
  border-color: white;
}

.btn-secondary:hover {
  background: white;
  color: #333;
  transform: translateY(-2px);
}

.hero-scroll {
  position: absolute;
  bottom: 30px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
}

.scroll-indicator {
  width: 30px;
  height: 50px;
  border: 2px solid rgba(255, 255, 255, 0.5);
  border-radius: 25px;
  position: relative;
  cursor: pointer;
}

.scroll-indicator span {
  position: absolute;
  top: 8px;
  left: 50%;
  width: 4px;
  height: 8px;
  background: rgba(255, 255, 255, 0.8);
  border-radius: 2px;
  transform: translateX(-50%);
  animation: scroll 2s infinite;
}

@keyframes scroll {
  0% { opacity: 0; transform: translateX(-50%) translateY(0); }
  50% { opacity: 1; }
  100% { opacity: 0; transform: translateX(-50%) translateY(15px); }
}

@media (max-width: 768px) {
  .hero-title {
    font-size: 2.5rem;
  }
  
  .hero-description {
    font-size: 1.1rem;
  }
  
  .hero-actions {
    flex-direction: column;
    align-items: center;
  }
  
  .btn {
    width: 200px;
  }
}
</style>

5. 产品展示组件

vue
<!-- .vitepress/theme/components/ProductsSection.vue -->
<template>
  <section class="products-section">
    <div class="container">
      <div class="section-header" data-aos="fade-up">
        <h2>我们的产品</h2>
        <p>为不同行业提供专业的技术解决方案</p>
      </div>
      
      <div class="products-grid">
        <ProductCard
          v-for="product in products"
          :key="product.id"
          :product="product"
          data-aos="fade-up"
          :data-aos-delay="product.id * 100"
        />
      </div>
      
      <div class="section-footer" data-aos="fade-up">
        <a href="/products/" class="btn btn-outline">
          查看所有产品
        </a>
      </div>
    </div>
  </section>
</template>

<script setup>
import { ref } from 'vue'
import ProductCard from './ProductCard.vue'

const products = ref([
  {
    id: 1,
    title: '智能数据分析平台',
    description: '基于AI的大数据分析平台,帮助企业挖掘数据价值,做出智能决策。',
    image: '/images/products/data-platform.jpg',
    features: ['实时数据处理', '智能可视化', '预测分析'],
    link: '/products/data-platform'
  },
  {
    id: 2,
    title: '云原生开发框架',
    description: '现代化的微服务开发框架,支持容器化部署和自动扩缩容。',
    image: '/images/products/cloud-framework.jpg',
    features: ['微服务架构', '容器化部署', '自动扩缩容'],
    link: '/products/cloud-framework'
  },
  {
    id: 3,
    title: '企业协作平台',
    description: '一站式企业协作解决方案,提升团队协作效率和沟通质量。',
    image: '/images/products/collaboration.jpg',
    features: ['即时通讯', '项目管理', '文档协作'],
    link: '/products/collaboration'
  }
])
</script>

<style scoped>
.products-section {
  padding: 80px 0;
  background: #f8fafc;
}

.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 20px;
}

.section-header {
  text-align: center;
  margin-bottom: 60px;
}

.section-header h2 {
  font-size: 2.5rem;
  font-weight: 700;
  color: #1a202c;
  margin-bottom: 1rem;
}

.section-header p {
  font-size: 1.1rem;
  color: #718096;
  max-width: 600px;
  margin: 0 auto;
}

.products-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
  gap: 30px;
  margin-bottom: 60px;
}

.section-footer {
  text-align: center;
}

.btn {
  display: inline-block;
  padding: 12px 30px;
  border-radius: 8px;
  font-weight: 600;
  text-decoration: none;
  transition: all 0.3s ease;
}

.btn-outline {
  background: transparent;
  color: #667eea;
  border: 2px solid #667eea;
}

.btn-outline:hover {
  background: #667eea;
  color: white;
  transform: translateY(-2px);
  box-shadow: 0 10px 25px rgba(102, 126, 234, 0.2);
}

@media (max-width: 768px) {
  .products-grid {
    grid-template-columns: 1fr;
    gap: 20px;
  }
  
  .section-header h2 {
    font-size: 2rem;
  }
}
</style>

6. 产品卡片组件

vue
<!-- .vitepress/theme/components/ProductCard.vue -->
<template>
  <div class="product-card">
    <div class="card-image">
      <img :src="product.image" :alt="product.title" />
      <div class="card-overlay">
        <a :href="product.link" class="card-link">
          了解详情
        </a>
      </div>
    </div>
    
    <div class="card-content">
      <h3 class="card-title">{{ product.title }}</h3>
      <p class="card-description">{{ product.description }}</p>
      
      <div class="card-features">
        <span
          v-for="feature in product.features"
          :key="feature"
          class="feature-tag"
        >
          {{ feature }}
        </span>
      </div>
    </div>
  </div>
</template>

<script setup>
defineProps({
  product: {
    type: Object,
    required: true
  }
})
</script>

<style scoped>
.product-card {
  background: white;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
  transition: all 0.3s ease;
}

.product-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
}

.card-image {
  position: relative;
  height: 200px;
  overflow: hidden;
}

.card-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}

.product-card:hover .card-image img {
  transform: scale(1.05);
}

.card-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.product-card:hover .card-overlay {
  opacity: 1;
}

.card-link {
  color: white;
  text-decoration: none;
  padding: 10px 20px;
  border: 2px solid white;
  border-radius: 25px;
  font-weight: 600;
  transition: all 0.3s ease;
}

.card-link:hover {
  background: white;
  color: #333;
}

.card-content {
  padding: 25px;
}

.card-title {
  font-size: 1.25rem;
  font-weight: 600;
  color: #1a202c;
  margin-bottom: 10px;
}

.card-description {
  color: #718096;
  line-height: 1.6;
  margin-bottom: 20px;
}

.card-features {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.feature-tag {
  background: #e2e8f0;
  color: #4a5568;
  padding: 4px 12px;
  border-radius: 20px;
  font-size: 0.875rem;
  font-weight: 500;
}
</style>

7. 团队展示组件

vue
<!-- .vitepress/theme/components/TeamSection.vue -->
<template>
  <section class="team-section">
    <div class="container">
      <div class="section-header" data-aos="fade-up">
        <h2>核心团队</h2>
        <p>汇聚行业精英,共创技术未来</p>
      </div>
      
      <div class="team-grid">
        <TeamMember
          v-for="member in teamMembers"
          :key="member.id"
          :member="member"
          data-aos="fade-up"
          :data-aos-delay="member.id * 100"
        />
      </div>
    </div>
  </section>
</template>

<script setup>
import { ref } from 'vue'
import TeamMember from './TeamMember.vue'

const teamMembers = ref([
  {
    id: 1,
    name: '张伟',
    position: '首席技术官',
    avatar: '/images/team/zhang-wei.jpg',
    bio: '15年技术研发经验,专注于云计算和人工智能领域',
    social: {
      linkedin: 'https://linkedin.com/in/zhangwei',
      github: 'https://github.com/zhangwei'
    }
  },
  {
    id: 2,
    name: '李娜',
    position: '产品总监',
    avatar: '/images/team/li-na.jpg',
    bio: '10年产品管理经验,擅长用户体验设计和产品策略',
    social: {
      linkedin: 'https://linkedin.com/in/lina',
      twitter: 'https://twitter.com/lina'
    }
  },
  {
    id: 3,
    name: '王强',
    position: '架构师',
    avatar: '/images/team/wang-qiang.jpg',
    bio: '资深系统架构师,在大规模分布式系统设计方面有丰富经验',
    social: {
      linkedin: 'https://linkedin.com/in/wangqiang',
      github: 'https://github.com/wangqiang'
    }
  },
  {
    id: 4,
    name: '刘敏',
    position: '设计总监',
    avatar: '/images/team/liu-min.jpg',
    bio: '创意设计专家,致力于打造优秀的用户界面和体验',
    social: {
      linkedin: 'https://linkedin.com/in/liumin',
      dribbble: 'https://dribbble.com/liumin'
    }
  }
])
</script>

<style scoped>
.team-section {
  padding: 80px 0;
}

.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 20px;
}

.section-header {
  text-align: center;
  margin-bottom: 60px;
}

.section-header h2 {
  font-size: 2.5rem;
  font-weight: 700;
  color: #1a202c;
  margin-bottom: 1rem;
}

.section-header p {
  font-size: 1.1rem;
  color: #718096;
}

.team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 30px;
}

@media (max-width: 768px) {
  .team-grid {
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 20px;
  }
  
  .section-header h2 {
    font-size: 2rem;
  }
}
</style>

8. 联系表单组件

vue
<!-- .vitepress/theme/components/ContactForm.vue -->
<template>
  <div class="contact-form">
    <form @submit.prevent="submitForm" class="form">
      <div class="form-group">
        <label for="name">姓名 *</label>
        <input
          id="name"
          v-model="form.name"
          type="text"
          required
          placeholder="请输入您的姓名"
        />
      </div>
      
      <div class="form-group">
        <label for="email">邮箱 *</label>
        <input
          id="email"
          v-model="form.email"
          type="email"
          required
          placeholder="请输入您的邮箱"
        />
      </div>
      
      <div class="form-group">
        <label for="company">公司</label>
        <input
          id="company"
          v-model="form.company"
          type="text"
          placeholder="请输入您的公司名称"
        />
      </div>
      
      <div class="form-group">
        <label for="subject">主题 *</label>
        <select id="subject" v-model="form.subject" required>
          <option value="">请选择咨询主题</option>
          <option value="product">产品咨询</option>
          <option value="cooperation">合作洽谈</option>
          <option value="support">技术支持</option>
          <option value="other">其他</option>
        </select>
      </div>
      
      <div class="form-group">
        <label for="message">留言 *</label>
        <textarea
          id="message"
          v-model="form.message"
          required
          rows="5"
          placeholder="请详细描述您的需求或问题"
        ></textarea>
      </div>
      
      <button
        type="submit"
        class="submit-btn"
        :disabled="isSubmitting"
      >
        {{ isSubmitting ? '发送中...' : '发送消息' }}
      </button>
    </form>
    
    <div v-if="submitStatus" class="status-message" :class="submitStatus.type">
      {{ submitStatus.message }}
    </div>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import emailjs from 'emailjs-com'

const form = reactive({
  name: '',
  email: '',
  company: '',
  subject: '',
  message: ''
})

const isSubmitting = ref(false)
const submitStatus = ref(null)

async function submitForm() {
  isSubmitting.value = true
  submitStatus.value = null
  
  try {
    await emailjs.send(
      'your_service_id',
      'your_template_id',
      {
        from_name: form.name,
        from_email: form.email,
        company: form.company,
        subject: form.subject,
        message: form.message
      },
      'your_public_key'
    )
    
    submitStatus.value = {
      type: 'success',
      message: '消息发送成功!我们会尽快与您联系。'
    }
    
    // 重置表单
    Object.keys(form).forEach(key => {
      form[key] = ''
    })
    
  } catch (error) {
    submitStatus.value = {
      type: 'error',
      message: '发送失败,请稍后重试或直接联系我们。'
    }
  } finally {
    isSubmitting.value = false
  }
}
</script>

<style scoped>
.contact-form {
  max-width: 600px;
  margin: 0 auto;
}

.form {
  background: white;
  padding: 40px;
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}

.form-group {
  margin-bottom: 25px;
}

.form-group label {
  display: block;
  margin-bottom: 8px;
  font-weight: 600;
  color: #374151;
}

.form-group input,
.form-group select,
.form-group textarea {
  width: 100%;
  padding: 12px 16px;
  border: 2px solid #e5e7eb;
  border-radius: 8px;
  font-size: 16px;
  transition: border-color 0.3s ease;
}

.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
  outline: none;
  border-color: #667eea;
}

.submit-btn {
  width: 100%;
  padding: 15px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  border: none;
  border-radius: 8px;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s ease;
}

.submit-btn:hover:not(:disabled) {
  transform: translateY(-2px);
  box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3);
}

.submit-btn:disabled {
  opacity: 0.7;
  cursor: not-allowed;
}

.status-message {
  margin-top: 20px;
  padding: 15px;
  border-radius: 8px;
  text-align: center;
  font-weight: 500;
}

.status-message.success {
  background: #d1fae5;
  color: #065f46;
  border: 1px solid #a7f3d0;
}

.status-message.error {
  background: #fee2e2;
  color: #991b1b;
  border: 1px solid #fca5a5;
}
</style>

高级功能

1. 多语言支持

typescript
// .vitepress/config.ts
export default defineConfig({
  locales: {
    root: {
      label: '简体中文',
      lang: 'zh-CN',
      title: '科技创新有限公司',
      description: '专注于前沿技术研发和创新解决方案'
    },
    en: {
      label: 'English',
      lang: 'en-US',
      title: 'Tech Innovation Co., Ltd.',
      description: 'Focus on cutting-edge technology R&D and innovative solutions',
      themeConfig: {
        nav: [
          { text: 'Home', link: '/en/' },
          { text: 'About', link: '/en/about/' },
          { text: 'Products', link: '/en/products/' },
          { text: 'Team', link: '/en/team/' },
          { text: 'News', link: '/en/news/' },
          { text: 'Contact', link: '/en/contact/' }
        ]
      }
    }
  }
})

2. SEO 优化

vue
<!-- .vitepress/theme/components/SEOHead.vue -->
<template>
  <Head>
    <title>{{ pageTitle }}</title>
    <meta name="description" :content="pageDescription" />
    <meta property="og:title" :content="pageTitle" />
    <meta property="og:description" :content="pageDescription" />
    <meta property="og:image" :content="pageImage" />
    <meta property="og:url" :content="pageUrl" />
    <meta name="twitter:card" content="summary_large_image" />
    <meta name="twitter:title" :content="pageTitle" />
    <meta name="twitter:description" :content="pageDescription" />
    <meta name="twitter:image" :content="pageImage" />
    <link rel="canonical" :href="pageUrl" />
    <script type="application/ld+json" v-html="structuredData"></script>
  </Head>
</template>

<script setup>
import { computed } from 'vue'
import { useData } from 'vitepress'

const { page, site } = useData()

const pageTitle = computed(() => {
  return page.value.title ? `${page.value.title} - ${site.value.title}` : site.value.title
})

const pageDescription = computed(() => {
  return page.value.description || site.value.description
})

const pageImage = computed(() => {
  return page.value.frontmatter.image || '/images/og-image.jpg'
})

const pageUrl = computed(() => {
  return `${site.value.base}${page.value.relativePath.replace('.md', '.html')}`
})

const structuredData = computed(() => {
  return JSON.stringify({
    "@context": "https://schema.org",
    "@type": "Organization",
    "name": "科技创新有限公司",
    "url": site.value.base,
    "logo": `${site.value.base}/logo.png`,
    "description": site.value.description,
    "address": {
      "@type": "PostalAddress",
      "streetAddress": "科技园区创新大厦",
      "addressLocality": "北京",
      "addressCountry": "CN"
    },
    "contactPoint": {
      "@type": "ContactPoint",
      "telephone": "+86-10-12345678",
      "contactType": "customer service"
    }
  })
})
</script>

3. 性能监控

javascript
// .vitepress/theme/utils/analytics.js
export function initAnalytics() {
  // Google Analytics
  if (typeof gtag !== 'undefined') {
    gtag('config', 'GA_MEASUREMENT_ID', {
      page_title: document.title,
      page_location: window.location.href
    })
  }
  
  // 性能监控
  if ('performance' in window) {
    window.addEventListener('load', () => {
      const perfData = performance.getEntriesByType('navigation')[0]
      
      // 发送性能数据
      gtag('event', 'page_load_time', {
        event_category: 'Performance',
        event_label: 'Load Time',
        value: Math.round(perfData.loadEventEnd - perfData.fetchStart)
      })
    })
  }
}

部署配置

Docker 部署

dockerfile
# Dockerfile
FROM node:18-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci

COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/docs/.vitepress/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
nginx
# nginx.conf
events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    
    server {
        listen 80;
        server_name localhost;
        root /usr/share/nginx/html;
        index index.html;
        
        location / {
            try_files $uri $uri/ $uri.html /index.html;
        }
        
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }
}

CI/CD 流水线

yaml
# .github/workflows/deploy.yml
name: Deploy Company Website

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout
      uses: actions/checkout@v3
      with:
        fetch-depth: 0
    
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run tests
      run: npm run test
    
    - name: Build
      run: npm run build
      env:
        NODE_ENV: production
    
    - name: Deploy to staging
      if: github.event_name == 'pull_request'
      run: |
        echo "Deploy to staging environment"
        # 部署到测试环境的命令
    
    - name: Deploy to production
      if: github.ref == 'refs/heads/main'
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: docs/.vitepress/dist
        custom_domain: company.example.com
    
    - name: Notify deployment
      if: always()
      uses: 8398a7/action-slack@v3
      with:
        status: ${{ job.status }}
        webhook_url: ${{ secrets.SLACK_WEBHOOK }}

最佳实践

1. 内容管理

  • 内容策略 - 制定清晰的内容更新计划
  • 版本控制 - 使用 Git 管理内容变更
  • 审核流程 - 建立内容审核和发布流程

2. 用户体验

  • 加载速度 - 优化图片和资源加载
  • 移动适配 - 确保移动设备良好体验
  • 无障碍访问 - 遵循 WCAG 无障碍标准

3. 安全性

  • HTTPS - 启用 SSL 证书
  • 内容安全 - 设置 CSP 头部
  • 定期更新 - 保持依赖包最新版本

示例项目

完整的示例项目可以在 GitHub 上查看。

在线演示

功能特色

  • ✅ 响应式设计
  • ✅ 多语言支持
  • ✅ SEO 优化
  • ✅ 性能监控
  • ✅ 自动化部署
  • ✅ 内容管理系统

通过这个案例,你可以学习如何使用 VitePress 构建专业的企业官网,包括品牌展示、产品介绍、团队展示和客户联系等核心功能。

vitepress开发指南