uniapp+vue3聊天室|uni-app+vite4+uv-ui跨端仿微信app聊天语音/朋友圈
<p><span style="font-size: 18px; font-family: 宋体, "Songti SC"; color: rgba(0, 204, 0, 1)">原创研发<span style="background-color: rgba(255, 255, 0, 1)">uniapp+vue3+pinia2</span>跨<strong>三端</strong>仿微信app聊天模板<em>Uniapp-Wechat</em>。</span></p><p><span style="font-size: 12px"><strong>uni-vue3-wchat</strong>基于<span style="background-color: rgba(0, 255, 255, 1)">uni-app+vue3+pinia2+uni-ui+uv-ui</span>等技术跨端仿制微信App界面聊天项目,<strong>支持编译到H5+小程序端+App端</strong>。实现<span style="background-color: rgba(204, 255, 204, 1)">编辑框多行消息/emoj混合、长按触摸式仿微信语音面板、图片/视频预览、红包/朋友圈</span>等功能。</span></p>
<h3>预览图</h3>
<p><span style="font-size: 12px">编译至<strong>h5+App端+小程序端</strong>运行效果</span></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429104600484-2017148452.png"></p>
<h3>技术栈</h3>
<ul>
<li><span style="font-size: 12px">开发工具:HbuilderX 4.0.8</span></li>
<li><span style="font-size: 12px">技术框架:Uniapp+Vue3+Pinia2+Vite4.x</span></li>
<li><span style="font-size: 12px">UI组件库:uni-ui+uv-ui(uniapp+vue3组件库)</span></li>
<li><span style="font-size: 12px">弹框组件:uv3-popup(自定义uniapp+vue3多端弹框组件)</span></li>
<li><span style="font-size: 12px">自定义组件:uv3-navbar导航栏+uv3-tabbar菜单栏</span></li>
<li><span style="font-size: 12px">缓存技术:pinia-plugin-unistorage</span></li>
<li><span style="font-size: 12px">支持编译:H5+小程序+APP端</span></li>
</ul>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429105544788-2101587551.png"></p>
<p><span style="font-size: 12px">目前uni-app对vue3支持性已经蛮不错了。之前也有给大家分享一款uniapp+vue3短视频/直播商城项目。</span></p>
<p><span style="font-size: 12px">https://www.cnblogs.com/xiaoyan2017/p/17938517</span></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429110135179-1354116860.gif"></p>
<p><span style="font-size: 12px"><em>uniapp-vue3-wchat</em>基于最新跨端技术开发,支持编译H5/小程序端/APP端,运行效果基本保持一致。</span></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429110650434-1794075979.gif"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429110859812-563109761.gif"></p>
<h3>项目构建目录</h3>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429111152644-2113050138.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429111326793-1942174310.gif"></p>
<p><span style="font-size: 12px">支持在pc端以<strong>750px</strong>像素布局显示。</span></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429113527025-316426662.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429113354730-322257750.png"></p>
<blockquote>
<h4><em>目前uni-wechat项目同步上线到我的作品集,如果恰好有需要,欢迎自行去拍哈~ 感谢小伙伴们的支持!</em></h4>
<p><span style="font-size: 12px">原创uni-app+vue3+uv-ui跨端仿微信app聊天室</span></p>
</blockquote>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114116892-1736087261.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114131290-1699985429.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114145003-1526228696.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114202901-92438248.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114225086-1500861339.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114244188-2127645144.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114304236-2147130971.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114333253-168883784.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114419597-1549138500.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114440163-891327798.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114455937-1546541771.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114529258-1087863798.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114608434-1764126937.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114635423-358536981.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114658496-1168128034.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114716150-1446581801.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114747721-511462229.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114804681-1874280086.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114820013-965537383.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114832462-1837849076.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114842872-732931155.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429114922300-1372682231.png"></p>
<p><span style="font-size: 12px">整个项目采用<strong>vue3 setup</strong>语法糖编码开发。</span></p>
<h3>App.vue配置</h3>
<p><span style="font-size: 12px">项目主模板<em>App.vue</em>使用<span style="color: rgba(0, 204, 0, 1)">vue3 setup</span>语法。</span></p>
<div class="cnblogs_code">
<pre><script setup><span style="color: rgba(0, 0, 0, 1)">
import { provide } from </span>'vue'<span style="color: rgba(0, 0, 0, 1)">
import { onLaunch, onShow, onHide, onPageNotFound } from </span>'@dcloudio/uni-app'<span style="color: rgba(0, 0, 0, 1)">
onLaunch(() </span>=><span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>'App Launch'<span style="color: rgba(0, 0, 0, 1)">)
uni.hideTabBar()
loadSystemInfo()
})
onShow(() </span>=><span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>'App Show'<span style="color: rgba(0, 0, 0, 1)">)
})
onHide(() </span>=><span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>'App Hide'<span style="color: rgba(0, 0, 0, 1)">)
})
onPageNotFound((e) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
console.warn(</span>'Route Error:'<span style="color: rgba(0, 0, 0, 1)">, `${e.path}`)
})
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取系统设备信息</span>
const loadSystemInfo = () =><span style="color: rgba(0, 0, 0, 1)"> {
uni.getSystemInfo({
success: (e) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取手机状态栏高度</span>
let statusBar =<span style="color: rgba(0, 0, 0, 1)"> e.statusBarHeight
let customBar
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> #ifndef MP</span>
customBar = statusBar + (e.platform == 'android' ? 50 : 45<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> #endif</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> #ifdef MP-WEIXIN</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取胶囊按钮的布局位置信息</span>
let menu =<span style="color: rgba(0, 0, 0, 1)"> wx.getMenuButtonBoundingClientRect()
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 导航栏高度 = 胶囊下距离 + 胶囊上距离 - 状态栏高度</span>
customBar = menu.bottom + menu.top -<span style="color: rgba(0, 0, 0, 1)"> statusBar
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> #endif</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> #ifdef MP-ALIPAY</span>
customBar = statusBar +<span style="color: rgba(0, 0, 0, 1)"> e.titleBarHeight
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> #endif</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 由于globalData在vue3 setup存在兼容性问题,改为provide/inject替代方案</span>
provide('globalData'<span style="color: rgba(0, 0, 0, 1)">, {
statusBarH: statusBar,
customBarH: customBar,
screenWidth: e.screenWidth,
screenHeight: e.screenHeight,
platform: e.platform
})
}
})
}
</span></script>
<style>
<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> #ifndef APP-NVUE </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@import </span>'static/fonts/iconfont.css'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> #endif </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
</style>
<style lang="scss"><span style="color: rgba(0, 0, 0, 1)">
@import </span>'styles/reset.scss'<span style="color: rgba(0, 0, 0, 1)">;
@import </span>'styles/layout.scss'<span style="color: rgba(0, 0, 0, 1)">;
</span></style></pre>
</div>
<h3>uni-app+vue3自定义导航条+菜单栏</h3>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429122331773-1241731102.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429122625884-890863363.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429122834165-1407915091.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429123035338-1499616398.png"></p>
<p><span style="font-size: 12px">在<strong>components</strong>目录下自定义导航栏Navbar和底部菜单栏Tabbar组件。</span></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429123458911-774585181.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429123702483-1019356483.png"></p>
<p><span style="font-size: 12px">navbar导航条支持是否显示返回、自定义标题(居中)、背景色/文字颜色、搜索等功能。</span></p>
<p><strong><span style="font-size: 12px">支持如下自定义插槽</span></strong></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">slot </span><span style="color: rgba(255, 0, 0, 1)">#back </span><span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">slot </span><span style="color: rgba(255, 0, 0, 1)">#backText </span><span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">slot </span><span style="color: rgba(255, 0, 0, 1)">#left </span><span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">slot </span><span style="color: rgba(255, 0, 0, 1)">#title </span><span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">slot </span><span style="color: rgba(255, 0, 0, 1)">#search </span><span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">slot </span><span style="color: rgba(255, 0, 0, 1)">#right </span><span style="color: rgba(0, 0, 255, 1)">/></span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">uv3-navbar </span><span style="color: rgba(255, 0, 0, 1)">:back</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(255, 0, 0, 1)"> title</span><span style="color: rgba(0, 0, 255, 1)">="标题内容"</span><span style="color: rgba(255, 0, 0, 1)"> bgcolor</span><span style="color: rgba(0, 0, 255, 1)">="#07c160"</span><span style="color: rgba(255, 0, 0, 1)"> color</span><span style="color: rgba(0, 0, 255, 1)">="#fff"</span><span style="color: rgba(255, 0, 0, 1)"> fixed zIndex</span><span style="color: rgba(0, 0, 255, 1)">="1010"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">uv3-navbar </span><span style="color: rgba(255, 0, 0, 1)">custom bgcolor</span><span style="color: rgba(0, 0, 255, 1)">="linear-gradient(to right, #07c160, #0000ff)"</span><span style="color: rgba(255, 0, 0, 1)"> color</span><span style="color: rgba(0, 0, 255, 1)">="#fff"</span><span style="color: rgba(255, 0, 0, 1)"> center transparent zIndex</span><span style="color: rgba(0, 0, 255, 1)">="2024"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">template </span><span style="color: rgba(255, 0, 0, 1)">#back</span><span style="color: rgba(0, 0, 255, 1)">><</span><span style="color: rgba(128, 0, 0, 1)">uni-icons </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="close"</span> <span style="color: rgba(0, 0, 255, 1)">/></</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">template </span><span style="color: rgba(255, 0, 0, 1)">#backText</span><span style="color: rgba(0, 0, 255, 1)">><</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">></span>首页<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">template </span><span style="color: rgba(255, 0, 0, 1)">#title</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">image </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">="/static/logo.jpg"</span><span style="color: rgba(255, 0, 0, 1)"> style</span><span style="color: rgba(0, 0, 255, 1)">="height:20px;width:20px;"</span> <span style="color: rgba(0, 0, 255, 1)">/></span><span style="color: rgba(0, 0, 0, 1)"> Admin
</span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">template </span><span style="color: rgba(255, 0, 0, 1)">#right</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="ml-20"</span><span style="color: rgba(255, 0, 0, 1)"> @click</span><span style="color: rgba(0, 0, 255, 1)">="handleAdd"</span><span style="color: rgba(0, 0, 255, 1)">><</span><span style="color: rgba(128, 0, 0, 1)">text </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="iconfont icon-tianjia"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="ml-20"</span><span style="color: rgba(0, 0, 255, 1)">><</span><span style="color: rgba(128, 0, 0, 1)">text </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="iconfont icon-msg"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">uv3-navbar</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
</div>
<h3>uni-vue3-wchat布局模板</h3>
<p><span style="font-size: 12px">由于整体项目结构采用顶部<strong>导航区域+主体内容区+底部区域</strong>,所以新建一个公共布局模板。</span></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429125906607-2041570472.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429130237480-903243492.png"> <img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429130348714-778916538.png"></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 公共布局模板 </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> #ifdef MP-WEIXIN </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
export </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">default</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> {
</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">/*</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">*
* 解决小程序class、id透传问题
* manifest.json中配置mergeVirtualHostAttributes: true, 在微信小程序平台不生效,组件外部传入的class没有挂到组件根节点上,在组件中增加options: { virtualHost: true }
* https://github.com/dcloudio/uni-ui/issues/753
</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">*/</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
options: { virtualHost: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">true</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> }
}
</span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> #endif </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">setup</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
const props </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> defineProps({
</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)"> 是否显示自定义tabbar</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> showTabBar: { type: , </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">default</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">false</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> },
})
</span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="uv3__container flexbox flex-col flex1"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 顶部插槽 </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">slot </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="header"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 内容区 </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="uv3__scrollview flex1"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">slot </span><span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 底部插槽 </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">slot </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="footer"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> tabbar栏 </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">uv3-tabbar </span><span style="color: rgba(255, 0, 0, 1)">v-if</span><span style="color: rgba(0, 0, 255, 1)">="showTabBar"</span><span style="color: rgba(255, 0, 0, 1)"> hideTabBar fixed </span><span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
</div>
<h3>uniapp+vue3实现微信九宫格图像</h3>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429132537791-1704239041.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429132644347-83378864.png"></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">setup</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
import { onMounted, ref, computed, watch, getCurrentInstance } from </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">vue</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
const props </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> defineProps({
</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)"> 图像组</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> avatar: { type: Array, </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">default</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">null</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> },
})
const instance </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> getCurrentInstance()
const uuid </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> computed(() </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Math.floor(Math.random() </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">*</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">10000</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">))
const avatarPainterId </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> ref(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">canvasid</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">+</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> uuid.value)
const createAvatar </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> () </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> {
const ctx </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> uni.createCanvasContext(avatarPainterId.value, instance)
</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)"> 计算图像在画布上的坐标</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> const avatarSize </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">12</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
const gap </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">2</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">for</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(let i </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">0</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, len </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> props.avatar.length; i </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"><</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> len; i</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">++</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">) {
const row </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Math.floor(i </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">3</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">)
const col </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> i </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">%</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">3</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
const x </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> col </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">*</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (avatarSize </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">+</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> gap)
const y </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> row </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">*</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (avatarSize </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">+</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> gap)
ctx.drawImage(props.avatar, x, y, avatarSize, avatarSize)
}
ctx.draw(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">false</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, () </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> {
</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)"> 输出临时图片</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">/*</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)"> uni.canvasToTempFilePath({
canvasId: avatarPainterId.value,
success: (res) => {
console.log(res.tempFilePath)
}
}) </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">*/</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
})
}
onMounted(() </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> {
createAvatar()
})
watch(() </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> props.avatar, () </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> {
createAvatar()
})
</span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">template </span><span style="color: rgba(255, 0, 0, 1)">v-if</span><span style="color: rgba(0, 0, 255, 1)">="avatar.length > 1"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="uv3__avatarPainter"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">canvas </span><span style="color: rgba(255, 0, 0, 1)">:canvas-id</span><span style="color: rgba(0, 0, 255, 1)">="avatarPainterId"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="uv3__avatarPainter-canvas"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">canvas</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">template </span><span style="color: rgba(255, 0, 0, 1)">v-else</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">image </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="uv3__avatarOne"</span><span style="color: rgba(255, 0, 0, 1)"> :src</span><span style="color: rgba(0, 0, 255, 1)">="avatar"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">style </span><span style="color: rgba(255, 0, 0, 1)">lang</span><span style="color: rgba(0, 0, 255, 1)">="scss"</span><span style="color: rgba(255, 0, 0, 1)"> scoped</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(128, 0, 0, 1)">
.uv3__avatarPainter </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">{</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)">background-color</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)"> #eee</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)"> border-radius</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)"> 5px</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)"> overflow</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)"> hidden</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)"> padding</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)"> 2px</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)"> height</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)"> 44px</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)"> width</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)"> 44px</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">}</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(128, 0, 0, 1)">
.uv3__avatarPainter-canvas </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">{</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)">height</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)"> 100%</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)"> width</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)"> 100%</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">}</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(128, 0, 0, 1)">
.uv3__avatarOne </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">{</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)">border-radius</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)"> 5px</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)"> height</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)"> 44px</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)"> width</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)"> 44px</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">}</span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">style</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
</div>
<h3>uniapp+vue3自定义弹出框</h3>
<p><span style="font-size: 12px">项目中所有的弹窗效果都是基于<em>uniapp+vue3</em>自定义组件实现功能。</span></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429130855459-1627153005.png"> <img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429130931800-882296996.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429131027305-110243231.png"> <img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429131113148-68142588.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429131233089-1706057744.png"> <img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429131322307-1375025734.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429131427286-164806501.png"></p>
<p><span style="font-size: 12px"><strong>支持如下参数配置:</strong></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">v-model 当前组件是否显示
title 标题(支持富文本div标签、自定义插槽内容)
content 内容(支持富文本div标签、自定义插槽内容)
type 弹窗类型(toast | footer | actionsheet | actionsheetPicker | android/ios)
customStyle 自定义弹窗样式
icon toast图标(loading | success | fail | warn | info)
shade 是否显示遮罩层
shadeClose 是否点击遮罩时关闭弹窗
opacity 遮罩层透明度
round 是否显示圆角
xclose 是否显示关闭图标
xposition 关闭图标位置(left | right | top | bottom)
xcolor 关闭图标颜色
anim 弹窗动画(scaleIn | fadeIn | footer | fadeInUp | fadeInDown)
position 弹出位置(top | right | bottom | left)
follow 长按/右键弹窗(坐标点)
time 弹窗自动关闭秒数(1、2、3)
zIndex 弹窗层叠(默认202107)
btns 弹窗按钮(参数:text|style|disabled|click)
------------------------------------------
## slot [插槽]
</span><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">template </span><span style="color: rgba(255, 0, 0, 1)">#title</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">template </span><span style="color: rgba(255, 0, 0, 1)">#content</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="color: rgba(0, 0, 0, 1)">
------------------------------------------
## emit
open 打开弹出层时触发(@open="xxx")
close 关闭弹出层时触发(@close="xxx")</span></pre>
</div>
<p><span style="font-size: 12px">支持<strong>组件式+函数式</strong>调用。</span></p>
<div class="cnblogs_code">
<pre><script setup><span style="color: rgba(0, 0, 0, 1)">
import { onMounted, ref, computed, watch, nextTick, getCurrentInstance } from </span>'vue'<span style="color: rgba(0, 0, 0, 1)">
const props </span>=<span style="color: rgba(0, 0, 0, 1)"> defineProps({
...
})
const emit </span>=<span style="color: rgba(0, 0, 0, 1)"> defineEmits([
</span>'update:modelValue'<span style="color: rgba(0, 0, 0, 1)">,
</span>'open'<span style="color: rgba(0, 0, 0, 1)">,
</span>'close'<span style="color: rgba(0, 0, 0, 1)">
])
const instance </span>=<span style="color: rgba(0, 0, 0, 1)"> getCurrentInstance()
const opts </span>=<span style="color: rgba(0, 0, 0, 1)"> ref({
...props
})
const visible </span>= ref(<span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">)
const closeAnim </span>= ref(<span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">)
const stopTimer </span>= ref(<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
const oIndex </span>=<span style="color: rgba(0, 0, 0, 1)"> ref(props.zIndex)
const uuid </span>= computed(() => Math.floor(Math.random() * 10000<span style="color: rgba(0, 0, 0, 1)">))
const positionStyle </span>= ref({ position: 'absolute', left: '-999px', top: '-999px'<span style="color: rgba(0, 0, 0, 1)"> })
const toastIcon </span>=<span style="color: rgba(0, 0, 0, 1)"> {
...
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 打开弹框</span>
const open = (options) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(visible.value) <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
opts.value </span>=<span style="color: rgba(0, 0, 0, 1)"> Object.assign({}, props, options)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> console.log('-=-=混入参数:', opts.value)</span>
visible.value = <span style="color: rgba(0, 0, 255, 1)">true</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> nvue 的各组件在安卓端默认是透明的,如果不设置background-color,可能会导致出现重影的问题</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> #ifdef APP-NVUE</span>
<span style="color: rgba(0, 0, 255, 1)">if</span>(opts.value.customStyle && !opts.value.customStyle['background'] && !opts.value.customStyle['background-color'<span style="color: rgba(0, 0, 0, 1)">]) {
opts.value.customStyle[</span>'background'] = '#fff'<span style="color: rgba(0, 0, 0, 1)">
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> #endif</span>
<span style="color: rgba(0, 0, 0, 1)">
let _index </span>= ++<span style="color: rgba(0, 0, 0, 1)">index
oIndex.value </span>= _index +<span style="color: rgba(0, 0, 0, 1)"> parseInt(opts.value.zIndex)
emit(</span>'open'<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">typeof</span> opts.value.onOpen === 'function' &&<span style="color: rgba(0, 0, 0, 1)"> opts.value.onOpen()
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 长按处理</span>
<span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(opts.value.follow) {
nextTick(() </span>=><span style="color: rgba(0, 0, 0, 1)"> {
let winW </span>=<span style="color: rgba(0, 0, 0, 1)"> uni.getSystemInfoSync().windowWidth
let winH </span>=<span style="color: rgba(0, 0, 0, 1)"> uni.getSystemInfoSync().windowHeight
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> console.log('坐标点信息:', opts.value.follow)</span>
getDom(uuid.value).then(res =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> console.log('Dom尺寸信息:', res)</span>
<span style="color: rgba(0, 0, 255, 1)">if</span>(!res) <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
let pos </span>= getPos(opts.value.follow, opts.value.follow, res.width+15, res.height+15<span style="color: rgba(0, 0, 0, 1)">, winW, winH)
positionStyle.value.left </span>= pos + 'px'<span style="color: rgba(0, 0, 0, 1)">
positionStyle.value.top </span>= pos + 'px'<span style="color: rgba(0, 0, 0, 1)">
})
})
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(opts.value.time) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(stopTimer.value) clearTimeout(stopTimer.value)
stopTimer.value </span>= setTimeout(() =><span style="color: rgba(0, 0, 0, 1)"> {
close()
}, parseInt(opts.value.time) </span>* 1000<span style="color: rgba(0, 0, 0, 1)">)
}
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 关闭弹框</span>
const close = () =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(!visible.value) <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
closeAnim.value </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
setTimeout(() </span>=><span style="color: rgba(0, 0, 0, 1)"> {
visible.value </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
closeAnim.value </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
emit(</span>'update:modelValue', <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">)
emit(</span>'close'<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">typeof</span> opts.value.onClose === 'function' &&<span style="color: rgba(0, 0, 0, 1)"> opts.value.onClose()
positionStyle.value.left </span>= '-999px'<span style="color: rgba(0, 0, 0, 1)">
positionStyle.value.top </span>= '-999px'<span style="color: rgba(0, 0, 0, 1)">
stopTimer.value </span>&&<span style="color: rgba(0, 0, 0, 1)"> clearTimeout(stopTimer.value)
}, </span>200<span style="color: rgba(0, 0, 0, 1)">)
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 点击遮罩层</span>
const handleShadeClick = () =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(JSON.parse(opts.value.shadeClose)) {
close()
}
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 按钮事件</span>
const handleBtnClick = (e, index) =><span style="color: rgba(0, 0, 0, 1)"> {
let btn </span>=<span style="color: rgba(0, 0, 0, 1)"> opts.value.btns
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(!btn?<span style="color: rgba(0, 0, 0, 1)">.disabled) {
console.log(</span>'按钮事件类型:', <span style="color: rgba(0, 0, 255, 1)">typeof</span><span style="color: rgba(0, 0, 0, 1)"> btn.click)
</span><span style="color: rgba(0, 0, 255, 1)">typeof</span> btn.click === 'function' &&<span style="color: rgba(0, 0, 0, 1)"> btn.click(e)
}
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取dom宽高</span>
const getDom = (id) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Promise((resolve, inject) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> uniapp vue3中 uni.createSelectorQuery().in(this) 会报错__route__未定义https://ask.dcloud.net.cn/question/140192</span>
uni.createSelectorQuery().<span style="color: rgba(0, 0, 255, 1)">in</span>(instance).select('#uapopup-' +<span style="color: rgba(0, 0, 0, 1)"> id).fields({
size: </span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
}, data </span>=><span style="color: rgba(0, 0, 0, 1)"> {
resolve(data)
}).exec()
})
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 自适应坐标点</span>
const getPos = (x, y, ow, oh, winW, winH) =><span style="color: rgba(0, 0, 0, 1)"> {
let l </span>= (x + ow) > winW ? x -<span style="color: rgba(0, 0, 0, 1)"> ow : x
let t </span>= (y + oh) > winH ? y -<span style="color: rgba(0, 0, 0, 1)"> oh : y
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
}
onMounted(() </span>=><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(props.modelValue) {
open()
}
})
watch(() </span>=> props.modelValue, (val) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> console.log(val)</span>
<span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(val) {
open()
}</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
close()
}
})
defineExpose({
open,
close
})
</span></script></pre>
</div>
<h3>uniapp+vue3聊天模块</h3>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429133559816-1045161084.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429134016820-1563275812.png"> <img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429133838509-345189288.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429134115447-1886078050.png"></p>
<p><span style="font-size: 12px">uniapp+vue3实现增强版文本输入框。支持获取焦点高亮边框、单行(input)+多行(textarea)输入模式,自定义前缀/后缀图标。</span></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429134427655-151379229.png"></p>
<p><span style="font-size: 18px; font-family: 宋体, "Songti SC"; color: rgba(255, 0, 0, 1); background-color: rgba(255, 255, 153, 1)">该插件已经免费发布到插件应用市场,有需要的可以去看看哈~</span></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429134723495-808597927.gif"></p>
<p>如上图:实现了类似<strong>微信按住说话</strong>功能。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 语音操作面板 </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">v-if</span><span style="color: rgba(0, 0, 255, 1)">="voicePanelEnable"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="uv3__voicepanel-popup"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="uv3__voicepanel-body flexbox flex-col"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 取消发送+语音转文字 </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">v-if</span><span style="color: rgba(0, 0, 255, 1)">="!voiceToTransfer"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="uv3__voicepanel-transfer"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 提示动效 </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="animtips flexbox"</span><span style="color: rgba(255, 0, 0, 1)"> :class</span><span style="color: rgba(0, 0, 255, 1)">="voiceType == 2 ? 'left' : voiceType == 3 ? 'right' : null"</span><span style="color: rgba(0, 0, 255, 1)">><</span><span style="color: rgba(128, 0, 0, 1)">Waves </span><span style="color: rgba(255, 0, 0, 1)">:lines</span><span style="color: rgba(0, 0, 255, 1)">=".includes(voiceType) ? 10 : 20"</span> <span style="color: rgba(0, 0, 255, 1)">/></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 操作项 </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="icobtns flexbox"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="vbtn cancel flexbox flex-col"</span><span style="color: rgba(255, 0, 0, 1)"> :class</span><span style="color: rgba(0, 0, 255, 1)">="{'hover': voiceType == 2}"</span><span style="color: rgba(255, 0, 0, 1)"> @click</span><span style="color: rgba(0, 0, 255, 1)">="handleVoiceCancel"</span><span style="color: rgba(0, 0, 255, 1)">><</span><span style="color: rgba(128, 0, 0, 1)">text </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="vicon uv3-icon uv3-icon-close"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="vbtn word flexbox flex-col"</span><span style="color: rgba(255, 0, 0, 1)"> :class</span><span style="color: rgba(0, 0, 255, 1)">="{'hover': voiceType == 3}"</span><span style="color: rgba(0, 0, 255, 1)">><</span><span style="color: rgba(128, 0, 0, 1)">text </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="vicon uv3-icon uv3-icon-word"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 语音转文字(识别结果状态) </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">v-if</span><span style="color: rgba(0, 0, 255, 1)">="voiceToTransfer"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="uv3__voicepanel-transfer result fail"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 提示动效 </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="animtips flexbox"</span><span style="color: rgba(0, 0, 255, 1)">><</span><span style="color: rgba(128, 0, 0, 1)">uni-icons </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="info-filled"</span><span style="color: rgba(255, 0, 0, 1)"> color</span><span style="color: rgba(0, 0, 255, 1)">="#fff"</span><span style="color: rgba(255, 0, 0, 1)"> size</span><span style="color: rgba(0, 0, 255, 1)">="20"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">uni-icons</span><span style="color: rgba(0, 0, 255, 1)">><</span><span style="color: rgba(128, 0, 0, 1)">text </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="c-fff"</span><span style="color: rgba(0, 0, 255, 1)">></span>未识别到文字<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 操作项 </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="icobtns flexbox"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="vbtn cancel flexbox flex-col"</span><span style="color: rgba(255, 0, 0, 1)"> @click</span><span style="color: rgba(0, 0, 255, 1)">="handleVoiceCancel"</span><span style="color: rgba(0, 0, 255, 1)">><</span><span style="color: rgba(128, 0, 0, 1)">text </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="vicon uv3-icon uv3-icon-chexiao"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">></span>取消<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="vbtn word flexbox flex-col"</span><span style="color: rgba(0, 0, 255, 1)">><</span><span style="color: rgba(128, 0, 0, 1)">text </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="vicon uv3-icon uv3-icon-audio"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">></span>发送原语音<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="vbtn check flexbox flex-col"</span><span style="color: rgba(0, 0, 255, 1)">><</span><span style="color: rgba(128, 0, 0, 1)">text </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="vicon uv3-icon uv3-icon-duigou"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 背景语音图 </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="uv3__voicepanel-cover"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">image </span><span style="color: rgba(255, 0, 0, 1)">v-if</span><span style="color: rgba(0, 0, 255, 1)">="!voiceToTransfer"</span><span style="color: rgba(255, 0, 0, 1)"> src</span><span style="color: rgba(0, 0, 255, 1)">="/static/voice_bg.webp"</span><span style="color: rgba(255, 0, 0, 1)"> :webp</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(255, 0, 0, 1)"> mode</span><span style="color: rgba(0, 0, 255, 1)">="widthFix"</span><span style="color: rgba(255, 0, 0, 1)"> style</span><span style="color: rgba(0, 0, 255, 1)">="width: 100%;"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> // 提示文字(操作状态) </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">v-if</span><span style="color: rgba(0, 0, 255, 1)">="!voiceToTransfer"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="uv3__voicepanel-tooltip"</span><span style="color: rgba(0, 0, 255, 1)">></span>{{voiceTypeMap}}<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 背景小图标 </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">v-if</span><span style="color: rgba(0, 0, 255, 1)">="!voiceToTransfer"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="uv3__voicepanel-fixico"</span><span style="color: rgba(0, 0, 255, 1)">><</span><span style="color: rgba(128, 0, 0, 1)">text </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="uv3-icon uv3-icon-audio fs-50"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
</div>
<p>OK,以上就是uni-app+vue3开发多端聊天app实例的一些知识分享,希望对大家有所帮助!</p>
<blockquote>
<p><span style="font-size: 12px">flutter3-deepseek流式AI模板|Flutter3.27+Dio+DeepSeeek聊天ai助手</span></p>
<p><span style="font-size: 12px">Uniapp-DeepSeek跨三端AI助手|uniapp+vue3+deepseek-v3流式ai聊天模板</span></p>
<p><span style="font-size: 12px">Electron35-DeepSeek桌面端AI系统|vue3.5+electron+arco客户端ai模板</span></p>
<p><span style="font-size: 12px">Vite5+Electron聊天室|electron31跨平台仿微信EXE客户端|vue3聊天程序</span></p>
<p><span style="font-size: 12px">Electron31-Vue3Admin管理系统|vite5+electron+pinia桌面端后台Exe</span></p>
<p><span style="font-size: 12px">Tauri2.0-Vue3OS桌面端os平台|tauri2+vite6+arco电脑版OS管理系统</span></p>
</blockquote>
<p><strong>最后附上几个最新实战项目</strong></p>
<p><span style="font-size: 12px">uniapp+vite酒店预订app模板:https://www.cnblogs.com/xiaoyan2017/p/18592873</span></p>
<p><span style="font-size: 12px">uniapp+vue3手机版os系统:https://www.cnblogs.com/xiaoyan2017/p/18204751</span></p>
<p><span style="font-size: 12px">flutter3.27短视频直播商城:https://www.cnblogs.com/xiaoyan2017/p/18700875<br></span></p>
<p><span style="font-size: 12px">flutter3+window_manager仿macOS桌面系统:https://www.cnblogs.com/xiaoyan2017/p/18132176</span></p>
<p><span style="font-size: 12px">flutter3.27仿携程app酒店预订系统:https://www.cnblogs.com/xiaoyan2017/p/18726313</span></p>
<p><img src="https://img2024.cnblogs.com/blog/1289798/202404/1289798-20240429135428883-320532133.gif"></p>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
本文为博主原创文章,未经博主允许不得转载,欢迎大家一起交流 QQ(282310962) wx(xy190310)<br><br>
来源:https://www.cnblogs.com/xiaoyan2017/p/18165578
頁:
[1]