mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5
1105 字
6 分钟
全栈进阶:手撸核心业务逻辑

核心思考:理清前后端边界与状态流转#

从纯粹依赖外部代码片段提示,走向自主重构与组件设计,对 Prisma 数据建模、前端 Pinia 状态管理以及路由架构有了更深的认知。

  1. 路由的物理与逻辑边界: 从功能定位上理清了前端与后端路由的职责:

    • 前端路由 (Vue Router):控制视图层展现。基于 HTML5 History API 拦截 URL 变化并映射至对应视图组件,规避了全局重载。
    • 后端路由 (Express Router):控制资源与数据分发。遵循 RESTful 或其他规范对应至特定的业务逻辑/ Controller。 两者的解耦是现代前后端分离协作的地基。
  2. 单一数据源 (Single Source of Truth): 在重构跨路由媒体播放器状态(播放、暂停、进度)过程中,再次印证了状态集约化管理的收效。

    • 散列化反模式:视图容器、Audio 实例本身以及 LocalStorage 互相监听同步,将不可逆地引发状态撕裂和循环依赖。
    • 集约化正解:Pinia 承担绝对且唯一的状态代理(大脑),播放器组件仅执行响应,LocalStorage 负责挂载/卸载时的数据快照。所有变更一律流经 Store 声明的 Action 函数。

核心功能重构与实现路径解析#

1. 全栈开发流程 (Prisma + Express + Vue)#

场景:实现一个“用户列表”功能。

  • Step 1: 数据建模 (后端)schema.prisma 定义模型,这是数据的源头。

    model User {
    id Int @id @default(autoincrement())
    username String @unique
    role String @default("user")
    }

    执行 npx prisma db push 同步数据库。

  • Step 2: 接口开发 (后端)userController.ts 中写逻辑,在 index.ts 注册路由。

    // controller
    export const getUsers = async (req, res) => {
    const users = await prisma.user.findMany();
    res.json(users);
    };
    // router
    app.get('/api/users', getUsers);
  • Step 3: 状态管理 (前端)stores/user.ts 定义 Store。

    export const useUserStore = defineStore('user', () => {
    const userList = ref([]);
    const fetchUsers = async () => {
    const res = await fetch('/api/users');
    userList.value = await res.json();
    };
    return { userList, fetchUsers };
    });
  • Step 4: 视图渲染 (前端) 组件三部曲:Store -> Action -> Template。

    <script setup>
    const userStore = useUserStore();
    onMounted(() => userStore.fetchUsers());
    </script>
    <template>
    <div v-for="user in userStore.userList" :key="user.id">{{ user.username }}</div>
    </template>

2. 播放器状态持久化 (Pinia + LocalStorage)#

场景:刷新页面后,歌曲能接着上次的进度播放。

  • 核心逻辑

    1. :监听切歌 (watch) 和页面关闭 (beforeunload),将 currentSongcurrentTime 存入 localStorage。
    2. :Store 初始化时 (restoreState) 读取 localStorage。
    3. 同步:利用 <audio>loadedmetadata 事件,在音频元数据加载完成后,立即设置 currentTime
  • 关键代码 (Store)

    // 保存状态
    const saveState = () => {
    localStorage.setItem('player-state', JSON.stringify({
    song: currentSong.value,
    time: currentTime.value
    }));
    };
    // 恢复状态
    const restoreState = () => {
    const saved = localStorage.getItem('player-state');
    if (saved) {
    const { song, time } = JSON.parse(saved);
    currentSong.value = song;
    currentTime.value = time; // 恢复进度变量
    }
    };
    // 自动保存策略
    watch(currentSong, saveState); // 切歌存
    window.addEventListener('beforeunload', saveState); // 关窗存
    restoreState(); // 启动取
  • 关键代码 (组件)

    <audio
    ref="audioRef"
    @timeupdate="(e) => playerStore.currentTime = e.target.currentTime" <!-- DOM -> Store -->
    @loadedmetadata="audioRef.currentTime = playerStore.currentTime" <!-- Store -> DOM (断点续传) -->
    ></audio>

3. 每日推荐 (前端算法 + 缓存)#

场景:每天展示 10 首随机歌曲,当天刷新不变,第二天自动刷新。

  • 实现原理

    1. 检查缓存:对比 localStorage 里的日期和今天是否一致。
    2. 一致:直接用缓存里的 ID 列表去 Store 里找歌。
    3. 不一致:执行洗牌算法,生成新列表,存入缓存。
  • 关键代码

    const generateDailyRecommend = () => {
    const today = dayjs().format('YYYY-MM-DD');
    const cachedDate = localStorage.getItem('daily_date');
    if (cachedDate !== today) {
    // 洗牌算法:随机排序后取前10
    const randomSongs = [...songList.value]
    .sort(() => 0.5 - Math.random())
    .slice(0, 10);
    // 更新缓存
    localStorage.setItem('daily_date', today);
    localStorage.setItem('daily_ids', JSON.stringify(randomSongs.map(s => s.id)));
    recommendSongs.value = randomSongs;
    } else {
    // 走缓存逻辑...
    }
    };

4. 全局播放器架构 (Layout 提升)#

场景:切换路由(如从首页进专辑页),音乐不中断。

  • 问题根因: 原结构中,播放器组件 (AppFooterPlayerBar) 放在各个页面 (HomeView) 内部。路由切换会导致页面销毁 -> 播放器销毁 -> 音乐停止。

  • 解决方案: 将播放器提升到 App.vue 或全局 Layout 中,包裹 RouterView

  • 架构变更

    <!-- App.vue (新结构) -->
    <template>
    <BasicLayout>
    <!-- 播放器在这里,永远不销毁 -->
    <RouterView /> <!-- 只有这里的内容在变 -->
    </BasicLayout>
    </template>

总结#

阶段性的重构充分说明,“能够跑通”只满足工程阶段其一,组件树和全局状态树从一开始的合理化设计,对后续重构调试的增益要远远大于补丁代码产生的心智消耗。

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

全栈进阶:手撸核心业务逻辑
https://blog.moxiaoshuai.fun/2025-12-全栈进阶手撸核心逻辑/
作者
莫莫
发布于
2025-12-10
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

封面
示例歌曲
示例艺人
封面
示例歌曲
示例艺人
0:00 / 0:00