一、搭建基础框架

nodejs版本:20.19.4

1.创建项目并安装依赖

pnpm create vue@latest
cd vue-demo
pnpm install -D tailwindcss@^3 postcss autoprefixer
npx tailwindcss init -p

2. 配置 Tailwind

  • 修改 tailwind.config.js:
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{vue,js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {
      colors: {
        primary: '#2563eb',
        secondary: '#4f46e5',
      },
      fontFamily: {
        sans: ['Inter', 'system-ui', 'sans-serif'],
      },
    },
  },
  plugins: [],
}
  • 创建 src/assets/css/tailwind.css:
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  body { @apply text-gray-800 bg-gray-50; }
  h1 { @apply text-[clamp(2rem,5vw,3.5rem)] font-bold; }
  h2 { @apply text-[clamp(1.5rem,3vw,2.5rem)] font-semibold; }
}

3.配置路由

  • 创建 src/router/index.js:
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
// import About from '../views/About.vue'
// import Contact from '../views/Contact.vue'

export default createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', component: Home },
    // { path: '/about', component: About },
    // { path: '/contact', component: Contact }
  ]
})

4.入口文件配置

  • 修改 src/main.ts:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './assets/css/tailwind.css'

const app = createApp(App)

app.use(router)

app.mount('#app')
  • 若没有安装typescript,修改 src/main.js:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './assets/css/tailwind.css'

createApp(App)
  .use(router)
  .mount('#app')

二、核心组件实现

1.根组件(src/App.vue)

<template>
  <div class="min-h-screen flex flex-col">
    <Navbar class="fixed top-0 left-0 right-0 z-50 bg-white/90 backdrop-blur-sm shadow-sm" />
    <main class="flex-grow pt-16">
      <router-view />
    </main>
    <Footer class="bg-gray-900 text-white py-12" />
  </div>
</template>

<script setup>
import Navbar from './components/common/Navbar.vue'
import Footer from './components/common/Footer.vue'
</script>

2. 导航栏组件(src/components/common/Navbar.vue)

<template>
  <nav class="container mx-auto px-4 py-4 flex justify-between items-center">
    <!-- Logo -->
    <a href="/" class="flex items-center gap-2">
      <div class="w-10 h-10 bg-primary rounded-md flex items-center justify-center">
        <span class="text-white font-bold">C</span>
      </div>
      <span class="text-xl font-bold text-primary">Company</span>
    </a>

    <!-- 桌面菜单 -->
    <ul class="hidden md:flex gap-8">
      <li><router-link to="/" class="hover:text-primary transition-colors">首页</router-link></li>
      <li><router-link to="/about" class="hover:text-primary transition-colors">关于我们</router-link></li>
      <li><router-link to="/contact" class="hover:text-primary transition-colors">联系我们</router-link></li>
    </ul>

    <!-- 咨询按钮 -->
    <button class="hidden md:block bg-primary hover:bg-primary/90 text-white px-6 py-2 rounded-md transition-colors">
      立即咨询
    </button>

    <!-- 移动端菜单按钮 -->
    <button class="md:hidden" @click="isMenuOpen = !isMenuOpen">
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
        <line x1="3" y1="12" x2="21" y2="12"></line>
        <line x1="3" y1="6" x2="21" y2="6"></line>
        <line x1="3" y1="18" x2="21" y2="18"></line>
      </svg>
    </button>
  </nav>

  <!-- 移动端菜单 -->
  <div v-if="isMenuOpen" class="md:hidden bg-white border-t p-4">
    <ul class="flex flex-col gap-4">
      <li><router-link to="/" class="block py-2">首页</router-link></li>
      <li><router-link to="/about" class="block py-2">关于我们</router-link></li>
      <li><router-link to="/contact" class="block py-2">联系我们</router-link></li>
      <li><button class="w-full bg-primary text-white px-6 py-2 rounded-md">立即咨询</button></li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { RouterLink } from 'vue-router'
const isMenuOpen = ref(false)
</script>

3. 首页实现(src/views/Home.vue)

