前端零基础教程(六):综合实战项目

通过完整的实战项目,综合运用HTML、CSS、JavaScript、Vue.js等知识,构建真实的前端应用

前端零基础教程(六):综合实战项目

通过前面的学习,我们已经掌握了 HTML、CSS、JavaScript 和 Vue.js 的基础知识。本文将通过完整的实战项目,综合运用所学知识,构建真实的前端应用。

第一章:项目规划(第 1 周)

1.1 项目选择

推荐项目类型

  • 待办事项应用:功能完整,适合初学者
  • 博客系统:内容管理,学习 CRUD
  • 电商网站:商品展示、购物车、订单
  • 社交平台:用户系统、内容发布、互动

1.2 项目需求分析

功能需求

  • 用户功能:注册、登录、个人中心
  • 核心功能:根据项目类型确定
  • 辅助功能:搜索、筛选、排序

技术需求

  • 前端框架:Vue.js 3
  • 路由管理:Vue Router
  • 状态管理:Pinia
  • UI 组件:Element Plus 或 Ant Design Vue
  • HTTP 请求:Axios

1.3 项目结构设计

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
my-project/
├── public/
│   └── index.html
├── src/
│   ├── assets/          # 静态资源
│   │   ├── images/
│   │   └── styles/
│   ├── components/      # 公共组件
│   │   ├── Header.vue
│   │   ├── Footer.vue
│   │   └── Loading.vue
│   ├── views/           # 页面组件
│   │   ├── Home.vue
│   │   ├── Login.vue
│   │   └── Profile.vue
│   ├── router/          # 路由配置
│   │   └── index.js
│   ├── stores/          # 状态管理
│   │   └── user.js
│   ├── api/             # API 接口
│   │   └── index.js
│   ├── utils/           # 工具函数
│   │   └── request.js
│   ├── App.vue
│   └── main.js
├── .eslintrc.js
├── .prettierrc
├── package.json
├── vite.config.js
└── README.md

第二章:项目一:个人博客系统(第 2-4 周)

2.1 项目功能

核心功能

  • 文章列表:展示所有文章
  • 文章详情:查看文章内容
  • 文章管理:添加、编辑、删除文章
  • 分类标签:文章分类和标签
  • 搜索功能:搜索文章

2.2 技术栈

  • Vue 3:前端框架
  • Vue Router:路由管理
  • Pinia:状态管理
  • Axios:HTTP 请求
  • Element Plus:UI 组件库

2.3 项目实现

路由配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// router/index.js
import { createRouter, createWebHistory } from "vue-router";
import Home from "../views/Home.vue";
import ArticleDetail from "../views/ArticleDetail.vue";
import ArticleEdit from "../views/ArticleEdit.vue";

