阅读视图

发现新文章,点击刷新页面。

从零搭一个 Vue 小家:用 Vite + 路由轻松入门现代前端开发

从零开始,轻松走进 Vue 的世界:一个“全家桶”小项目的搭建之旅

如果你刚刚接触前端开发,听到“Vue”、“Vite”、“路由”这些词时是不是有点懵?别担心!我们可以把写代码想象成搭积木、装修房子、甚至安排一场家庭旅行。今天,我们就通过一个名为 all-vue 的小项目,带你一步步理解现代 Vue 应用是怎么“搭起来”的。


🏠 第一步:选好地基——用 Vite 快速建项目

什么是vite?

Vite(法语,意为“快”)是一个由 Vue.js 作者 尤雨溪(Evan You) 主导开发的现代化前端构建工具。它旨在解决传统打包工具(如 Webpack)在开发阶段启动慢、热更新(HMR)延迟高等问题,提供极速的开发体验。

想象你要盖一栋房子。传统方式可能要先打地基、砌砖、铺电线……繁琐又耗时。而 Vite 就像一位超级高效的建筑承包商,你只要说一句:“我要一个 Vue 房子”,它立刻给你搭好框架,连水电都通好了!

在终端里运行:

npm init vite@latest all-vue -- --template vue

几秒钟后,你就得到了一个结构清晰的项目目录。其中最关键的是:

  • index.html:这是你房子的“大门”,浏览器一打开就看到它。
  • src/main.js:这是整栋房子的“总开关”,负责启动整个应用。
  • src/App.vue:这是“客厅”,所有房间(页面)都要从这里进出。

Vite 的优势在于——修改代码后,浏览器几乎瞬间刷新,就像你换了个沙发,家人马上就能坐上去试舒服不舒服。


🏗️ 第二步:认识整栋楼——项目结构概览

运行 npm init vite@latest all-vue -- --template vue 后,你会得到这样一栋“数字公寓”:

项目结构简略预览:

/all-vue
├── public/            # 公共资源(如 logo.png)
├── src/
│   ├── assets/        # 图片、字体等静态资源
│   ├── components/    # 可复用的小部件(按钮、卡片等)
│   ├── views/         # 独立页面(首页、关于页等)
|   |     |—— About.vue # 关于页面的Vue组件
|   |     |—— Home.vue # 主页的vue组件
│   ├── router/        # 室内导航系统
|   |     |—— index.js # 路由总控
│   ├── App.vue        # 中央控制台(客厅)
│   └── main.js        # 智能钥匙
├── index.html         # 入户大门
├── package.json       # 公寓的“住户手册 + 装修清单”
└── vite.config.js     # 建筑规范说明书

其中,package.json 就像这栋楼的住户手册 + 装修材料清单。打开它,你会看到:

{
  "name": "all-vue",
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "vue": "^3.4.0",
    "vue-router": "^4.3.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.0",
    "vite": "^5.0.0"
  }
}
  • dependencies:这是“入住必需品”,比如 Vue 框架本身、路由系统——没有它们,房子没法正常运转;
  • devDependencies:这是“装修工具包”,只在开发时用(比如 Vite 构建工具),住户入住后就不需要了;
  • scripts:这是“快捷指令”,比如 npm run dev 就是“启动预览模式”,npm run build 是“打包交付”。

有了这份清单,任何开发者都能一键还原你的整套环境——就像照着宜家说明书组装家具一样可靠。


🚪 第三步:认识“大门”——index.html 的两个秘密

虽然现代 Vue 应用的逻辑几乎全在 JavaScript 和 .vue 文件里,但一切的起点,其实是这个看似简单的 index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>all-vue</title>
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>
</html>

别小看这十几行代码,它藏着两个关键设计:

🔌 1. <div id="app"></div>:Vue 的“插座”

你可以把它想象成墙上预留的一个智能插座面板。它本身空无一物,但一旦通电(Vue 应用启动),就会自动“投影”出整个用户界面。

main.js 中,我们这样写:

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

