经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 大数据/云/AI » 人工智能基础 » 查看文章
uniapp-chatgpt跨端仿ChatGPT实例|uniapp+vue3+pinia多端聊天模板
来源:cnblogs  作者:xiaoyan2017  时间:2023/6/28 8:51:27  对本文有异议

基于uniapp+vite4+pinia跨多端实现chatgpt会话模板Uniapp-ChatGPT

uni-chatgpt 使用uni-app+vite4+vue3+pinia+uview-plus等技术构建多端仿制ChatGPT手机端APP会话应用模板。支持编译到h5+小程序+APP端,支持渲染markdown语法及代码高亮、解决软键盘撑起布局问题。

◆ 效果预览

编译 [H5+小程序+App端] 效果如下

◆ 技术栈

  • 编辑器:HbuilderX 3.8.4
  • 框架技术:Uniapp+Vite4+Vue3+Pinia
  • UI组件库:uView-plus^3.1.31
  • markdown渲染:markdown-it
  • 代码高亮:highlight.js
  • 本地缓存:pinia-plugin-unistorage
  • 弹框组件:ua-popup(基于uniapp封装跨端弹层组件)
  • 自定义组件:导航条ua-navbar+菜单栏ua-tabbar
  • 支持编译:小程序+H5+APP端

◆ 功能特性

  1. 沉浸式自定义顶部导航条+底部tabbar
  2. 支持h5+小程序+App端渲染markdown语法及代码高亮
  3. 基于pinia全局状态管理
  4. 基于uview-plus跨端vue3组件库
  5. 支持会话本地缓存

◆ 项目结构目录

基于hbuilderx创建的项目,整个项目页面全部采用uniapp vue3语法编码开发。

如果对uniapp结合vue3创建多端项目感兴趣,可以去看看之前的分享文章。

https://www.cnblogs.com/xiaoyan2017/p/17487018.html

◆ Uniapp自定义多端Navbar+Tabbar组件

项目中顶部navbar和底部tabbar均是自定义组件实现功能,保证整体风格统一协调。

如下图:在components目录下新建组件。支持easycom模式,无需引入,直接可以使用。

  1. <ua-navbar back="false" custom :title="title" size="40rpx" center fixed :bgcolor="bgcolor">
  2. <template #left>
  3. <view @click="showSidebar=true"><text class="iconfont ve-icon-menuon"></text></view>
  4. </template>
  5. <template #right>
  6. <text class="iconfont ve-icon-plus fs-36" @click="handleNewChat"></text>
  7. </template>
  8. </ua-navbar>

至于如何实现组件功能,这里就不做详细介绍了,大家可以去看看之前的分享文章。

https://www.cnblogs.com/xiaoyan2017/p/14978408.html

另外Navbar和Tabbar组件的vue2版本已经发布到了插件市场,如果大家有需要可以去下载,一次性拿走使用。

https://ext.dcloud.net.cn/plugin?id=5592
https://ext.dcloud.net.cn/plugin?id=5593

◆ 主入口main.js配置

在main.js中使用vue3语法,引入pinia状态管理、uview-plus组件库。

  1. /**
  2. * 主入口配置
  3. */
  4. import App from './App'
  5. import { createSSRApp } from 'vue'
  6.  
  7. // 引入pinia状态管理
  8. import pinia from '@/store'
  9.  
  10. // 引入uview-plus组件库
  11. import uviewplus from '@/uview-plus'
  12. export function createApp() {
  13. const app = createSSRApp(App)
  14. app.use(pinia)
  15. app.use(uviewplus)
  16. return {
  17. app,
  18. pinia
  19. }
  20. }

◆ App.vue模板配置

