LLM前端项目实践记录-项目搭建与组件布局 | 豆包MarsCode AI刷题

226 阅读3分钟

一、项目搭建与基础依赖安装

技术栈:Vite、Vue2、Typescript、Element-plus、Scss.

参考字节Vite实战课程juejin.cn/course/byte…

1、创建Vite项目

首先安装pnpm,这里注意把npm国外下载源换成国内的不然可能下载不了,pnpm的下载源也可以换成国内的。

npm i -g pnpm

使用pnpm创建vite项目,这里输入命令会让你输入项目名称以及使用的框架等,选择适合自己的就行。

pnpm create vite
pnpm install
pnpm run dev

2、项目结构

  • src 目录:存放项目的源代码。

    • assets:用于存放图片、字体等静态资源。
    • components:存放 Vue 组件。
    • utils: 存放工具类、工具组件如防抖功能等。
    • views: 单独的页面视图。
    • App.vue:根组件。
    • main.ts:项目的入口文件,用于创建 Vue 应用实例并挂载到 DOM 上。
  • public 目录:存放一些公共的静态资源,这些资源会直接被复制到构建目录中,不会经过处理。

  • index.html:项目的 HTML 模板文件。

  • tsconfig.json:TypeScript 的配置文件,用于配置 TypeScript 编译器的相关选项。

二、组件布局

image.png

ChatView

这一部分是应对项目要求的独立对话框模式视图。 主要的模板代码:

<template>
  <div class="common-layout">
    <el-container>
      <el-aside class="chat-sidebar" width="200px"></el-aside>
      <el-container>
        <el-header>
          <el-avatar :src="aiAvatar" :size="40" />
          <el-text type="primary" :size="large">Xcalibur AI</el-text>
          <el-icon :size="30" style="margin: 0 10px 0 10px;"><Operation /></el-icon>
          <el-icon :size="30">
            <Close class="el-icon-close" @click="close"/>
          </el-icon>
        </el-header>
        <el-main style="padding: 0;">
          <ChatWindow class="chat-window" />
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

主要应用了side-bar、header、main布局方式,使用了 el-containerel-asideel-headerel-main 等 Element Plus的组件来搭建页面布局,构建出类似侧边栏、头部、主体内容区域的布局效果。

效果展示

image.png

ChatInput

集成用户消息输入、文件、图片上传功能的子组件

在实现的时候,我加入了很多优化细节。

  • 按键防抖的功能,核心是用到了setTimeout函数,用于控制shift+enter换行的触发防抖。 这里我写了一个Debouncer类,以提供防抖函数的可扩展性和复用性。
class Debouncer {
    timer: null | ReturnType<typeof setTimeout>;
    
    constructor() {
        this.timer = null; // 定义 timer
    }

    debounce(func: (...args: any[]) => void, delay: number , immediate = false) {


        return (...args: any[]) => {
            // 清除之前的 timer
            if (this.timer) {
                clearTimeout(this.timer);
            }
            if (immediate && !this.timer) {
                func.apply(this, args);
            }
            // 设置新的 timer
            this.timer = setTimeout(() => {
                func.apply(this, args); // 执行传入的函数
            }, delay);
        };
    }
}

export default new Debouncer();

将它绑定到我的按键处理函数上,即实现了按键防抖。

  • 在使用豆包的时候,我注意到它的输入框可以随着内容溢出自动向上生长扩张,因此我在代码中,将chat-input组件设置为了flex:1样式并把chat-window设置为了display:flex弹性盒子样式,让chat-input组件视图自动向上生长。
.chat-input {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    flex: 1;
    margin-bottom: 10px;
    max-height: 22%;
    width: 40%;
    border: 1px solid;
    border-radius: 5px;
}
  • 空白内容自动清除的优化:我在使用一些类似的LLM聊天输入框时,发现如果我输入了多行空行,就无法使用enter发送,需要自己手动清除空行,于是我在代码中加入了消息检测,以使得用户输入无效内容就自动清空内容,并将输入框返回初始高度
            const processedValue = this.message.replace(/\s/g, '');
            if (processedValue === '') {
                this.placeholderSign = '请输入有效内容';
                this.message = '';
                this.setTextAreaHeight();
                return;
            }
            
            
        setTextAreaHeight() {
            const textarea = this.$refs.textArea;
            textarea.style.height = 36 + "px"; // 设置为初始高度
            textarea.style.height = textarea.scrollHeight + "px";
        },