这句话的意思就是:“请把 App.vue 这个‘客厅’的内容,投射到 id 为 app 的那个插座上。”
没有这个插座,Vue 再厉害也无处施展;有了它,动态内容才能在静态 HTML 中生根发芽。

⚡ 2. <script type="module" src="/src/main.js"></script>:原生 ES 模块的魔法

注意这里的 type="module"。这是现代浏览器支持的一种原生模块加载方式。传统脚本是“一股脑全塞进来”,而模块化脚本则像快递包裹——每个文件独立打包,按需引用,互不干扰。

Vite 正是利用了这一特性,无需打包即可直接在浏览器中运行模块化的代码。这意味着:

  • 开发时启动飞快(冷启动快);
  • 修改文件后热更新极快(HMR 精准替换);
  • 代码结构清晰,符合现代工程规范。

所以,index.html 不仅是入口,更是连接静态 HTML 世界动态 Vue 世界的桥梁。


🔑 第四步:打造“钥匙”——main.js 如何启动应用

有了大门,就得有钥匙。main.js 就是这把精密的电子钥匙,负责激活整套智能家居系统:

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './style.css'

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

这段代码做了三件事,环环相扣:

  1. 引入核心模块:从 Vue 拿到“造房子”的工具(createApp),从本地拿到“客厅设计图”(App.vue)和“导航系统”(router);
  2. 组装系统:用 .use(router) 把导航插件装进主程序;
  3. 插入插座.mount('#app') 表示:“请把这套系统通电安装在 index.html 中 id 为 app 的插座上。”

没有这把钥匙,再漂亮的客厅也只是一堆图纸;有了它,整个房子才真正“活”起来。


💡 第五步:点亮客厅——根组件 App.vue

钥匙转动,门开了,我们走进 App.vue —— 这是所有功能的总控中心:

<template>
  <div id="app">
    <nav>
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </nav>
    <router-view />
  </div>
</template>

多人一开始会直接写 <div>Home | About</div>,但这只是静态文字。要让它们变成可点击的导航,就得用 Vue Router 提供的 <router-link> 组件。

这里有两个核心元素:

  • <router-link> :智能门把手,点击不刷新页面,只切换内容;
  • <router-view /> :魔法地板,当前该展示哪个房间,它就实时投影出来。

虽然原始文件只写了 HomeAbout,但正确的写法应如上所示——让文字变成可交互的导航。


🗺️ 第六步:装上导航系统——配置 Vue Router

路由,就像是你家里的智能导航系统。没有它,你只能待在客厅;有了它,你才能自由穿梭于各个房间。

我们在 src/router/index.js 中这样配置:

import { createRouter, createWebHashHistory } from 'vue-router';
import Home from '../views/Home.vue'
import About from '../views/About.vue'

const routes = [
  { path: '/', name: 'Home', component: Home },
  { path: '/about', name: 'About', component: About }
]

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

export default router

这段代码的意思是:

  • 当用户访问 /(也就是主页),就显示 Home.vue 这个房间;
  • 当用户访问 /about,就带他去 About.vue 那个房间。

注意这里用了 createWebHashHistory(),这意味着网址会变成 http://localhost:5173/#/about。那个 # 就像门牌号里的“分隔符”,告诉系统:“后面的部分是内部房间号,不是新地址”。


🛋️ 第七步:布置房间——编写页面组件

现在,我们来装修两个房间。

首页(Home.vue)

<template>
  <div>
    <h1>Home</h1>
  </div>
</template>

关于页(About.vue)

<template>
  <div>
    <h1>About</h1>
  </div>
</template>

每个 .vue 文件都是一个自包含的“功能单元”:有自己的结构(template)、逻辑(script)和样式(style)。它们彼此隔离,却能通过路由无缝切换。


🎨 第八步:美化家园——全局样式 style.css

虽然功能齐备,但房子还是灰扑扑的。这时候,style.css 就派上用场了。你可以在这里写:

body {
  font-family: 'Arial', sans-serif;
  background-color: #f5f5f5;
}

