# 搭建聊天室(前端 vue3 + pinia + axios + elementplus)01 搭建项目基本框架

# 一、项目技术栈选型

vue3:

  • 更小的包大小:Vue 3 通过使用模块化架构和逐渐引入编译时的 Tree-shaking,可以产生更小的包大小,提高应用程序的加载速度。
  • 更好的性能:Vue 3 对响应式系统进行了全面重写,提供了更好的性能和内存利用率。
  • Composition API:Vue 3 引入了 Composition API,使得组件逻辑更加可组合和可重用。

pinia:

  • 类型安全:Pinia 是一个状态管理库,基于 Vue 3 的响应式系统,并且提供了类型安全的状态管理解决方案。
  • 插件化:Pinia 支持插件机制,可以扩展它的功能,例如中间件、插件等。
  • 简洁易用:Pinia 提供了简洁的 API 和开发体验,使得状态管理变得更加直观和容易。

vue-router:

  • 路由管理:Vue Router 是 Vue 官方提供的路由管理库,可以帮助你实现单页面应用的路由控制。
  • 嵌套路由:Vue Router 支持嵌套路由,可以更好地组织和管理你的应用程序。
  • 导航守卫:Vue Router 提供了导航守卫机制,可以在路由切换前后执行相应的逻辑。

axios:

  • 强大的 HTTP 客户端:Axios 是一个流行的基于 Promise 的 HTTP 客户端,用于发送 AJAX 请求。
  • 简单易用:Axios 提供了简单易用的 API,支持拦截器、请求取消、错误处理等功能。
  • 跨平台兼容性:Axios 可以在浏览器和 Node.js 中使用,具有良好的跨平台兼容性。

element-plus:

  • 丰富的组件:Element Plus 提供了丰富的 UI 组件,包括按钮、表单、对话框、表格等,可以帮助快速搭建出美观的用户界面。
  • 友好的文档和示例:Element Plus 提供了清晰的文档和示例,方便开发人员快速上手,并且可以参考示例进行定制化开发。
  • 主题定制:Element Plus 支持主题定制,可以根据项目需求进行样式定制,保证 UI 组件与项目风格一致。
  • 国际化支持:Element Plus 提供了多语言国际化支持,可以轻松实现多语言切换,适配不同地区的用户需求。

websocket:

  • 实时双向通信:WebSocket 提供了一种基于 TCP 协议的全双工通信方式,可以实现实时的双向通信。
  • 较低的延迟:相比传统的 HTTP 请求,WebSocket 可以减少通信的延迟,使得实时性更强。
  • 服务器推送:WebSocket 支持服务器主动推送消息给客户端,可以轻松实现即时通讯功能。

scss:

  • 变量和混合:SCSS 提供了变量和混合功能,可以方便地定义和重复使用样式属性和代码块,减少了代码量和维护成本。
  • 嵌套规则:SCSS 支持嵌套规则,使得 CSS 的层级关系更加清晰和易于理解,同时也可以减少选择器的复杂度。
  • 继承:SCSS 支持继承功能,可以避免样式的重复定义,提高了代码的重用性和可维护性。
  • 导入其他文件:SCSS 支持导入其他 SCSS 文件,可以将样式代码拆分到多个文件中,方便管理和维护。
  • 自定义函数:SCSS 支持自定义函数,可以实现一些常用的计算和处理,例如颜色转换等。

vite:

  • 快速开发:Vite 是一个基于 ES Modules 的快速开发工具,具有快速的冷启动、模块热更新等特性,提高了开发效率。
  • 按需加载:Vite 通过按需加载模块,减少了不必要的加载时间,加快了应用程序的加载速度。
  • 简化配置:Vite 使用原生的 ES Modules,不需要繁琐的构建配置,简化了项目的配置过程。

综上所述,我们可以快速的搭建出一个聊天室前端部分。后端部分因为本人不是专业后端,没学过 java,不过也会写点业务,之后会出教程。

# 二、初始化项目

找到 vite 官网

# 搭建项目
pnpm create vite
# project name: anixuil-chat
# language: vue javascript
# 进入项目
cd anixuil-chat
# 安装依赖
pnpm i
pnpm i scss sass pinia vue-router axios element-plus -D
# 自动引入
pnpm install -D unplugin-vue-components unplugin-auto-import
# 运行项目
pnpm run dev

main.js

import { createApp } from "vue";
import "@/styles/reset.scss"; // global css
import App from "./App.vue";
import router from "@/router";
import ElementPlus from "element-plus";
import zhCn from "element-plus/dist/locale/zh-cn.mjs";
const app = createApp(App);
app.use(router);
app.use(ElementPlus, {
  locale: zhCn,
});
app.mount("#app");

vite.config.js

