天山玉米 發表於 2024-4-29 13:56:00

uniapp+vue3聊天室|uni-app+vite4+uv-ui跨端仿微信app聊天语音/朋友圈

<p><span style="font-size: 18px; font-family: 宋体, &quot;Songti SC&quot;; 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>&lt;script setup&gt;<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>=&gt;<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>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      console.log(</span>'App Show'<span style="color: rgba(0, 0, 0, 1)">)
    })
   
    onHide(() </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      console.log(</span>'App Hide'<span style="color: rgba(0, 0, 0, 1)">)
    })
   
    onPageNotFound((e) </span>=&gt;<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 = () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      uni.getSystemInfo({
            success: (e) </span>=&gt;<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>&lt;/script&gt;

&lt;style&gt;
    <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>
&lt;/style&gt;
&lt;style lang="scss"&gt;<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>&lt;/style&gt;</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)">&lt;</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)">/&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</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)">/&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</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)">/&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</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)">/&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</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)">/&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</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)">/&gt;</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</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)">/&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;</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)">/&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>首页<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">/&gt;</span><span style="color: rgba(0, 0, 0, 1)"> Admin
    </span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;</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)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;</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)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">uv3-navbar</span><span style="color: rgba(0, 0, 255, 1)">&gt;</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">&nbsp;&nbsp;<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)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 公共布局模板 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>

<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> #ifdef MP-WEIXIN </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</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)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> #endif </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</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)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
      <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 顶部插槽 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">/&gt;</span>
      
      <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 内容区 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">slot </span><span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      
      <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 底部插槽 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">/&gt;</span>
      
      <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> tabbar栏 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</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)">&lt;</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)">&gt;</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)">=&gt;</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)">=&gt;</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)">&lt;</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)">=&gt;</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) =&gt; {
                  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)">=&gt;</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)">=&gt;</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)">=&gt;</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)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</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 &gt; 1"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">canvas</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</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)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">style</span><span style="color: rgba(0, 0, 255, 1)">&gt;</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">&nbsp;&nbsp;<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">&nbsp;&nbsp;<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">&nbsp;&nbsp;<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)">&lt;</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)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</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>&lt;script setup&gt;<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(() =&gt; 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) =&gt;<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 &amp;&amp; !opts.value.customStyle['background'] &amp;&amp; !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' &amp;&amp;<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>=&gt;<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 =&gt;<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(() =&gt;<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 = () =&gt;<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>=&gt;<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' &amp;&amp;<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>&amp;&amp;<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 = () =&gt;<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) =&gt;<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' &amp;&amp;<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) =&gt;<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) =&gt;<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>=&gt;<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) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      let l </span>= (x + ow) &gt; winW ? x -<span style="color: rgba(0, 0, 0, 1)"> ow : x
      let t </span>= (y + oh) &gt; 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>=&gt;<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>=&gt; props.modelValue, (val) =&gt;<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>&lt;/script&gt;</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">&nbsp;&nbsp;<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: 宋体, &quot;Songti SC&quot;; 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)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 语音操作面板 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
      <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 取消发送+语音转文字 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
            <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 提示动效 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;</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)">/&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 操作项 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
                <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;</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)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
                <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;</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)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      
      <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 语音转文字(识别结果状态) </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
            <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 提示动效 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;</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)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">uni-icons</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;</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)">&gt;</span>未识别到文字<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 操作项 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
                <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;</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)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>取消<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
                <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;</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)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>发送原语音<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
                <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;</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)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      
      <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 背景语音图 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">/&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> // 提示文字(操作状态) </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;</span>{{voiceTypeMap}}<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 背景小图标 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</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)">&gt;&lt;</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)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</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>&nbsp;</p>

</div>
<div id="MySignature" role="contentinfo">
    本文为博主原创文章,未经博主允许不得转载,欢迎大家一起交流 QQ(282310962) wx(xy190310)<br><br>
来源:https://www.cnblogs.com/xiaoyan2017/p/18165578
頁: [1]
查看完整版本: uniapp+vue3聊天室|uni-app+vite4+uv-ui跨端仿微信app聊天语音/朋友圈