nav {
  padding: 1rem;
  background: white;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

就像给墙壁刷漆、给地板打蜡,让整个家更温馨舒适。


▶️ 最后一步:启动你的 Vue 家园!

现在,所有“装修材料”都已就位——地基打好了(Vite 项目)、大门装上了(index.html)、钥匙配好了(main.js)、客厅布置妥当(App.vue),连房间(Home.vueAbout.vue)和导航系统(Vue Router)也都调试完毕。是时候打开电闸,点亮整栋房子了!

请在终端(命令行)中依次执行以下两条命令(确保你已在 all-vue 项目目录下):

# 第一步:安装“住户手册”里列出的所有依赖(比如 Vue 和路由)
npm install

# 第二步:启动开发服务器——相当于按下“智能家居总开关”
npm run dev

运行成功后,你会看到类似这样的提示:

  VITE v5.0.0  ready in 320 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

这时,只需打开浏览器,访问 http://localhost:5173/ (端口号可能略有不同),就能看到你的 Vue 小家啦!

image.png

  • 点击 Home,客厅中央显示 “Home”;
  • 点击 About,瞬间切换到 “About” 页面——全程无需刷新,就像在家自由走动一样丝滑。

🎉 恭喜你!你不仅看懂了代码,还亲手让它跑起来了!

这不再是一堆抽象的文件,而是一个真正能交互的 Web 应用。你已经完成了从“零”到“一”的飞跃——而这,正是所有伟大项目的起点。


🧩 总结:Vue 项目的“生活化”逻辑链

让我们用一次智能家居入住体验来串起全过程:

  1. Vite 是开发商:提供标准化精装修样板间;
  2. index.html 是入户门:设有智能插座(#app)和模块化接线口(type="module");
  3. main.js 是电子钥匙:插入后激活整套系统;
  4. App.vue 是中央控制台:集成导航与内容展示区;
  5. Vue Router 是室内导航图:定义各房间路径;
  6. Home.vue / About.vue 是功能房间:各自独立,按需进入;
  7. style.css 是全屋软装方案:统一视觉风格。

✨ 写在最后:你已经站在 Vue 的门口

这个 all-vue 项目虽小,却包含了现代 Vue 应用的核心骨架:组件化 + 路由 + 响应式 + 工程化构建。你不需要一开始就懂所有细节,就像学骑自行车,先扶稳车把,再慢慢蹬脚踏。

当你运行 npm run dev,看到浏览器里出现“Home”和“About”两个链接,并能自由切换时——恭喜你,你已经成功迈出了 Vue 开发的第一步!

接下来,你可以:

  • 在 Home 里加一张图片;
  • 在 About 里写一段自我介绍;
  • 用 CSS 让导航栏变彩色;
  • 甚至添加第三个页面……

编程不是魔法,而是一步步搭建的过程。而你,已经搭好了第一块积木。

现代前端工程化实战:从 Vite 到 React Router demo的构建之旅

前端技术的迭代从未停歇。当我们谈论现代前端开发时,React 19Vite 已经成为了不可忽视的标准配置。React 19 带来了更高效的并发渲染机制,而 Vite 则凭借基于 ESM 的极致冷启动速度,彻底改变了开发体验。

本文将通过一个名为 react-demo 的实战项目,带你从零开始理解如何搭建、配置并开发一个标准的现代 React 应用。我们将涵盖工程化配置、路由管理、Hooks 状态逻辑以及样式预处理等核心知识点。

一、 极速启动:Vite 与 ESM 的革命

在过去,Webpack 是构建工具的王者,但它在启动大型项目时往往需要漫长的打包等待。现代开发推荐使用 Vite(法语意为“快”)作为脚手架。

1. 为什么是 Vite?

Vite 的核心优势在于它利用了浏览器原生的 ES Modules (ESM) 机制。在开发阶段 (npm run dev),Vite 不需要对代码进行全量打包,而是按需提供模块,这实现了极致的“冷启动”体验。

当我们运行 npm init vite 拉取项目模板后,项目结构非常清晰。观察项目的 package.json 脚本配置:

"scripts": {
  "dev": "vite",
  "build": "vite build",
  "preview": "vite preview"
}

这对应了完整的开发生命周期:dev(开发) -> build(构建生产包) -> preview(本地预览生产包)。

2. 依赖管理的艺术:Dev vs Prod

在安装依赖时,区分“开发依赖”和“生产依赖”至关重要。

  • dependencies (生产依赖) :如 reactreact-dom。React 19.2.0 是核心库,负责组件定义和 diff 算法;而 react-dom 负责将组件渲染到浏览器 DOM 中。这类似于 Vue 的生态,React Core 对应 Vue Core,React DOM 对应 Vue 的渲染器。对应配置为 package.json 中的dependencies
  • devDependencies (开发依赖) :如 stylus。我们使用 npm i -D stylus 安装它,因为 Stylus 只是在开发阶段帮助我们将 .styl 文件编译为 CSS,上线后的代码并不需要 Stylus 引擎。对应配置为 package.json 中的devDependencies
// 生产依赖
  "dependencies": {
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "react-router-dom": "^7.10.1"
  },
// 开发依赖
  "devDependencies": {
    "@eslint/js": "^9.39.1",
    "@types/react": "^19.2.5",
    "@types/react-dom": "^19.2.3",
    "@vitejs/plugin-react": "^5.1.1",
    "eslint": "^9.39.1",
    "eslint-plugin-react-hooks": "^7.0.1",
    "eslint-plugin-react-refresh": "^0.4.24",
    "globals": "^16.5.0",
    "stylus": "^0.64.0",
    "vite": "^7.2.4"
  }

二、 入口与渲染:React 19 的严谨模式

项目的入口文件 main.jsx 展示了 React 19 最标准的挂载方式。

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.styl'
import App from './App.jsx'

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

严格模式 (StrictMode)

你可能会发现,在开发环境下组件的生命周期函数(如 useEffect)会执行两次。这并非 Bug,而是 <StrictMode> 的有意为之。它通过双重调用来帮助开发者检测不安全的副作用(Side Effects)和过时的 API 使用,确保代码在生产环境中更加健壮。

样式预处理

我们引入了全局样式 index.styl。Stylus 的魅力在于其极简的语法——省略花括号、冒号和分号,通过缩进来组织代码:

*
  margin: 0
  padding: 0

body
  background-color pink

Vite 内置了对 CSS 预处理器的支持,无需繁琐的 Webpack Loader 配置,安装即用,安装指令为npm i -D stylus。其中的-D就代表了开发依赖,如果不书写-D则会默认安装至生产依赖。

三、 路由架构:单页应用的骨架

单页应用(SPA)的核心在于:页面不刷新,URL 改变,内容切换,在一个页面 (index.html) 中实现 "多页面" 的切换效果。我们使用 react-router-dom v7 来实现这一功能。首先需要通过npm i react-router-dom指令安装路由。

1. 路由模式选择

App.jsx 中,我们采用了 BrowserRouter(别名为 Router)。相比于 URL 中带有 # 号的 HashRouterBrowserRouter 利用 HTML5 History API,提供了更现代化、更美观的 URL 结构,是目前的行业标准。

2. 声明式导航:Link vs A

在 React Router 中,我们严禁使用传统的 <a href> 标签进行内部跳转。因为 <a> 标签会导致浏览器强制刷新页面,从而重置 React 的所有状态。

相反,我们使用 <Link> 组件:

<nav>
  <ul>
    <li><Link to="/">Home</Link></li>
    <li><Link to="/about">About</Link></li>
  </ul>
</nav>

<Link> 组件在内部“消化”了点击事件,通过 JavaScript 修改 URL 并通过 Context 通知路由系统更新视图,实现了无缝的页面切换。

3. 路由配置分离

为了保持代码的整洁,我们将具体的路由规则抽离到了 router/index.jsx 中:

import { Routes, Route } from 'react-router-dom';
import Home from '../pages/Home.jsx';
import About from '../pages/About.jsx';

export default function AppRoutes() {
    return (
        <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/about" element={<About />} />
        </Routes>
    )
}

这种集中管理路由表的方式,使得 App.jsx 只需关注整体布局,而将路由细节交给 AppRoutes 组件处理。

四、 核心业务逻辑:Hooks 驱动的数据流

Home.jsx 组件展示了 React 函数式组件的核心逻辑:Hooks。我们的目标是调用 GitHub API 并展示数据。

1. 响应式状态:useState

const [repos, setRepos] = useState([]);

useState 是 React 响应式系统的基石。它返回当前状态 repos 和更新函数 setRepos。每当调用 setRepos 时,React 就会感知数据变化,并触发组件的重新渲染(Re-render),更新视图。

2. 副作用管理:useEffect

网络请求属于“副作用”(Side Effect),不能直接写在组件渲染逻辑中。我们使用 useEffect 来处理组件挂载后的逻辑:

useEffect(() => {
    // 组件挂载完成 (onMounted)
    fetch('https://api.github.com/users/shunwuyu/repos')
        .then(res => res.json())
        .then(json => setRepos(json))
}, [])
  • 执行时机useEffect 确保代码在组件渲染并挂载到 DOM 之后执行,避免阻塞 UI 渲染。
  • 依赖数组 [] :第二个参数传入空数组 [],意味着这个 Effect 只在组件初始化时执行一次(相当于类组件的 componentDidMount)。如果不传此参数,每次渲染都会触发请求,导致无限循环。

3. 条件渲染与列表 Key

在 JSX 中,我们利用 JavaScript 的灵活性来构建 UI。

return (
        <div>
            <h1>Home</h1>
            {
                repos.length ? (
                    <ul>
                        {
                            repos.map(repo => (
                                <li key={repo.id}>
                                    <a href={repo.html_url} target="_blank" rel="noreferrer">
                                        {repo.name}
                                    </a>
                                </li>
                            ))
                        }
                    </ul>
                ) : null
            }
        </div>
    );
  • Diff 算法的关键:在遍历列表时,必须为每个元素提供唯一的 key(如 repo.id)。这能帮助 React 的 Diff 算法高效地识别元素的增删改,最小化 DOM 操作。
  • 条件渲染:通过三元运算符检查 repos.length,在数据加载前不渲染列表,防止页面报错。

五、 总结

通过这个项目,我们不仅搭建了一个简单的 GitHub 仓库浏览器,更重要的是实践了现代 React 开发的标准范式:

  1. 工程化:利用 Vite 极速构建,区分开发与生产依赖。
  2. 组件化:通过 Props 和 Hooks 实现逻辑复用。
  3. 路由化:使用 React Router 实现 SPA 的无感跳转。
  4. 响应式:利用 useStateuseEffect 驱动数据流向。

从 React 19 的底层优化到 Vite 的工程实践,这套技术栈为开发者提供了极其高效的开发体验,是构建未来 Web 应用的坚实基础。

六、Home.jsx 源代码

import { useState, useEffect } from 'react';

const Home = () => {
    const [repos, setRepos] = useState([]);
    // render 是第一位的
    // console.log('Home 组件渲染了');
    useEffect(() => {
        // home 组件可以看到了
        // console.log('Home 组件挂载了');
        // 发送api请求,不会和组件渲染去争抢
        fetch('https://api.github.com/users/shunwuyu/repos')
            .then(res => res.json())
            .then(json => setRepos(json))
    }, [])
    return (
        <div>
            <h1>Home</h1>
            {
                repos.length ? (
                    <ul>
                        {
                            repos.map(repo => (
                                <li key={repo.id}>
                                    <a href={repo.html_url} target="_blank" rel="noreferrer">
                                        {repo.name}
                                    </a>
                                </li>
                            ))
                        }
                    </ul>
                ) : null
            }
        </div>
    );
}

export default Home;
❌