前言
随着chatgpt
智能聊天继续火爆,越来越多的开发者参加其中。明天给大家分享vite4.x
搭建繁难网页版仿ChatGpt聊天程序Vue3ChatGPT。
技术框架
- 编辑工具:Cursor
- 框架技术:Vue3+Vite4.x+Pinia2
- 组件库:VEPlus (基于vue3桌面端组件库)
- 国际化多语言:vue-i18n^9.2.2
- 代码高亮:highlight.js^11.7.0
- 本地存储:pinia-plugin-persistedstate^3.1.0
- markdown解析:vue3-markdown-it
vue3-chatgpt
反对两种布局模板、dark+light模式、全屏+半屏展现、Markdown语法解析、侧边栏收起等性能。
我的项目构造
基于vite4.x构建我的项目,采纳vue3 setup语法糖编码。
main.js入口文件
import { createApp } from 'vue'import App from './App.vue'// 引入Router和Storeimport Router from './router'import Store from './store'// 引入插件配置import Plugins from './plugins'const app = createApp(App)app.use(Router).use(Store).use(Plugins).mount('#app')
vite.config.js配置文件
import { defineConfig, loadEnv } from 'vite'import vue from '@vitejs/plugin-vue'import { resolve } from 'path'import { parseEnv } from './src/utils/env'// https://vitejs.dev/config/export default defineConfig(({ mode }) => { const viteEnv = loadEnv(mode, process.cwd()) const env = parseEnv(viteEnv) return { plugins: [vue()], // base: '/', // mode: 'development', // development|production /*构建选项*/ build: { // minify: 'esbuild', // 打包形式 esbuild(打包快)|terser // chunkSizeWarningLimit: 2000, // 打包大小正告 // rollupOptions: { // output: { // chunkFileNames: 'assets/js/[name]-[hash].js', // entryFileNames: 'assets/js/[name]-[hash].js', // assetFileNames: 'assets/[ext]/[name]-[hash].[ext]', // } // } }, esbuild: { // 打包去除 console.log 和 debugger drop: env.VITE_DROP_CONSOLE ? ['console', 'debugger'] : [] }, /*开发服务器选项*/ server: { // 端口 port: env.VITE_PORT, // 是否浏览器主动关上 open: env.VITE_OPEN, // 开启https https: env.VITE_HTTPS, // 代理配置 proxy: { // ... } }, resolve: { // 设置别名 alias: { '@': resolve(__dirname, 'src'), '@assets': resolve(__dirname, 'src/assets'), '@components': resolve(__dirname, 'src/components'), '@views': resolve(__dirname, 'src/views'), // 解决vue-i18n正告提醒:You are running the esm-bundler build of vue-i18n. 'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js' } } }})
公共布局模板
整体分为顶部导航栏、左侧菜单栏、右侧主体栏。
<script setup> import { computed } from 'vue' import { appStore } from '@/store/modules/app' // 引入布局模板 import Classic from './layout/classic/index.vue' import Columns from './layout/columns/index.vue' const store = appStore() const config = computed(() => store.config) const LayoutConfig = { classic: Classic, columns: Columns }</script><template> <div class="vegpt__container" :class="{'is-half': store.config.halfScreen}" :style="{'--themeSkin': store.config.skin}"> <component :is="LayoutConfig[config.layout]" /> </div></template><style lang="scss" scoped></style>
<div class="ve__layout-body flex1 flexbox"> <!-- //两头栏 --> <div class="ve__layout-menus flexbox" :class="{'hidden': store.config.collapse}"> <aside class="ve__layout-aside flexbox flex-col"> <ChatNew /> <Scrollbar class="flex1" autohide size="4" gap="1"> <ChatList /> </Scrollbar> <ExtraLink /> <Collapse /> </aside> </div> <!-- //左边栏 --> <div class="ve__layout-main flex1 flexbox flex-col"> <!-- 主内容区 --> <Main /> </div></div>
/** * 聊天状态治理 * @author YXY Q:282310962 */import { defineStore } from 'pinia'import { guid, isEmpty } from '@/utils'export const chatStore = defineStore('chat', { state: () => ({ // 聊天会话记录 sessionId: '', session: [] }), getters: {}, actions: { // 创立新会话 createSession(ssid) { this.sessionId = ssid this.session.push({ sessionId: ssid, title: '', data: [] }) }, // 新增会话 addSession(message) { // 判断以后会话uuid是否存在,不存在创立新会话 if(!this.sessionId) { const ssid = guid() this.createSession(ssid) } this.session.map(item => { if(item.sessionId == this.sessionId) { if(!item.title) { item.title = message.content } item.data.push(message) } }) // ... }, // 获取会话 getSession() { return this.session.find(item => item.sessionId == this.sessionId) }, // 移除会话 removeSession(ssid) { const index = this.session.findIndex(item => item?.sessionId === ssid) if(index > -1) { this.session.splice(index, 1) } this.sessionId = '' }, // 删除某一条会话 deleteSession(ssid) { // ... }, // 清空会话 clearSession() { this.session = [] this.sessionId = '' } }, // 本地长久化存储(默认存储localStorage) persist: true /* persist: { // key: 'chatStore', // 不设置则是默认app storage: localStorage, paths: ['aa', 'bb'] // 设置缓存键 } */})
如上图:聊天框采纳Input组件实现性能。
<script setup> import { ref, watch } from 'vue' import { guid } from '@/utils' import { chatStore } from '@/store/modules/chat' const props = defineProps({ value: { type: [String, Number] } }) const emit = defineEmits(['clear']) const chatState = chatStore() const uploadImgRef = ref() const editorRef = ref() const editorText = ref(props.value) // ... // 发送会话 const handleSubmit = () => { editorRef.value.focus() if(!editorText.value) return let data = { type: 'text', role: 'User', key: guid(), content: editorText.value } chatState.addSession(data) // 清空 editorText.value = '' } const handleKeydown = (e) => { // ctrl+enter if(e.ctrlKey && e.keyCode == 13) { handleSubmit() } } // 抉择图片 const handleUploadImage = () => { let file = uploadImgRef.value.files[0] if(!file) return let size = Math.floor(file.size / 1024) console.log(size) if(size > 2*1024) { Message.danger('图片大小不能超过2M') uploadImgRef.value.value = '' return false } let reader = new FileReader() reader.readAsDataURL(file) reader.onload = function() { let img = this.result let data = { type: 'image', role: 'User', key: guid(), content: img } chatState.addSession(data) } } // ...</script>
OK,基于vue3开发仿造chatgpt实例就先分享这么多,心愿大家能喜爱~~
https://segmentfault.com/a/1190000042710924
https://segmentfault.com/a/1190000040711708