const routes = [
  {
    path: "/",
    name: "Home",
    component: Home,
  },
  {
    path: "/article/:id",
    name: "ArticleDetail",
    component: ArticleDetail,
  },
  {
    path: "/edit/:id?",
    name: "ArticleEdit",
    component: ArticleEdit,
  },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

状态管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// stores/article.js
import { defineStore } from "pinia";
import { ref } from "vue";

export const useArticleStore = defineStore("article", {
  state: () => ({
    articles: [],
    currentArticle: null,
    loading: false,
  }),
  actions: {
    async fetchArticles() {
      this.loading = true;
      try {
        // 模拟 API 调用
        const response = await fetch("/api/articles");
        this.articles = await response.json();
      } catch (error) {
        console.error("获取文章失败:", error);
      } finally {
        this.loading = false;
      }
    },
    async fetchArticle(id) {
      this.loading = true;
      try {
        const response = await fetch(`/api/articles/${id}`);
        this.currentArticle = await response.json();
      } catch (error) {
        console.error("获取文章详情失败:", error);
      } finally {
        this.loading = false;
      }
    },
    async createArticle(article) {
      // 创建文章逻辑
    },
    async updateArticle(id, article) {
      // 更新文章逻辑
    },
    async deleteArticle(id) {
      // 删除文章逻辑
    },
  },
});

首页组件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!-- views/Home.vue -->
<template>
  <div class="home">
    <div class="search-bar">
      <el-input
        v-model="searchQuery"
        placeholder="搜索文章"
        @keyup.enter="handleSearch"
      >
        <template #append>
          <el-button @click="handleSearch">搜索</el-button>
        </template>
      </el-input>
    </div>

    <div class="article-list" v-loading="articleStore.loading">
      <ArticleCard
        v-for="article in filteredArticles"
        :key="article.id"
        :article="article"
      />
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from "vue";
import { useArticleStore } from "@/stores/article";
import ArticleCard from "@/components/ArticleCard.vue";

const articleStore = useArticleStore();
const searchQuery = ref("");

const filteredArticles = computed(() => {
  if (!searchQuery.value) {
    return articleStore.articles;
  }
  return articleStore.articles.filter(
    (article) =>
      article.title.includes(searchQuery.value) ||
      article.content.includes(searchQuery.value)
  );
});

const handleSearch = () => {
  // 搜索逻辑已在 computed 中实现
};

onMounted(() => {
  articleStore.fetchArticles();
});
</script>

文章卡片组件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!-- components/ArticleCard.vue -->
<template>
  <el-card class="article-card" @click="goToDetail">
    <template #header>
      <h3>{{ article.title }}</h3>
    </template>
    <p class="summary">{{ article.summary }}</p>
    <div class="meta">
      <span class="date">{{ formatDate(article.createdAt) }}</span>
      <el-tag v-for="tag in article.tags" :key="tag" class="tag">
        {{ tag }}
      </el-tag>
    </div>
  </el-card>
</template>

<script setup>
import { useRouter } from "vue-router";

const props = defineProps({
  article: {
    type: Object,
    required: true,
  },
});

const router = useRouter();

const goToDetail = () => {
  router.push(`/article/${props.article.id}`);
};

const formatDate = (date) => {
  return new Date(date).toLocaleDateString("zh-CN");
};
</script>

第三章:项目二:电商网站(第 4-6 周)

3.1 项目功能

核心功能

  • 商品展示:商品列表、商品详情
  • 购物车:添加、删除、修改商品
  • 订单管理:创建订单、订单列表
  • 用户系统:注册、登录、个人中心

3.2 技术实现

购物车 Store

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// stores/cart.js
import { defineStore } from "pinia";

export const useCartStore = defineStore("cart", {
  state: () => ({
    items: [],
  }),
  getters: {
    totalPrice: (state) => {
      return state.items.reduce((total, item) => {
        return total + item.price * item.quantity;
      }, 0);
    },
    itemCount: (state) => {
      return state.items.reduce((count, item) => {
        return count + item.quantity;
      }, 0);
    },
  },
  actions: {
    addItem(product) {
      const existingItem = this.items.find((item) => item.id === product.id);
      if (existingItem) {
        existingItem.quantity++;
      } else {
        this.items.push({
          ...product,
          quantity: 1,
        });
      }
    },
    removeItem(productId) {
      const index = this.items.findIndex((item) => item.id === productId);
      if (index > -1) {
        this.items.splice(index, 1);
      }
    },
    updateQuantity(productId, quantity) {
      const item = this.items.find((item) => item.id === productId);
      if (item) {
        item.quantity = quantity;
      }
    },
    clearCart() {
      this.items = [];
    },
  },
});

商品列表组件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!-- views/ProductList.vue -->
<template>
  <div class="product-list">
    <div class="filters">
      <el-select v-model="selectedCategory" placeholder="选择分类">
        <el-option
          v-for="category in categories"
          :key="category"
          :label="category"
          :value="category"
        />
      </el-select>
    </div>

    <div class="products">
      <ProductCard
        v-for="product in filteredProducts"
        :key="product.id"
        :product="product"
        @add-to-cart="handleAddToCart"
      />
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from "vue";
import { useCartStore } from "@/stores/cart";
import ProductCard from "@/components/ProductCard.vue";

const cartStore = useCartStore();
const selectedCategory = ref("");
const products = ref([]);
const categories = ref(["全部", "电子产品", "服装", "食品"]);

const filteredProducts = computed(() => {
  if (!selectedCategory.value || selectedCategory.value === "全部") {
    return products.value;
  }
  return products.value.filter((p) => p.category === selectedCategory.value);
});

const handleAddToCart = (product) => {
  cartStore.addItem(product);
  ElMessage.success("已添加到购物车");
};
</script>

第四章:项目优化(第 6 周)

4.1 性能优化

代码分割

1
2
3
4
5
6
7
// 路由懒加载
const routes = [
  {
    path: "/about",
    component: () => import("../views/About.vue"),
  },
];

图片优化

1
2
3
4
5
6
7
8
<template>
  <img
    :src="imageSrc"
    :alt="imageAlt"
    loading="lazy"
    @error="handleImageError"
  />
</template>

4.2 SEO 优化

元数据管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<script setup>
import { useHead } from "@unhead/vue";

useHead({
  title: "页面标题",
  meta: [
    { name: "description", content: "页面描述" },
    { property: "og:title", content: "页面标题" },
  ],
});
</script>

4.3 错误处理

全局错误处理

1
2
3
4
5
// main.js
app.config.errorHandler = (err, instance, info) => {
  console.error("全局错误:", err);
  // 错误上报逻辑
};

第五章:项目部署(第 6 周)

5.1 构建项目

1
2
3
4
5
# 构建生产版本
npm run build

# 预览构建结果
npm run preview

5.2 部署到服务器

静态文件部署

1
2
# 将 dist 目录上传到服务器
scp -r dist/* user@server:/var/www/html/

Nginx 配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
server {
    listen 80;
    server_name example.com;
    root /var/www/html;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

5.3 CI/CD 部署

GitHub Actions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
      - run: npm install
      - run: npm run build
      - name: Deploy to server
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_KEY }}
          source: "dist/*"
          target: "/var/www/html"

第六章:学习总结

6.1 知识回顾

前端三剑客

  • HTML:网页结构
  • CSS:网页样式
  • JavaScript:网页交互

现代前端

  • Vue.js:前端框架
  • 工程化:开发工具链
  • 项目实战:综合应用

6.2 下一步学习

进阶方向

  • TypeScript:类型安全开发
  • SSR/Nuxt.js:服务端渲染
  • 微前端:大型应用架构
  • 性能优化:深入性能优化

持续学习

  • 关注新技术:关注前端新技术
  • 参与开源:参与开源项目
  • 技术分享:写博客、做分享
  • 项目实践:多做项目实践

结语:从零基础到独立开发

通过这六篇教程的学习,你已经掌握了:

  1. HTML 基础:网页结构创建
  2. CSS 基础:网页样式设计
  3. JavaScript 基础:网页交互实现
  4. Vue.js 框架:现代前端开发
  5. 工程化工具:开发工具链
  6. 项目实战:完整项目开发

记住,前端学习是一个持续的过程:

  • 多实践:通过项目巩固知识
  • 理解原理:理解技术背后的原理
  • 关注趋势:关注前端技术趋势
  • 持续学习:保持学习热情

愿你在前端开发的道路上不断进步,创造出优秀的作品!

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计