<template>
  <div>
    <!-- 英雄区 -->
    <section class="relative h-[90vh] overflow-hidden">
      <div class="absolute inset-0 bg-gradient-to-r from-primary/90 to-secondary/90 z-10"></div>
      <img 
        src="https://picsum.photos/id/1067/1920/1080" 
        alt="企业办公环境" 
        class="absolute inset-0 w-full h-full object-cover"
      >

      <div class="container mx-auto px-4 h-full flex items-center relative z-20">
        <div class="max-w-2xl text-white">
          <h1 class="mb-6 leading-tight">
            创新解决方案<br>
            驱动企业未来
          </h1>
          <p class="text-xl mb-8 text-white/90">
            10年行业经验,为500+企业提供数字化转型服务
          </p>
          <div class="flex flex-col sm:flex-row gap-4">
            <button class="bg-white text-primary hover:bg-gray-100 px-8 py-3 rounded-md font-medium transition-colors">
              了解服务
            </button>
            <button class="bg-transparent border border-white text-white hover:bg-white/10 px-8 py-3 rounded-md font-medium transition-colors">
              查看案例
            </button>
          </div>
        </div>
      </div>
    </section>

    <!-- 服务展示 -->
    <section class="py-20">
      <div class="container mx-auto px-4">
        <div class="text-center mb-16">
          <h2 class="mb-4">我们的服务</h2>
          <p class="text-gray-600 max-w-2xl mx-auto">专业团队提供全方位企业解决方案</p>
        </div>

        <div class="grid grid-cols-1 md:grid-cols-3 gap-8">
          <!-- 服务卡片 1 -->
          <div class="bg-white p-8 rounded-lg shadow-sm hover:shadow-md transition-shadow">
            <div class="w-14 h-14 bg-primary/10 text-primary rounded-full flex items-center justify-center mb-6">
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
                <path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
              </svg>
            </div>
            <h3 class="text-xl font-semibold mb-3">数字化转型</h3>
            <p class="text-gray-600">帮助企业实现业务流程数字化,提升运营效率</p>
          </div>

          <!-- 服务卡片 2 -->
          <div class="bg-white p-8 rounded-lg shadow-sm hover:shadow-md transition-shadow">
            <div class="w-14 h-14 bg-primary/10 text-primary rounded-full flex items-center justify-center mb-6">
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
                <line x1="8" y1="21" x2="16" y2="21"></line>
                <line x1="12" y1="17" x2="12" y2="21"></line>
              </svg>
            </div>
            <h3 class="text-xl font-semibold mb-3">云服务部署</h3>
            <p class="text-gray-600">提供云平台搭建与迁移服务,降低IT基础设施成本</p>
          </div>

          <!-- 服务卡片 3 -->
          <div class="bg-white p-8 rounded-lg shadow-sm hover:shadow-md transition-shadow">
            <div class="w-14 h-14 bg-primary/10 text-primary rounded-full flex items-center justify-center mb-6">
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline>
              </svg>
            </div>
            <h3 class="text-xl font-semibold mb-3">数据分析</h3>
            <p class="text-gray-600">通过大数据分析,为企业决策提供数据支持</p>
          </div>
        </div>
      </div>
    </section>
  </div>
</template>

4. 页脚组件(src/components/common/Footer.vue)

<template>
  <div class="container mx-auto px-4">
    <div class="grid grid-cols-1 md:grid-cols-4 gap-8 mb-12">
      <div>
        <h3 class="text-xl font-bold mb-4">Company</h3>
        <p class="text-gray-400 mb-4">专注于企业数字化转型的专业服务提供商</p>
        <div class="flex gap-4">
          <a href="#" class="text-gray-400 hover:text-white transition-colors">
            <i class="fab fa-facebook"></i>
          </a>
          <a href="#" class="text-gray-400 hover:text-white transition-colors">
            <i class="fab fa-twitter"></i>
          </a>
          <a href="#" class="text-gray-400 hover:text-white transition-colors">
            <i class="fab fa-linkedin"></i>
          </a>
        </div>
      </div>

      <div>
        <h4 class="text-lg font-semibold mb-4">快速链接</h4>
        <ul class="space-y-2">
          <li><a href="/" class="text-gray-400 hover:text-white transition-colors">首页</a></li>
          <li><a href="/about" class="text-gray-400 hover:text-white transition-colors">关于我们</a></li>
          <li><a href="/contact" class="text-gray-400 hover:text-white transition-colors">联系我们</a></li>
        </ul>
      </div>

      <div>
        <h4 class="text-lg font-semibold mb-4">服务</h4>
        <ul class="space-y-2">
          <li><a href="#" class="text-gray-400 hover:text-white transition-colors">数字化转型</a></li>
          <li><a href="#" class="text-gray-400 hover:text-white transition-colors">云服务部署</a></li>
          <li><a href="#" class="text-gray-400 hover:text-white transition-colors">数据分析</a></li>
        </ul>
      </div>

      <div>
        <h4 class="text-lg font-semibold mb-4">联系我们</h4>
        <ul class="space-y-2 text-gray-400">
          <li>邮箱:contact@company.com</li>
          <li>电话:400-123-4567</li>
          <li>地址:北京市朝阳区XX大厦</li>
        </ul>
      </div>
    </div>

    <div class="border-t border-gray-800 pt-8 text-center text-gray-500">
      <p>© 2023 Company. 保留所有权利</p>
    </div>
  </div>
</template>

<script setup>
// 引入Font Awesome图标库(需安装)
import '@fortawesome/fontawesome-free/css/all.min.css'
</script>

三、运行与预览

1.安装 Font Awesome 图标库(用于页脚社交图标):

pnpm install @fortawesome/fontawesome-free

2.启动开发服务器:

npm run dev

目录结构

company-website/
├─ public/               # 静态资源
├─ src/
│  ├─ assets/css/        # 样式文件
│  ├─ components/        # 组件
│  │  └─ common/         # 通用组件
│  ├─ views/             # 页面视图
│  ├─ router/            # 路由配置
│  ├─ App.vue            # 根组件
│  └─ main.js            # 入口文件
├─ tailwind.config.js    # Tailwind配置
└─ vite.config.js        # Vite配置