在app.vue中使用vue3 setup语法,获取手机系统状态栏高度。

  1. <script setup>
  2. import { provide } from 'vue'
  3. import { onLaunch, onShow, onHide, onPageNotFound } from '@dcloudio/uni-app'
  4. onLaunch(() => {
  5. console.log('App Launch')
  6. // 隐藏tabBar
  7. uni.hideTabBar()
  8. // 初始化
  9. initSysInfo()
  10. })
  11. onShow(() => {
  12. console.log('App Show')
  13. })
  14. onHide(() => {
  15. console.log('App Hide')
  16. })
  17. onPageNotFound((e) => {
  18. console.warn('Router Error>>', ` No match path "${e.path}" `);
  19. uni.redirectTo({
  20. url: '/pages/404/index'
  21. })
  22. })
  23. const initSysInfo = () => {
  24. uni.getSystemInfo({
  25. success: (e) => {
  26. // 获取手机状态栏高度
  27. let statusBar = e.statusBarHeight
  28. let customBar
  29. // #ifndef MP
  30. customBar = statusBar + (e.platform == 'android' ? 50 : 45)
  31. // #endif
  32. // #ifdef MP-WEIXIN
  33. // 获取胶囊按钮的布局位置信息
  34. let menu = wx.getMenuButtonBoundingClientRect()
  35. // 导航栏高度 = 胶囊下距离 + 胶囊上距离 - 状态栏高度
  36. customBar = menu.bottom + menu.top - statusBar
  37. // #endif
  38. // #ifdef MP-ALIPAY
  39. customBar = statusBar + e.titleBarHeight
  40. // #endif
  41. // 目前globalData在vue3 setup支持性不好,改为provide/inject方式
  42. provide('globalData', {
  43. statusBarH: statusBar,
  44. customBarH: customBar,
  45. platform: e.platform
  46. })
  47. }
  48. })
  49. }
  50. </script>

由于底部tabbar采用自定义组件,所以在onLaunch中给隐藏掉系统tabbar功能。

如上图:在vue3 setup中globalData有兼容性问题,所以使用了provide/inject替代方案。

◆ uniapp vue3渲染markdown语法+代码高亮

uni-chatgpt能很好的兼容适配 h5+小程序+App端 解析markdown语法及代码高亮显示。

至于如何在uniapp中实现解析markdown语法模板以及解决键盘撑起页面布局问题,大家可以去看看之前的这篇文章。

https://www.cnblogs.com/xiaoyan2017/p/17502105.html

◆ uniapp多功能Input输入编辑框

为了整体风格一致,会话编辑框采用自定义组件实现功能。

