回顾运行4条命令后

接【第三步+前后端分离调】,装好所以依赖运行命令后

其实后面有5步

比如:你想在D:\Code\wslant-Frontend这文件夹中建立一个vue3项目
那么你就:开始-运行-cmd-

第一步:进入你要创建项目的文件夹
cd D:\Code\wslant-Frontend
第二步:创建Vue3项目骨架
npm create vite@latest vue-project -- --template vue
第三步: 进入项目文件夹(如果你创建第2个vue3项目这步装过的会直接跳过生成vue3项目)
cd vue-project
第四步: 安装所有基础依赖(第2个vue3项目这步会跳过
npm install
第五步:启动项目(第2个vue3项目会直接启动
npm run dev

就会得到Vs Code中的Vue3标准的项目完整结构

项目结构还原:从 0 到 Vue 项目完整结构

我帮你把「从 0 到生成这个项目文件结构」的完整过程,按你之前的操作一步步还原出来,你照着回忆一下就懂了��

一、还原你的完整操作流程(和你之前的步骤完全对应)

第 1 步:创建项目骨架(生成大部分文件)

你在终端执行了创建命令,这一步就生成了除了node_modulespackage-lock.json之外的所有文件 / 文件夹:

bash
npm create vite@latest vue-project -- --template vue

这一步是「搭房子」,自动复制了 Vue3 + Vite 模板里的所有基础文件,包括:

  • src/ 文件夹(含App.vuemain.jsrouter等)
  • index.htmlpackage.jsonvite.config.js 等配置文件

第 2 步:进入项目文件夹

bash
cd vue-project

第 3 步:执行 npm install(生成依赖相关文件)

这一步才会下载依赖,生成你看到的:

  • node_modules/ 文件夹(所有第三方依赖都在这里)
  • package-lock.json(锁定依赖版本)

第 4 步(可选):安装了额外依赖(比如 axios)

bash
npm install axios

这一步会更新package.jsonpackage-lock.json,但不会生成新的文件夹,只会往node_modules里加东西。

第 5 步:用 VS Code 打开项目

你在 VS Code 里打开了vue-project文件夹,所以在资源管理器里看到了完整的项目结构。

二、总结标记下:哪些是哪一步生成的

文件 / 文件夹

生成时机

.vscode/public/src/

第 1 步 npm create vite@latest

index.htmlpackage.jsonvite.config.js

第 1 步 npm create vite@latest

node_modules/package-lock.json

第 3 步 npm install

router/stores/

模板自带,也是第 1 步生成

你真正可能会改或者可能会改的文件

超精简版

Vue3 项目真正需要手动修改、经常用到的文件只有 5 个:

  1. src/router/index.js → 页面路由(跳转)
  2. src/stores/ → 全局状态(共享数据)
  3. src/App.vue → 主页面组件
  4. src/main.js → 项目入口配置
  5. vite.config.js → 跨域、端口、代理

目前我们这个项目就只改了src/App.vue → 主页面组件

再给你确认一遍:

  • 前端:只改了 App.vue,其他文件(main.js、vite.config.js 等)全都没动
  • 后端:改了 5 个文件
    • ScoreServlet.java ✅
    • test11.java ✅
    • web.xml ✅
    • index.jsp ✅
    • register.html ✅


      App.vue的代码
       

      <template>

        <!-- 页面最外层容器,控制整体布局和样式 -->

        <div class="container">

          <!-- 页面标题:成绩录入系统,标注技术栈 Vue3 + Java 后端 -->

          <h1>📚 成绩录入系统(Vue3 + Java 后端)</h1>

          <!-- 表单区域,用于输入学生人数和成绩 -->

          <div class="form">

            <!-- 表单项:输入学生人数 -->

            <div class="form-item">

              <label>学生人数:</label>

              <!--

                输入框:

                type="number" 只能输入数字

                v-model.number="n" 双向绑定到变量 n,并且自动转数字类型

                min="1" 最小值为1

                placeholder 提示文字

              -->

              <input type="number" v-model.number="n" min="1" placeholder="请输入人数" />

            </div>

            <!--

              成绩输入区域:

              v-if="n > 0" 只有当学生人数大于0时才显示这一整块

            -->

            <div class="form-item" v-if="n > 0">

              <label>成绩列表:</label>

              <div class="scores">

                <!--

                  循环生成成绩输入框:

                  v-for="(s, index) in scores" 遍历 scores 数组,生成对应数量的输入框

                  :key="index" 循环必须加 key,提高 Vue 渲染效率

                  v-model.number="scores[index]" 双向绑定数组里的每一项成绩

                  type="number" 数字输入

                  min="0" 最低分0

                  max="100" 最高分100

                  placeholder 显示“第x科成绩”

                -->

                <input

                  v-for="(s, index) in scores"

                  :key="index"

                  v-model.number="scores[index]"

                  type="number"

                  min="0"

                  max="100"

                  placeholder="第{{ index + 1 }}科成绩"

                />

              </div>

            </div>

            <!--

              提交按钮:

              @click="submit" 点击时执行 submit 函数

              :disabled="loading" 提交中时按钮禁用,防止重复点击

              按钮文字:loading 时显示“提交中...”,否则显示正常文字

            -->

            <button @click="submit" :disabled="loading">

              {{ loading ? "提交中..." : "提交计算平均分" }}

            </button>

          </div>

          <!--

            结果展示区域:

            v-if="result" 只有拿到后端返回结果后才显示

          -->

          <div class="result" v-if="result">

            <h2>✅ 计算结果</h2>

            <!-- 展示后端返回的平均分 -->

            <p>平均分:{{ result.avg }}</p>

            <!-- 展示后端返回的成绩列表 -->

            <p>成绩列表:{{ result.scores }}</p>

          </div>

        </div>

      </template>

      <!-- Vue3 组合式API 脚本 -->

      <script setup>

      // 导入 Vue 提供的响应式函数:ref(定义基础类型响应式变量)、watch(监听变量变化)

      import { ref, watch } from "vue";

      // 学生人数 n,默认值为 1,响应式变量

      const n = ref(1);

      // 成绩数组,默认有1个成绩0,会根据人数 n 自动生成对应长度

      const scores = ref([0]);

      // 加载状态:提交时为 true,按钮置灰;结束后为 false

      const loading = ref(false);

      // 存储后端返回的计算结果(平均分、成绩列表),默认 null

      const result = ref(null);

      // 监听器:监听学生人数 n 的变化

      watch(n, (newVal) => {

        // 当人数改变时,自动重置成绩数组:长度为新人数,全部填充 0

        scores.value = Array(newVal).fill(0);

      });

      // 提交函数:把成绩发给 Java 后端,获取平均分

      const submit = async () => {

        // 开始提交,设置加载中

        loading.value = true;

        try {

          // 1. 拼接请求参数(拼接成后端能识别的格式)

          const params = new URLSearchParams();

          // 添加学生人数参数

          params.append("n", n.value);

          // 循环把每一个成绩添加到参数里:score0, score1, score2...

          scores.value.forEach((score, index) => {

            params.append(`score${index}`, score);

          });

          // 2. 发送 GET 请求到 Java 后端接口

          const res = await fetch("http://localhost:8089/wslant/scoreServlet?" + params.toString(), {

            method: "GET", // 请求方式:GET

          });

          // 3. 把后端返回的数据转成 JSON 格式

          const data = await res.json();

          // 4. 把结果存到 result 中,页面自动渲染

          result.value = data;

        } catch (err) {

          // 请求失败:弹出提示 + 控制台打印错误

          alert("请求失败:" + err.message);

          console.error(err);

        } finally {

          // 无论成功/失败,最后都关闭加载状态

          loading.value = false;

        }

      };

      </script>

      <!-- 局部样式,只对当前组件生效 -->

      <style scoped>

      /* 最外层容器:宽度、居中、内边距、字体 */

      .container {

        max-width: 600px;

        margin: 50px auto;

        padding: 20px;

        font-family: Arial, sans-serif;

      }

      /* 表单背景、内边距、圆角 */

      .form {

        background: #f5f5f5;

        padding: 20px;

        border-radius: 8px;

      }

      /* 表单项间距 */

      .form-item {

        margin-bottom: 15px;

      }

      /* 标签样式:独占一行、下边距、加粗 */

      label {

        display: block;

        margin-bottom: 5px;

        font-weight: bold;

      }

      /* 输入框样式:内边距、边框、圆角 */

      input {

        padding: 8px;

        border: 1px solid #ddd;

        border-radius: 4px;

      }

      /* 成绩输入框布局:弹性布局、自动换行、间距 */

      .scores {

        display: flex;

        flex-wrap: wrap;

        gap: 10px;

      }

      /* 按钮样式:背景色、文字颜色、无边框、圆角、鼠标手势 */

      button {

        padding: 10px 20px;

        background: #42b983;

        color: white;

        border: none;

        border-radius: 4px;

        cursor: pointer;

      }

      /* 按钮禁用时的样式:灰色背景 */

      button:disabled {

        background: #ccc;

      }

      /* 结果区域:上边距、内边距、边框、圆角 */

      .result {

        margin-top: 20px;

        padding: 15px;

        border: 1px solid #42b983;

        border-radius: 8px;

      }

      </style>

更多推荐