以下是基于 Vue 3 + Axios 的接口封装方案:

一、安装 Axios

pnpm install axios

二、创建接口封装文件

  • 在 src/utils/ 目录下创建 request.js,封装 Axios 实例和通用方法:
// src/utils/request.js
import axios from 'axios'

// 创建 Axios 实例
const request = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL || '/api', // 基础地址(从环境变量获取)
  timeout: 10000, // 超时时间
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  }
})

// 请求拦截器:添加 token、处理请求参数等
request.interceptors.request.use(
  (config) => {
    // 示例:添加认证 token(根据实际需求修改)
    const token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  (error) => {
    // 处理请求错误
    console.error('请求错误:', error)
    return Promise.reject(error)
  }
)

// 响应拦截器:处理响应数据、统一错误提示等
request.interceptors.response.use(
  (response) => {
    // 假设后端返回格式为 { code: 200, data: ..., message: '' }
    const res = response.data

    // 非成功状态(根据实际后端约定调整)
    if (res.code !== 200) {
      // 错误提示(可结合 UI 库的消息组件,如 Element Plus 的 ElMessage)
      console.error('接口错误:', res.message || '请求失败')
      return Promise.reject(new Error(res.message || '请求失败'))
    }

    // 只返回数据部分,简化使用
    return res.data
  },
  (error) => {
    // 处理网络错误、超时等
    console.error('响应错误:', error)

    // 分类错误提示
    if (error.message.includes('timeout')) {
      console.error('请求超时,请稍后重试')
    } else if (error.response) {
      const status = error.response.status
      switch (status) {
        case 401:
          console.error('未授权,请登录')
          // 可跳转登录页
          break
        case 404:
          console.error('接口不存在')
          break
        case 500:
          console.error('服务器错误')
          break
        default:
          console.error(`请求错误:${status}`)
      }
    } else {
      console.error('网络错误,请检查网络连接')
    }

    return Promise.reject(error)
  }
)

// 封装常用请求方法
export default {
  // GET 请求
  get(url, params = {}) {
    return request({
      url,
      method: 'get',
      params
    })
  },

  // POST 请求
  post(url, data = {}) {
    return request({
      url,
      method: 'post',
      data
    })
  },

  // PUT 请求
  put(url, data = {}) {
    return request({
      url,
      method: 'put',
      data
    })
  },

  // DELETE 请求
  delete(url, params = {}) {
    return request({
      url,
      method: 'delete',
      params
    })
  }
}

三、创建接口管理文件

  • 按模块划分接口,在 src/api/ 目录下创建对应文件(如官网常用的 home.js、contact.js 等):
// src/api/home.js
import request from '@/utils/request'

// 获取首页轮播图数据
export const getBannerList = () => {
  return request.get('/home/banner')
}

// 获取服务
export const getServiceList = () => {
  return request.get('/home/service')
}

// 获取客户案例
export const getCaseList = (params) => {
  return request.get('/home/cases', params)
}
// 提交联系表单
export const submitContactForm = (data) => {
  return request.post('/contact/submit', data)
}

四、配置环境变量(可选)

  • 在项目根目录创建 .env.development 和 .env.production 文件,区分开发 / 生产环境的接口地址:
# .env.development(开发环境)
VITE_API_BASE_URL = 'http://dev-api.company.com'
# .env.production(生产环境)
# VITE_API_BASE_URL = 'http://api.company.com'

五、在组件中使用

  • 在 Vue 组件中引入接口方法并使用:
<!-- src/views/Home.vue -->
<template>
  <div>
    <!-- 轮播图区域 -->
    <div v-if="banners.length">
      <div v-for="banner in banners" :key="banner.id">
        <img :src="banner.imageUrl" :alt="banner.title">
      </div>
    </div>
  </div>
</template>

<script setup>
import { onMounted, ref } from 'vue'
import { getBannerList, getServiceList } from '@/api/home'

// 轮播图数据
const banners = ref([])
// 服务列表数据
const services = ref([])

// 页面加载时获取数据
onMounted(async () => {
  try {
    // 并行请求多个接口
    const [bannerData, serviceData] = await Promise.all([
      getBannerList(),
      getServiceList()
    ])
    banners.value = bannerData
    services.value = serviceData
  } catch (error) {
    console.error('获取首页数据失败:', error)
  }
})
</script>

六、关键特性说明

  1. 统一基础配置:通过 Axios 实例设置基础地址、超时时间等,避免重复配置。
  2. 拦截器处理:
    • 请求拦截器:统一添加认证信息(如 token)、处理参数格式。
    • 响应拦截器:统一解析响应数据、处理错误(如网络错误、权限问题)。
  3. 模块化管理:按业务模块拆分接口,便于维护和查找。
  4. 环境区分:通过环境变量区分开发 / 生产接口地址,避免手动修改。
  5. 错误处理:集中处理各类错误,可结合 UI 库的消息组件(如 Element Plus 的 ElMessage)提供友好提示。