目前兼容h5+小程序+App端,支持input单行文本、textarea多行文本,可自适应高度,自定义前缀/后缀插槽及密码输入等功能。

  1. <template>
  2. <div
  3. class="ve__input"
  4. :class="[
  5. preClass,
  6. isClass,
  7. sizeClass,
  8. {'is-disabled': isDisabled},
  9. {'is-resizable': type == 'textarea' && !autosize},
  10. {'ve__input--group': $slots.prepend || $slots.append},
  11. {'ve__input--group__prepend': $slots.prepend},
  12. {'ve__input--group__append': $slots.append}
  13. ]"
  14. >
  15. <!-- 前置插槽(prepend slot) -->
  16. <div v-if="$slots.prepend" class="ve__input--prepend"><slot name="prepend" /></div>
  17.  
  18. <div class="ve__input-wrapper">
  19. <!-- 输入框前缀 -->
  20. <div v-if="$slots.prefix || prefixIcon" class="ve__input--prefix">
  21. <span class="ve__input--prefix__inner">
  22. <slot name="prefix" />
  23. <i v-if="prefixIcon" class="iconfont" :class="prefixIcon"></i>
  24. </span>
  25. </div>
  26.  
  27. <template v-if="type != 'textarea'">
  28. <input
  29. class="ve__input-inner"
  30. ref="inputRef"
  31. :type="showPassword ? (passwordVisible ? 'text' : 'password') : type"
  32. :value="modelValue"
  33. :name="name"
  34. :maxlength="maxlength"
  35. :readonly="readonly"
  36. :disabled="isDisabled"
  37. :placeholder="placeholder"
  38. :cursor-spacing="15"
  39. :focus="autofocus"
  40. @focus="handleFocus"
  41. @blur="handleBlur"
  42. @input="handleInput"
  43. @change="handleChange"
  44. @keydown="handleKeydown"
  45. />
  46. </template>
  47. <template v-else>
  48. <textarea
  49. class="ve__input-inner ve__textarea-inner"
  50. ref="textareaRef"
  51. :value="modelValue"
  52. :maxlength="maxlength"
  53. :readonly="readonly"
  54. :disabled="isDisabled"
  55. :placeholder="placeholder"
  56. :show-confirm-bar="false"
  57. :adjust-position="false"
  58. :cursor-spacing="15"
  59. :focus="autofocus"
  60. :auto-height="isTrue(autosize) || isObject(autosize)"
  61. :style="textareaStyle"
  62. @focus="handleFocus"
  63. @blur="handleBlur"
  64. @input="handleInput"
  65. @change="handleChange"
  66. @keydown="handleKeydown"
  67. />
  68. </template>
  69.  
  70. <!-- 输入框后缀 -->
  71. <div v-if="showSuffixVisible" class="ve__input--suffix" @click="handleSearch" @mousedown.prevent>
  72. <span class="ve__input--suffix__inner">
  73. <!-- 后缀 -->
  74. <template v-if="!showClear || !showPwdVisible">
  75. <slot name="suffix" />
  76. <i v-if="suffixIcon" class="iconfont" :class="suffixIcon"></i>
  77. </template>
  78. <!-- 清除 -->
  79. <i v-if="showClear" class="iconfont ve-icon-close-circle ve__input-clear" @click="handleClear" @mousedown.prevent></i>
  80. <!-- 密码可见 -->
  81. <i v-if="showPwdVisible" class="iconfont ve-icon-hide ve__input-password" :class="{'ve-icon-eye1': passwordVisible}" @click="handlePwdVisible" @mousedown.prevent @mouseup.prevent></i>
  82. <!-- 限制字数 -->
  83. <em v-if="showLimitWordVisible" class="ve__input-limitword">{{inputLength}} / {{maxlength}}</em>
  84. </span>
  85. </div>
  86. </div>
  87.  
  88. <!-- 后置插槽(append slot) -->
  89. <div v-if="$slots.append" class="ve__input--append" @click="handleSearch" @mousedown.prevent><slot name="append" /></div>
  90. </div>
  91. </template>
  1. <template>
  2. <view class="ugpt__editor">
  3. <view class="ugpt__editor-inner flexbox">
  4. <u-button class="btn" shape="circle" @click="handleUploadImage"><text class="iconfont ve-icon-image fs-32"></text></u-button>
  5. <u-button class="btn" shape="circle" @click="showPopover=true"><text class="iconfont ve-icon-yuyin1 fs-32"></text></u-button>
  6. <ua-input
  7. class="flex1"
  8. v-model="editorText"
  9. type="textarea"
  10. :autosize="{maxRows: 6}"
  11. clearable
  12. placeholder="Prompt..."
  13. @clear="handleClear"
  14. />
  15. <u-button type="success" shape="circle" :disabled="!editorText" @click="handleSubmit" style="transform: scale(.8);width: auto;"><text class="iconfont ve-icon-send-o"></text></u-button>
  16. </view>
  17. </view>
  18. </template>

◆ uniapp配置vite.config.js

使用hbuilderx构建的uniapp项目同样支持.env文件及vite.config.js配置。支持修改默认运行端口。

  1. import { defineConfig, loadEnv } from 'vite'
  2. import uni from '@dcloudio/vite-plugin-uni'
  3. import { resolve } from 'path'
  4. import { parseEnv } from './utils/env'
  5.  
  6. // https://vitejs.dev/config/
  7. export default defineConfig(({ command, mode }) => {
  8. const viteEnv = loadEnv(mode, __dirname)
  9. const env = parseEnv(viteEnv)
  10. return {
  11. plugins: [
  12. uni()
  13. ],
  14. define: {
  15. // 自定义环境变量
  16. 'process.env.VITE_APPNAME': JSON.stringify('uniapp-chatgpt'),
  17. 'process.env.VITE_ENV': env
  18. },
  19. // base: '/',
  20. // mode: 'development', // Default: 'development' for serve, 'production' for build
  21.  
  22. /*构建选项*/
  23. esbuild: {
  24. // 打包去除 console.log 和 debugger
  25. drop: env.VITE_DROP_CONSOLE && command === 'build' ? ["console", "debugger"] : []
  26. },
  27. /*开发服务器选项*/
  28. server: {
  29. // 端口
  30. port: env.VITE_PORT,
  31. // 运行时自动打开浏览器
  32. open: env.VITE_OPEN,
  33. // 代理配置
  34. proxy: {
  35. // ...
  36. }
  37. }
  38. }
  39. })

OK,基于uniapp+vue3构建跨端仿制chatgpt模板就分享到这里,希望对大家有所帮助~~??

最后附上一个vue3+electron25桌面端实例项目

https://www.cnblogs.com/xiaoyan2017/p/17468074.html

 

原文链接:https://www.cnblogs.com/xiaoyan2017/p/17507581.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号