/*
 * @Author: Anixuil
 * @Date: 2024-02-24 13:32:06
 * @LastEditors: Anixuil
 * @LastEditTime: 2024-02-28 15:27:29
 * @Description: vite 配置文件
 */
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
const pathSrc = path.resolve(__dirname, "src");
// https://vitejs.dev/config/
export default defineConfig({
  server: {
    port: 2001,
    open: true,
  },
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use "@/styles/element/index.scss" as *;`,
      },
    },
  },
  envPrefix: "CHAT", // 环境变量前缀
  plugins: [
    vue(),
    AutoImport({
      imports: ["vue", "vue-router"],
      // 自动引入修改主题色添加这一行,使用预处理样式,不添加将会导致使用 ElMessage,ElNotification 等组件时默认的主题色会覆盖自定义的主题色
      resolvers: [
        ElementPlusResolver({
          importStyle: "sass",
        }),
      ],
    }),
    Components({
      resolvers: [
        ElementPlusResolver({
          // 自动引入修改主题色添加这一行,使用预处理样式
          importStyle: "sass",
        }),
      ],
    }),
  ],
  resolve: {
    // 配置路径别名
    alias: {
      "@": pathSrc,
    },
  },
});

@/styles/element/index.scss

/* 只需要重写你需要的即可 */
@forward "element-plus/theme-chalk/src/common/var.scss" with (
    $colors: (
        "primary": (
            "base": rgb(245, 30, 30),
        )
    )
);
// @use "element-plus/theme-chalk/src/index.scss" as *;

reset.scss

body,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
p,
blockquote,
dl,
dt,
dd,
ul,
ol,
li,
pre,
form,
fieldset,
legend,
button,
input,
textarea,
th,
td {
    margin: 0;
    padding: 0;
}
body,
button,
input,
select,
textarea {
    font: 12px/1.5tahoma, arial, \5b8b\4f53;
}
h1,
h2,
h3,
h4,
h5,
h6 {
    font-size: 100%;
}
address,
cite,
dfn,
em,
var {
    font-style: normal;
}
code,
kbd,
pre,
samp {
    font-family: couriernew, courier, monospace;
}
small {
    font-size: 12px;
}
ul,
ol {
    list-style: none;
}
a {
    text-decoration: none;
}
a:hover {
    text-decoration: underline;
}
sup {
    vertical-align: text-top;
}
sub {
    vertical-align: text-bottom;
}
legend {
    color: #000;
}
fieldset,
img {
    border: 0;
}
button,
input,
select,
textarea {
    font-size: 100%;
}
table {
    border-collapse: collapse;
    border-spacing: 0;
}

@/styles/common.scss

body {
    font-size: 14px;
    // 伪类隐藏页面滚动条
    &::-webkit-scrollbar {
        display: none;
    }
}
/* fade-transform 路由切换动画效果 */
.fade-transform-leave-active,
.fade-transform-enter-active {
    transition: all 0.5s;
}
.fade-transform-enter-from,
.fade-transform-leave-to {
    opacity: 0;
    transform: translateY(30px);
}

@/styles/index.scss

@import "element/index.scss";
@import "common.scss";

# 三、遇到的问题

在搭建项目中,遇到了 elementplus 主题色无法修改的问题,重点是这一句

image-20240228153849799

还有一个就是路由跳转动画的问题。

image-20240224162855469

核心实现逻辑是这样,但是动画样式只有出去的没有进来的,也就是只有 leave-to,没有 enter-from

最后发现是我借鉴我的 vue2 项目,vue2 和 vue3 transition 的一些语法稍微有些区别,我直接赋值过来是有问题的。

/*
 * @Author: Anixuil
 * @Date: 2024-02-24 13:49:36
 * @LastEditors: Anixuil
 * @LastEditTime: 2024-02-24 15:43:09
 * @Description: 路由配置
 */
import { createRouter, createWebHashHistory } from "vue-router";
const routes = [
  { path: "/", redirect: "/index" },
  {
    path: "/index",
    name: "index",
    component: () => import("@/views/index.vue"),
    meta: {
      title: "首页",
      transition: "fade-transform",
    },
  },
  {
    path: "/login",
    name: "login",
    component: () => import("@/views/login.vue"),
    meta: {
      title: "登录",
      transition: "fade-transform",
    },
  },
];
const router = createRouter({
  history: createWebHashHistory(),
  routes,
});
export default router;

路由配置如上,pinia 没有放在这里集成是因为我觉得虽然 pinia 相比 vuex 感觉上差不多,但是其实搭配 vue3 使用的时候,还是有一些区别的,尤其是在一些封装上面,我觉得可以抛弃脑中 vuex 的记忆,重新学习一下 pinia。所以下一章就是单独讲 pinia 的集成。(绝对不是今天写到这不想写了)