<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>吖远zzyの博客</title>
  <icon>https://www.hzv5.cn/icon.png</icon>
  <subtitle>一个不知名的编程爱好者</subtitle>
  <link href="https://www.hzv5.cn/atom.xml" rel="self"/>
  
  <link href="https://www.hzv5.cn/"/>
  <updated>2025-01-18T14:11:22.000Z</updated>
  <id>https://www.hzv5.cn/</id>
  
  <author>
    <name>吖远zzy</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>个人开发工具之抖音直播录制工具：一款功能强大的Android直播录制应用</title>
    <link href="https://www.hzv5.cn/2025/01/18/douyin-blog-post/"/>
    <id>https://www.hzv5.cn/2025/01/18/douyin-blog-post/</id>
    <published>2025-01-18T14:11:22.000Z</published>
    <updated>2025-01-18T14:11:22.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>在移动互联网时代，直播已经成为一种重要的内容形式。有时我们会希望将喜欢的直播内容保存下来，以便日后回顾或学习。今天为大家介绍一款博主设计并基于uni-app开发的抖音直播录制工具，它不仅支持普通的录制功能，可以进行后台不需要看着直播画面进行录制抖音直播画面，还具备自动检测、后台保活等进阶特性。</p><p><img src="/img/douyin/01.jpg" alt="配图_应用主界面截图"></p><span id="more"></span><h2 id="核心功能"><a href="#核心功能" class="headerlink" title="核心功能"></a>核心功能</h2><h3 id="1-多样化的链接支持"><a href="#1-多样化的链接支持" class="headerlink" title="1. 多样化的链接支持"></a>1. 多样化的链接支持</h3><p>这款工具支持多种形式的直播链接输入：</p><ul><li>标准直播间链接</li><li>短链接</li><li>分享文本（从抖音APP复制的分享内容）</li></ul><h3 id="2-智能解析与录制"><a href="#2-智能解析与录制" class="headerlink" title="2. 智能解析与录制"></a>2. 智能解析与录制</h3><p>输入链接后，工具会自动解析并显示直播信息：</p><ul><li>主播昵称</li><li>直播间标题</li><li>实时在线人数</li><li>直播源地址</li></ul><p><img src="/img/douyin/02.png" alt="配图_解析界面"></p><p>解析完成后，只需点击”开始录制”即可开始保存直播内容。录制过程中可以实时查看：</p><ul><li>已录制时长</li><li>文件大小</li><li>录制状态</li></ul><p><img src="/img/douyin/03.png" alt="配图_录制界面"></p><h3 id="3-自动检测功能"><a href="#3-自动检测功能" class="headerlink" title="3. 自动检测功能"></a>3. 自动检测功能</h3><p>最实用的功能之一是自动检测系统：</p><ol><li>输入直播链接后开启自动检测</li><li>系统会定期检查直播状态</li><li>检测到开播自动开始录制</li><li>直播结束自动停止录制</li></ol><p>这个功能特别适合：</p><ul><li>不定时开播的主播</li><li>需要完整录制的长直播</li><li>多场直播的批量录制</li></ul><h3 id="4-后台保活机制"><a href="#4-后台保活机制" class="headerlink" title="4. 后台保活机制"></a>4. 后台保活机制</h3><p>为了确保录制的稳定性，工具实现了完整的后台保活机制：</p><ul><li>悬浮窗权限</li><li>电池优化白名单</li><li>前台服务保活</li></ul><h3 id="5-历史记录管理"><a href="#5-历史记录管理" class="headerlink" title="5. 历史记录管理"></a>5. 历史记录管理</h3><p>工具提供了两种历史记录功能：</p><ol><li><p>录制文件历史</p><ul><li>支持视频预览</li><li>文件重命名</li><li>快速删除</li></ul></li><li><p>输入链接历史</p><ul><li>保存最近使用的链接</li><li>记录主播昵称</li><li>一键重复录制</li></ul></li></ol><p><img src="/img/douyin/04.png" alt="配图_历史记录界面"></p><h2 id="使用技巧"><a href="#使用技巧" class="headerlink" title="使用技巧"></a>使用技巧</h2><h3 id="基础录制流程"><a href="#基础录制流程" class="headerlink" title="基础录制流程"></a>基础录制流程</h3><ol><li>从抖音APP复制直播链接</li><li>粘贴到输入框</li><li>点击”获取直播源”</li><li>确认信息无误后点击”开始录制”</li><li>录制完成后点击”结束录制”</li></ol><h3 id="自动检测使用方法"><a href="#自动检测使用方法" class="headerlink" title="自动检测使用方法"></a>自动检测使用方法</h3><ol><li>输入直播链接</li><li>打开自动检测开关</li><li>保持应用在后台运行</li><li>系统会自动处理录制过程</li></ol><h3 id="提升录制稳定性"><a href="#提升录制稳定性" class="headerlink" title="提升录制稳定性"></a>提升录制稳定性</h3><ol><li>首次使用时授予所有必要权限</li><li>开启悬浮窗和忽略电池优化</li><li>将应用加入系统后台白名单</li><li>确保设备有足够的存储空间</li><li>保持网络连接稳定</li></ol><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li><p><strong>权限说明</strong></p><ul><li>存储权限：用于保存录制文件</li><li>悬浮窗权限：提高后台存活率</li><li>电池优化：防止系统休眠影响录制</li></ul></li><li><p><strong>资源消耗</strong></p><ul><li>建议在WiFi环境下使用</li><li>录制时会持续占用网络带宽</li><li>注意监控存储空间使用情况</li></ul></li><li><p><strong>使用限制</strong></p><ul><li>仅支持Android系统</li><li>需要Android 7.0及以上版本</li><li>部分机型可能需要特殊设置</li></ul></li></ol><h2 id="常见问题解答"><a href="#常见问题解答" class="headerlink" title="常见问题解答"></a>常见问题解答</h2><ol><li><p>Q: 为什么录制会自动停止？<br>A: 可能的原因有：</p><ul><li>直播已结束</li><li>网络连接不稳定</li><li>存储空间不足</li><li>后台进程被清理</li></ul></li><li><p>Q: 如何处理录制失败？<br>A: 建议按以下步骤排查：</p><ul><li>检查网络连接</li><li>验证存储权限</li><li>确认保活设置</li><li>清理设备存储空间</li></ul></li><li><p>Q: 自动检测不工作？<br>A: 请确认：</p><ul><li>是否授予了必要权限</li><li>链接格式是否正确</li><li>后台运行是否正常</li><li>检测间隔是否合理</li></ul></li></ol><h2 id="未来展望"><a href="#未来展望" class="headerlink" title="未来展望"></a>未来展望</h2><p>未来计划添加的功能：</p><ol><li>支持更多直播平台</li><li>添加录制视频剪辑功能</li><li>优化文件管理系统</li><li>提供更多自定义选项</li><li>增加云端备份功能</li></ol><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>这款抖音直播录制工具虽然功能强大，但使用简单直观。无论是普通用户还是专业用户，都能快速上手使用。希望这篇文章能帮助大家更好地使用这款工具。</p><h2 id="免责声明"><a href="#免责声明" class="headerlink" title="免责声明"></a>免责声明</h2><p>本工具仅供学习交流使用，请勿用于任何商业用途。使用本工具时，请遵守相关法律法规，尊重直播作者的权益。对于使用本工具所产生的任何问题，本项目概不负责。 </p>]]></content>
    
    
    <summary type="html">可以进行后台录制抖音直播画面的uniapp安卓端应用，再不需要打开直播间画面的情况下实现录制直播间的直播内容，无弹幕无礼物特效的纯净录屏。</summary>
    
    
    
    <category term="应用开发" scheme="https://www.hzv5.cn/categories/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91/"/>
    
    <category term="工具分享" scheme="https://www.hzv5.cn/categories/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    
    <category term="Android" scheme="https://www.hzv5.cn/tags/Android/"/>
    
    <category term="直播录制" scheme="https://www.hzv5.cn/tags/%E7%9B%B4%E6%92%AD%E5%BD%95%E5%88%B6/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="实用工具" scheme="https://www.hzv5.cn/tags/%E5%AE%9E%E7%94%A8%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>UniApp中Canvas绘图的易错点与踩坑指南</title>
    <link href="https://www.hzv5.cn/2025/01/10/uniapp-canvas-error/"/>
    <id>https://www.hzv5.cn/2025/01/10/uniapp-canvas-error/</id>
    <published>2025-01-10T13:12:28.000Z</published>
    <updated>2025-01-10T13:12:28.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>在UniApp中使用Canvas绘图时，常常会遇到一些容易忽略的问题和陷阱。本文将总结这些易错点，并提供解决方案，帮助你避免踩坑，提升开发效率。</p></blockquote><span id="more"></span><hr><h3 id="1-易错点与踩坑指南"><a href="#1-易错点与踩坑指南" class="headerlink" title="1. 易错点与踩坑指南"></a><strong>1. 易错点与踩坑指南</strong></h3><h4 id="1-1-Canvas上下文未正确获取"><a href="#1-1-Canvas上下文未正确获取" class="headerlink" title="1.1 Canvas上下文未正确获取"></a><strong>1.1 Canvas上下文未正确获取</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>调用<code>uni.createCanvasContext</code>后，绘图操作未生效。</li></ul></li><li><strong>原因</strong>：<ul><li>未正确获取Canvas上下文，或未调用<code>ctx.draw()</code>方法。</li></ul></li><li><strong>解决方案</strong>：<ol><li>确保正确获取Canvas上下文：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> ctx = uni.<span class="title function_">createCanvasContext</span>(<span class="string">&#x27;myCanvas&#x27;</span>);</span><br></pre></td></tr></table></figure></li><li>在绘图操作后调用<code>ctx.draw()</code>：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ctx.<span class="title function_">fillRect</span>(<span class="number">10</span>, <span class="number">10</span>, <span class="number">100</span>, <span class="number">100</span>);</span><br><span class="line">ctx.<span class="title function_">draw</span>(); <span class="comment">// 必须调用draw方法才会生效</span></span><br></pre></td></tr></table></figure></li></ol></li></ul><h4 id="1-2-Canvas尺寸设置不当"><a href="#1-2-Canvas尺寸设置不当" class="headerlink" title="1.2 Canvas尺寸设置不当"></a><strong>1.2 Canvas尺寸设置不当</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>Canvas绘图内容显示不全或完全不可见。</li></ul></li><li><strong>原因</strong>：<ul><li>Canvas的宽度或高度设置不正确，或者未适配屏幕分辨率。</li></ul></li><li><strong>解决方案</strong>：<ol><li>在<code>&lt;canvas&gt;</code>标签中设置正确的宽度和高度：<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">canvas</span> <span class="attr">canvas-id</span>=<span class="string">&quot;myCanvas&quot;</span> <span class="attr">style</span>=<span class="string">&quot;width: 300px; height: 300px;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">canvas</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li>使用<code>uni.getSystemInfoSync</code>获取屏幕宽度并动态设置Canvas尺寸：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> systemInfo = uni.<span class="title function_">getSystemInfoSync</span>();</span><br><span class="line"><span class="keyword">const</span> canvasWidth = systemInfo.<span class="property">windowWidth</span>;</span><br><span class="line"><span class="keyword">const</span> canvasHeight = systemInfo.<span class="property">windowHeight</span>;</span><br></pre></td></tr></table></figure></li></ol></li></ul><h4 id="1-3-Canvas层级问题"><a href="#1-3-Canvas层级问题" class="headerlink" title="1.3 Canvas层级问题"></a><strong>1.3 Canvas层级问题</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>Canvas被其他组件遮挡，导致绘图内容不可见。</li></ul></li><li><strong>原因</strong>：<ul><li>Canvas的层级（z-index）较低，或被其他组件覆盖。</li></ul></li><li><strong>解决方案</strong>：<ol><li>使用<code>position: fixed</code>或<code>position: absolute</code>提升Canvas层级：<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">canvas</span> <span class="attr">canvas-id</span>=<span class="string">&quot;myCanvas&quot;</span> <span class="attr">style</span>=<span class="string">&quot;position: fixed; top: 0; left: 0;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">canvas</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li>避免在Canvas上方放置其他组件。</li></ol></li></ul><h4 id="1-4-Canvas渲染时机问题"><a href="#1-4-Canvas渲染时机问题" class="headerlink" title="1.4 Canvas渲染时机问题"></a><strong>1.4 Canvas渲染时机问题</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>在页面加载时绘图，但内容未显示。</li></ul></li><li><strong>原因</strong>：<ul><li>Canvas渲染时机过早，页面尚未完全加载。</li></ul></li><li><strong>解决方案</strong>：<ol><li>在<code>onReady</code>生命周期中执行绘图操作：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="title function_">onReady</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> ctx = uni.<span class="title function_">createCanvasContext</span>(<span class="string">&#x27;myCanvas&#x27;</span>);</span><br><span class="line">    ctx.<span class="title function_">fillRect</span>(<span class="number">10</span>, <span class="number">10</span>, <span class="number">100</span>, <span class="number">100</span>);</span><br><span class="line">    ctx.<span class="title function_">draw</span>();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></li><li>使用<code>setTimeout</code>延迟绘图操作：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> ctx = uni.<span class="title function_">createCanvasContext</span>(<span class="string">&#x27;myCanvas&#x27;</span>);</span><br><span class="line">  ctx.<span class="title function_">fillRect</span>(<span class="number">10</span>, <span class="number">10</span>, <span class="number">100</span>, <span class="number">100</span>);</span><br><span class="line">  ctx.<span class="title function_">draw</span>();</span><br><span class="line">&#125;, <span class="number">500</span>);</span><br></pre></td></tr></table></figure></li></ol></li></ul><h4 id="1-5-Canvas绘图性能问题"><a href="#1-5-Canvas绘图性能问题" class="headerlink" title="1.5 Canvas绘图性能问题"></a><strong>1.5 Canvas绘图性能问题</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>绘图操作卡顿或延迟。</li></ul></li><li><strong>原因</strong>：<ul><li>绘图操作过于频繁，或Canvas尺寸过大。</li></ul></li><li><strong>解决方案</strong>：<ol><li>减少不必要的绘图操作。</li><li>使用<code>ctx.draw(true)</code>开启离屏渲染，提升性能。</li></ol></li></ul><h4 id="1-6-Canvas绘图内容模糊"><a href="#1-6-Canvas绘图内容模糊" class="headerlink" title="1.6 Canvas绘图内容模糊"></a><strong>1.6 Canvas绘图内容模糊</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>绘图内容显示模糊。</li></ul></li><li><strong>原因</strong>：<ul><li>Canvas的CSS尺寸与画布分辨率不匹配。</li></ul></li><li><strong>解决方案</strong>：<ol><li>使用<code>uni.getSystemInfoSync</code>获取设备像素比（<code>pixelRatio</code>），并设置Canvas的实际分辨率：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> systemInfo = uni.<span class="title function_">getSystemInfoSync</span>();</span><br><span class="line"><span class="keyword">const</span> pixelRatio = systemInfo.<span class="property">pixelRatio</span>;</span><br><span class="line"><span class="keyword">const</span> canvasWidth = <span class="number">300</span> * pixelRatio;</span><br><span class="line"><span class="keyword">const</span> canvasHeight = <span class="number">300</span> * pixelRatio;</span><br></pre></td></tr></table></figure></li><li>在CSS中设置Canvas的显示尺寸为逻辑像素：<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">canvas</span> <span class="attr">canvas-id</span>=<span class="string">&quot;myCanvas&quot;</span> <span class="attr">style</span>=<span class="string">&quot;width: 300px; height: 300px;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">canvas</span>&gt;</span></span><br></pre></td></tr></table></figure></li></ol></li></ul><hr><h3 id="2-示例代码"><a href="#2-示例代码" class="headerlink" title="2. 示例代码"></a><strong>2. 示例代码</strong></h3><p>以下是一个完整的Canvas绘图示例，涵盖了上述问题的解决方案：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">view</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">canvas</span> <span class="attr">canvas-id</span>=<span class="string">&quot;myCanvas&quot;</span> <span class="attr">style</span>=<span class="string">&quot;width: 300px; height: 300px;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">canvas</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">view</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="language-javascript">  <span class="title function_">onReady</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">this</span>.<span class="title function_">drawCanvas</span>();</span></span><br><span class="line"><span class="language-javascript">  &#125;,</span></span><br><span class="line"><span class="language-javascript">  <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">drawCanvas</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> systemInfo = uni.<span class="title function_">getSystemInfoSync</span>();</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> pixelRatio = systemInfo.<span class="property">pixelRatio</span>;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> canvasWidth = <span class="number">300</span> * pixelRatio;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> canvasHeight = <span class="number">300</span> * pixelRatio;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> ctx = uni.<span class="title function_">createCanvasContext</span>(<span class="string">&#x27;myCanvas&#x27;</span>);</span></span><br><span class="line"><span class="language-javascript">      ctx.<span class="title function_">fillRect</span>(<span class="number">10</span>, <span class="number">10</span>, <span class="number">100</span>, <span class="number">100</span>);</span></span><br><span class="line"><span class="language-javascript">      ctx.<span class="title function_">draw</span>();</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript">&#125;;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="language-css"></span></span><br><span class="line"><span class="language-css"><span class="selector-tag">canvas</span> &#123;</span></span><br><span class="line"><span class="language-css">  <span class="attribute">position</span>: fixed;</span></span><br><span class="line"><span class="language-css">  <span class="attribute">top</span>: <span class="number">0</span>;</span></span><br><span class="line"><span class="language-css">  <span class="attribute">left</span>: <span class="number">0</span>;</span></span><br><span class="line"><span class="language-css">&#125;</span></span><br><span class="line"><span class="language-css"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br></pre></td></tr></table></figure><hr><h3 id="3-总结"><a href="#3-总结" class="headerlink" title="3. 总结"></a><strong>3. 总结</strong></h3><p>在UniApp中使用Canvas绘图时，常见的易错点包括上下文未正确获取、Canvas尺寸问题、层级问题和渲染时机问题。通过本文提供的解决方案，你可以快速定位并解决这些问题，确保Canvas绘图内容正常显示。</p><blockquote><p>希望这篇博客对你有帮助！如果有其他问题，欢迎随时交流！ 🚀</p></blockquote>]]></content>
    
    
    <summary type="html">深入探讨uni-app组件Canvas开发的最佳实践,包括基础组件封装、组件通信、绘图不显示的常见问题与解决方案等内容,帮助开发者构建高质量的UI组件库。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    <category term="canvas" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/canvas/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="组件开发" scheme="https://www.hzv5.cn/tags/%E7%BB%84%E4%BB%B6%E5%BC%80%E5%8F%91/"/>
    
    <category term="UI组件" scheme="https://www.hzv5.cn/tags/UI%E7%BB%84%E4%BB%B6/"/>
    
  </entry>
  
  <entry>
    <title>QQ频道机器人与UniApp开发：常见踩坑点与解决方案</title>
    <link href="https://www.hzv5.cn/2025/01/07/uniapp-qq-channel-bot/"/>
    <id>https://www.hzv5.cn/2025/01/07/uniapp-qq-channel-bot/</id>
    <published>2025-01-07T03:41:22.000Z</published>
    <updated>2025-01-07T03:41:22.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>在开发QQ频道机器人和UniApp应用的过程中，可能会遇到一些常见的错误和坑。本文将总结这些容易出错的地方，并提供解决方案，帮助你更顺利地完成开发。</p></blockquote><span id="more"></span><hr><h3 id="1-QQ频道机器人开发中的常见问题"><a href="#1-QQ频道机器人开发中的常见问题" class="headerlink" title="1. QQ频道机器人开发中的常见问题"></a><strong>1. QQ频道机器人开发中的常见问题</strong></h3><h4 id="1-1-权限问题"><a href="#1-1-权限问题" class="headerlink" title="1.1 权限问题"></a><strong>1.1 权限问题</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>调用API时返回“权限不足”或“未授权”错误。</li></ul></li><li><strong>原因</strong>：<ul><li>未正确申请API权限，或未在请求头中携带正确的<code>Authorization</code>。</li></ul></li><li><strong>解决方案</strong>：<ol><li>在QQ开放平台确认已申请相关API权限。</li><li>确保请求头中包含正确的<code>Authorization</code>，格式为：<code>Bot &#123;BotToken&#125;</code>。</li></ol></li></ul><h4 id="1-2-消息发送失败"><a href="#1-2-消息发送失败" class="headerlink" title="1.2 消息发送失败"></a><strong>1.2 消息发送失败</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>发送消息时返回“频道不存在”或“消息发送失败”。</li></ul></li><li><strong>原因</strong>：<ul><li>频道ID错误，或机器人未加入目标频道。</li></ul></li><li><strong>解决方案</strong>：<ol><li>确认频道ID是否正确。</li><li>确保机器人已加入目标频道。</li></ol></li></ul><h4 id="1-3-Webhook配置问题"><a href="#1-3-Webhook配置问题" class="headerlink" title="1.3 Webhook配置问题"></a><strong>1.3 Webhook配置问题</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>Webhook无法接收消息，或消息格式解析失败。</li></ul></li><li><strong>原因</strong>：<ul><li>Webhook地址未正确配置，或未处理消息的加密和签名。</li></ul></li><li><strong>解决方案</strong>：<ol><li>在QQ开放平台正确配置Webhook地址。</li><li>参考官方文档处理消息的加密和签名验证。</li></ol></li></ul><hr><h3 id="2-UniApp开发中的常见问题"><a href="#2-UniApp开发中的常见问题" class="headerlink" title="2. UniApp开发中的常见问题"></a><strong>2. UniApp开发中的常见问题</strong></h3><h4 id="2-1-跨域问题"><a href="#2-1-跨域问题" class="headerlink" title="2.1 跨域问题"></a><strong>2.1 跨域问题</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>在H5端调用API时，出现跨域错误。</li></ul></li><li><strong>原因</strong>：<ul><li>后端服务未配置CORS（跨域资源共享）。</li></ul></li><li><strong>解决方案</strong>：<ol><li>在后端服务中添加CORS支持：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>();</span><br><span class="line">app.<span class="title function_">use</span>(<span class="function">(<span class="params">req, res, next</span>) =&gt;</span> &#123;</span><br><span class="line">  res.<span class="title function_">header</span>(<span class="string">&#x27;Access-Control-Allow-Origin&#x27;</span>, <span class="string">&#x27;*&#x27;</span>);</span><br><span class="line">  res.<span class="title function_">header</span>(<span class="string">&#x27;Access-Control-Allow-Headers&#x27;</span>, <span class="string">&#x27;Content-Type&#x27;</span>);</span><br><span class="line">  <span class="title function_">next</span>();</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li><li>在UniApp中使用代理解决跨域问题：<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// manifest.json</span></span><br><span class="line"><span class="attr">&quot;h5&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;devServer&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;proxy&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;/api&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;target&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://your-server.com&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;changeOrigin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span></span><br><span class="line">      <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></li></ol></li></ul><h4 id="2-2-样式兼容性问题"><a href="#2-2-样式兼容性问题" class="headerlink" title="2.2 样式兼容性问题"></a><strong>2.2 样式兼容性问题</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>在不同平台上样式显示不一致。</li></ul></li><li><strong>原因</strong>：<ul><li>不同平台对CSS的支持存在差异。</li></ul></li><li><strong>解决方案</strong>：<ol><li>使用UniApp提供的条件编译功能，针对不同平台编写样式：<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* #ifdef H5 */</span></span><br><span class="line"><span class="selector-class">.container</span> &#123; <span class="attribute">padding</span>: <span class="number">10px</span>; &#125;</span><br><span class="line"><span class="comment">/* #endif */</span></span><br><span class="line"><span class="comment">/* #ifdef MP-WEIXIN */</span></span><br><span class="line"><span class="selector-class">.container</span> &#123; <span class="attribute">padding</span>: <span class="number">20px</span>; &#125;</span><br><span class="line"><span class="comment">/* #endif */</span></span><br></pre></td></tr></table></figure></li><li>使用Flexbox或Grid布局，避免使用平台特定的样式。</li></ol></li></ul><h4 id="2-3-真机调试问题"><a href="#2-3-真机调试问题" class="headerlink" title="2.3 真机调试问题"></a><strong>2.3 真机调试问题</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>在真机上运行时，功能异常或无法调试。</li></ul></li><li><strong>原因</strong>：<ul><li>真机环境与开发环境存在差异。</li></ul></li><li><strong>解决方案</strong>：<ol><li>使用HBuilderX的真机调试功能，实时查看日志和错误信息。</li><li>确保真机与开发机在同一局域网下，并正确配置网络权限。</li></ol></li></ul><hr><h3 id="3-结合开发中的常见问题"><a href="#3-结合开发中的常见问题" class="headerlink" title="3. 结合开发中的常见问题"></a><strong>3. 结合开发中的常见问题</strong></h3><h4 id="3-1-数据格式不一致"><a href="#3-1-数据格式不一致" class="headerlink" title="3.1 数据格式不一致"></a><strong>3.1 数据格式不一致</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>QQ频道API返回的数据格式与UniApp前端预期不一致。</li></ul></li><li><strong>原因</strong>：<ul><li>未对API返回的数据进行格式化处理。</li></ul></li><li><strong>解决方案</strong>：<ol><li>在后端服务中对API返回的数据进行格式化：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">formatMessage</span> = (<span class="params">message</span>) =&gt; &#123;</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    <span class="attr">id</span>: message.<span class="property">id</span>,</span><br><span class="line">    <span class="attr">content</span>: message.<span class="property">content</span>,</span><br><span class="line">    <span class="attr">timestamp</span>: <span class="keyword">new</span> <span class="title class_">Date</span>(message.<span class="property">timestamp</span>).<span class="title function_">toLocaleString</span>()</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></li><li>在UniApp前端使用<code>computed</code>属性对数据进行处理：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">computed</span>: &#123;</span><br><span class="line">  <span class="title function_">formattedMessages</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">messages</span>.<span class="title function_">map</span>(<span class="function"><span class="params">msg</span> =&gt;</span> (&#123;</span><br><span class="line">      ...msg,</span><br><span class="line">      <span class="attr">timestamp</span>: <span class="keyword">new</span> <span class="title class_">Date</span>(msg.<span class="property">timestamp</span>).<span class="title function_">toLocaleString</span>()</span><br><span class="line">    &#125;));</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol></li></ul><h4 id="3-2-网络请求超时"><a href="#3-2-网络请求超时" class="headerlink" title="3.2 网络请求超时"></a><strong>3.2 网络请求超时</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>网络请求超时，导致功能异常。</li></ul></li><li><strong>原因</strong>：<ul><li>网络环境不稳定，或请求未设置超时时间。</li></ul></li><li><strong>解决方案</strong>：<ol><li>在UniApp中设置请求超时时间：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">uni.<span class="title function_">request</span>(&#123;</span><br><span class="line">  <span class="attr">url</span>: <span class="string">&#x27;https://your-server.com/api&#x27;</span>,</span><br><span class="line">  <span class="attr">timeout</span>: <span class="number">5000</span>, <span class="comment">// 设置超时时间为5秒</span></span><br><span class="line">  <span class="attr">success</span>: <span class="function">(<span class="params">res</span>) =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(res.<span class="property">data</span>)</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li><li>在后端服务中优化接口性能，减少响应时间。</li></ol></li></ul><hr><h3 id="4-总结"><a href="#4-总结" class="headerlink" title="4. 总结"></a><strong>4. 总结</strong></h3><p>在开发QQ频道机器人和UniApp应用时，权限问题、跨域问题、样式兼容性和网络请求是常见的踩坑点。通过本文提供的解决方案，你可以有效避免这些问题，提升开发效率和项目质量。</p><blockquote><p>如果你在开发过程中遇到其他问题，欢迎在评论区留言讨论！ 😊</p></blockquote>]]></content>
    
    
    <summary type="html">深入探讨uni-app中开发QQ机器人的最佳实践,包括基础封装、通信、跨端适配等常见问题内容,帮助开发者构建高质量的QQ频道机器人。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    <category term="QQ机器人" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/QQ%E6%9C%BA%E5%99%A8%E4%BA%BA/"/>
    
    <category term="QQ频道" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/QQ%E6%9C%BA%E5%99%A8%E4%BA%BA/QQ%E9%A2%91%E9%81%93/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="QQ频道" scheme="https://www.hzv5.cn/tags/QQ%E9%A2%91%E9%81%93/"/>
    
    <category term="QQ机器人" scheme="https://www.hzv5.cn/tags/QQ%E6%9C%BA%E5%99%A8%E4%BA%BA/"/>
    
  </entry>
  
  <entry>
    <title>UniApp中Canvas绘图不显示的常见问题与解决方案</title>
    <link href="https://www.hzv5.cn/2025/01/02/uniapp-canvas-not-show/"/>
    <id>https://www.hzv5.cn/2025/01/02/uniapp-canvas-not-show/</id>
    <published>2025-01-02T07:22:36.000Z</published>
    <updated>2025-01-02T07:22:36.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>在UniApp中使用Canvas绘图时，可能会遇到绘图内容不显示的问题。本文将总结这些常见问题的原因，并提供解决方案，帮助你快速定位和解决问题。</p></blockquote><span id="more"></span><hr><h3 id="1-Canvas绘图不显示的常见原因"><a href="#1-Canvas绘图不显示的常见原因" class="headerlink" title="1. Canvas绘图不显示的常见原因"></a><strong>1. Canvas绘图不显示的常见原因</strong></h3><h4 id="1-1-Canvas上下文未正确获取"><a href="#1-1-Canvas上下文未正确获取" class="headerlink" title="1.1 Canvas上下文未正确获取"></a><strong>1.1 Canvas上下文未正确获取</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>调用<code>uni.createCanvasContext</code>后，绘图操作未生效。</li></ul></li><li><strong>原因</strong>：<ul><li>未正确获取Canvas上下文，或未调用<code>ctx.draw()</code>方法。</li></ul></li><li><strong>解决方案</strong>：<ol><li>确保正确获取Canvas上下文：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> ctx = uni.<span class="title function_">createCanvasContext</span>(<span class="string">&#x27;myCanvas&#x27;</span>);</span><br></pre></td></tr></table></figure></li><li>在绘图操作后调用<code>ctx.draw()</code>：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ctx.<span class="title function_">fillRect</span>(<span class="number">10</span>, <span class="number">10</span>, <span class="number">100</span>, <span class="number">100</span>);</span><br><span class="line">ctx.<span class="title function_">draw</span>(); <span class="comment">// 必须调用draw方法才会生效</span></span><br></pre></td></tr></table></figure></li></ol></li></ul><h4 id="1-2-Canvas尺寸问题"><a href="#1-2-Canvas尺寸问题" class="headerlink" title="1.2 Canvas尺寸问题"></a><strong>1.2 Canvas尺寸问题</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>Canvas绘图内容显示不全或完全不可见。</li></ul></li><li><strong>原因</strong>：<ul><li>Canvas的宽度或高度设置不正确，或者未适配屏幕分辨率。</li></ul></li><li><strong>解决方案</strong>：<ol><li>在<code>&lt;canvas&gt;</code>标签中设置正确的宽度和高度：<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">canvas</span> <span class="attr">canvas-id</span>=<span class="string">&quot;myCanvas&quot;</span> <span class="attr">style</span>=<span class="string">&quot;width: 300px; height: 300px;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">canvas</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li>使用<code>uni.getSystemInfoSync</code>获取屏幕宽度并动态设置Canvas尺寸：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> systemInfo = uni.<span class="title function_">getSystemInfoSync</span>();</span><br><span class="line"><span class="keyword">const</span> canvasWidth = systemInfo.<span class="property">windowWidth</span>;</span><br><span class="line"><span class="keyword">const</span> canvasHeight = systemInfo.<span class="property">windowHeight</span>;</span><br></pre></td></tr></table></figure></li></ol></li></ul><h4 id="1-3-Canvas层级问题"><a href="#1-3-Canvas层级问题" class="headerlink" title="1.3 Canvas层级问题"></a><strong>1.3 Canvas层级问题</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>Canvas被其他组件遮挡，导致绘图内容不可见。</li></ul></li><li><strong>原因</strong>：<ul><li>Canvas的层级（z-index）较低，或被其他组件覆盖。</li></ul></li><li><strong>解决方案</strong>：<ol><li>使用<code>position: fixed</code>或<code>position: absolute</code>提升Canvas层级：<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">canvas</span> <span class="attr">canvas-id</span>=<span class="string">&quot;myCanvas&quot;</span> <span class="attr">style</span>=<span class="string">&quot;position: fixed; top: 0; left: 0;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">canvas</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li>避免在Canvas上方放置其他组件。</li></ol></li></ul><h4 id="1-4-Canvas渲染时机问题"><a href="#1-4-Canvas渲染时机问题" class="headerlink" title="1.4 Canvas渲染时机问题"></a><strong>1.4 Canvas渲染时机问题</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>在页面加载时绘图，但内容未显示。</li></ul></li><li><strong>原因</strong>：<ul><li>Canvas渲染时机过早，页面尚未完全加载。</li></ul></li><li><strong>解决方案</strong>：<ol><li>在<code>onReady</code>生命周期中执行绘图操作：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="title function_">onReady</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> ctx = uni.<span class="title function_">createCanvasContext</span>(<span class="string">&#x27;myCanvas&#x27;</span>);</span><br><span class="line">    ctx.<span class="title function_">fillRect</span>(<span class="number">10</span>, <span class="number">10</span>, <span class="number">100</span>, <span class="number">100</span>);</span><br><span class="line">    ctx.<span class="title function_">draw</span>();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></li><li>使用<code>setTimeout</code>延迟绘图操作：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> ctx = uni.<span class="title function_">createCanvasContext</span>(<span class="string">&#x27;myCanvas&#x27;</span>);</span><br><span class="line">  ctx.<span class="title function_">fillRect</span>(<span class="number">10</span>, <span class="number">10</span>, <span class="number">100</span>, <span class="number">100</span>);</span><br><span class="line">  ctx.<span class="title function_">draw</span>();</span><br><span class="line">&#125;, <span class="number">500</span>);</span><br></pre></td></tr></table></figure></li></ol></li></ul><hr><h3 id="2-其他常见问题"><a href="#2-其他常见问题" class="headerlink" title="2. 其他常见问题"></a><strong>2. 其他常见问题</strong></h3><h4 id="2-1-Canvas绘图性能问题"><a href="#2-1-Canvas绘图性能问题" class="headerlink" title="2.1 Canvas绘图性能问题"></a><strong>2.1 Canvas绘图性能问题</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>绘图操作卡顿或延迟。</li></ul></li><li><strong>原因</strong>：<ul><li>绘图操作过于频繁，或Canvas尺寸过大。</li></ul></li><li><strong>解决方案</strong>：<ol><li>减少不必要的绘图操作。</li><li>使用<code>ctx.draw(true)</code>开启离屏渲染，提升性能。</li></ol></li></ul><h4 id="2-2-Canvas绘图内容模糊"><a href="#2-2-Canvas绘图内容模糊" class="headerlink" title="2.2 Canvas绘图内容模糊"></a><strong>2.2 Canvas绘图内容模糊</strong></h4><ul><li><strong>问题描述</strong>：<ul><li>绘图内容显示模糊。</li></ul></li><li><strong>原因</strong>：<ul><li>Canvas的CSS尺寸与画布分辨率不匹配。</li></ul></li><li><strong>解决方案</strong>：<ol><li>使用<code>uni.getSystemInfoSync</code>获取设备像素比（<code>pixelRatio</code>），并设置Canvas的实际分辨率：<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> systemInfo = uni.<span class="title function_">getSystemInfoSync</span>();</span><br><span class="line"><span class="keyword">const</span> pixelRatio = systemInfo.<span class="property">pixelRatio</span>;</span><br><span class="line"><span class="keyword">const</span> canvasWidth = <span class="number">300</span> * pixelRatio;</span><br><span class="line"><span class="keyword">const</span> canvasHeight = <span class="number">300</span> * pixelRatio;</span><br></pre></td></tr></table></figure></li><li>在CSS中设置Canvas的显示尺寸为逻辑像素：<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">canvas</span> <span class="attr">canvas-id</span>=<span class="string">&quot;myCanvas&quot;</span> <span class="attr">style</span>=<span class="string">&quot;width: 300px; height: 300px;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">canvas</span>&gt;</span></span><br></pre></td></tr></table></figure></li></ol></li></ul><hr><h3 id="3-示例代码"><a href="#3-示例代码" class="headerlink" title="3. 示例代码"></a><strong>3. 示例代码</strong></h3><p>以下是一个完整的Canvas绘图示例，涵盖了上述问题的解决方案：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">view</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">canvas</span> <span class="attr">canvas-id</span>=<span class="string">&quot;myCanvas&quot;</span> <span class="attr">style</span>=<span class="string">&quot;width: 300px; height: 300px;&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">canvas</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">view</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="language-javascript">  <span class="title function_">onReady</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">this</span>.<span class="title function_">drawCanvas</span>();</span></span><br><span class="line"><span class="language-javascript">  &#125;,</span></span><br><span class="line"><span class="language-javascript">  <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">drawCanvas</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> systemInfo = uni.<span class="title function_">getSystemInfoSync</span>();</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> pixelRatio = systemInfo.<span class="property">pixelRatio</span>;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> canvasWidth = <span class="number">300</span> * pixelRatio;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> canvasHeight = <span class="number">300</span> * pixelRatio;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> ctx = uni.<span class="title function_">createCanvasContext</span>(<span class="string">&#x27;myCanvas&#x27;</span>);</span></span><br><span class="line"><span class="language-javascript">      ctx.<span class="title function_">fillRect</span>(<span class="number">10</span>, <span class="number">10</span>, <span class="number">100</span>, <span class="number">100</span>);</span></span><br><span class="line"><span class="language-javascript">      ctx.<span class="title function_">draw</span>();</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript">&#125;;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="language-css"></span></span><br><span class="line"><span class="language-css"><span class="selector-tag">canvas</span> &#123;</span></span><br><span class="line"><span class="language-css">  <span class="attribute">position</span>: fixed;</span></span><br><span class="line"><span class="language-css">  <span class="attribute">top</span>: <span class="number">0</span>;</span></span><br><span class="line"><span class="language-css">  <span class="attribute">left</span>: <span class="number">0</span>;</span></span><br><span class="line"><span class="language-css">&#125;</span></span><br><span class="line"><span class="language-css"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br></pre></td></tr></table></figure><hr><h3 id="4-总结"><a href="#4-总结" class="headerlink" title="4. 总结"></a><strong>4. 总结</strong></h3><p>在UniApp中使用Canvas绘图时，常见的问题包括上下文未正确获取、Canvas尺寸问题、层级问题和渲染时机问题。通过本文提供的解决方案，你可以快速定位并解决这些问题，确保Canvas绘图内容正常显示。</p><blockquote><p>希望这篇博客对你有帮助！如果有其他问题，欢迎随时交流！ 🚀</p></blockquote>]]></content>
    
    
    <summary type="html">深入探讨uni-app开发中canvas组件使用的最佳实践,包括基础组件封装、组件通信、绘图不显示的常见问题与解决方案等内容,帮助开发者构建高质量的UI组件库。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    <category term="canvas" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/canvas/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="组件开发" scheme="https://www.hzv5.cn/tags/%E7%BB%84%E4%BB%B6%E5%BC%80%E5%8F%91/"/>
    
    <category term="UI组件" scheme="https://www.hzv5.cn/tags/UI%E7%BB%84%E4%BB%B6/"/>
    
  </entry>
  
  <entry>
    <title>Hexo博客实现随机文章功能的完整教程</title>
    <link href="https://www.hzv5.cn/2025/01/01/hexo-random-post/"/>
    <id>https://www.hzv5.cn/2025/01/01/hexo-random-post/</id>
    <published>2025-01-01T14:55:12.000Z</published>
    <updated>2025-01-01T14:55:12.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>想要给博客增加一些趣味性？让读者可以随机浏览你的文章是个不错的选择。本文将详细介绍如何在Hexo博客中实现随机文章功能，就跟本博客的侧栏导航中的【<a href="/random" title="随机获取一篇博文 - 吖远zzy">手气</a>】菜单一样的效果。</p></blockquote><span id="more"></span><h2 id="1-功能介绍"><a href="#1-功能介绍" class="headerlink" title="1. 功能介绍"></a>1. 功能介绍</h2><p>随机文章功能可以让访问者随机浏览博客中的任意一篇文章,这不仅能增加博客的趣味性,还能提高文章的曝光率,让一些早期的优质文章也有机会被读者发现。</p><h2 id="2-实现步骤"><a href="#2-实现步骤" class="headerlink" title="2. 实现步骤"></a>2. 实现步骤</h2><h3 id="2-1-创建模板文件"><a href="#2-1-创建模板文件" class="headerlink" title="2.1 创建模板文件"></a>2.1 创建模板文件</h3><p>首先在主题的<code>layout</code>目录下创建<code>random.ejs</code>文件:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">&lt;%</span><br><span class="line">// 获取所有文章</span><br><span class="line">const posts = site.posts.data;</span><br><span class="line">// 随机选择一篇文章</span><br><span class="line">const randomPost = posts[Math.floor(Math.random() * posts.length)];</span><br><span class="line">%&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">// 立即重定向到随机文章</span><br><span class="line">window.location.href = &#x27;&lt;%- url_for(randomPost.path) %&gt;&#x27;;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;noscript&gt;</span><br><span class="line">  &lt;div style=&quot;text-align: center; padding: 20px;&quot;&gt;</span><br><span class="line">    &lt;p&gt;请点击下方链接访问随机文章：&lt;/p&gt;</span><br><span class="line">    &lt;a href=&quot;&lt;%- url_for(randomPost.path) %&gt;&quot;&gt;&lt;%- randomPost.title %&gt;&lt;/a&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/noscript&gt;</span><br></pre></td></tr></table></figure><h3 id="2-2-创建页面文件"><a href="#2-2-创建页面文件" class="headerlink" title="2.2 创建页面文件"></a>2.2 创建页面文件</h3><p>在<code>source</code>目录下创建<code>random</code>文件夹,并在其中创建<code>index.md</code>:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">title: 随机文章</span><br><span class="line">date: 2023-12-31 12:00:00</span><br><span class="line">type: random</span><br><span class="line">layout: random</span><br><span class="line"><span class="section">comments: false</span></span><br><span class="line"><span class="section">---</span></span><br></pre></td></tr></table></figure><h3 id="2-3-添加菜单项"><a href="#2-3-添加菜单项" class="headerlink" title="2.3 添加菜单项"></a>2.3 添加菜单项</h3><p>在主题的<code>_config.yml</code>中添加菜单项:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">menu:</span></span><br><span class="line">  <span class="attr">random:</span></span><br><span class="line">    <span class="attr">path:</span> <span class="string">/random</span></span><br><span class="line">    <span class="attr">text:</span> <span class="string">手气</span></span><br><span class="line">    <span class="attr">icon:</span> <span class="string">fas</span> <span class="string">fa-random</span></span><br></pre></td></tr></table></figure><h2 id="3-功能说明"><a href="#3-功能说明" class="headerlink" title="3. 功能说明"></a>3. 功能说明</h2><h3 id="3-1-工作原理"><a href="#3-1-工作原理" class="headerlink" title="3.1 工作原理"></a>3.1 工作原理</h3><ol><li>当访问者点击”随机文章”菜单时,会访问<code>/random</code>页面</li><li>模板会从所有文章中随机选择一篇</li><li>通过JavaScript自动跳转到选中的文章</li><li>如果浏览器禁用了JavaScript,则显示一个可点击的链接</li></ol><h3 id="3-2-优化建议"><a href="#3-2-优化建议" class="headerlink" title="3.2 优化建议"></a>3.2 优化建议</h3><ol><li><strong>性能优化</strong>: 如果博客文章很多,可以考虑缓存文章列表</li><li><strong>用户体验</strong>: 可以添加加载动画</li><li><strong>功能扩展</strong>: 可以按分类或标签随机</li></ol><h2 id="4-常见问题"><a href="#4-常见问题" class="headerlink" title="4. 常见问题"></a>4. 常见问题</h2><h3 id="4-1-页面闪烁"><a href="#4-1-页面闪烁" class="headerlink" title="4.1 页面闪烁"></a>4.1 页面闪烁</h3><p>如果出现页面闪烁,可以添加loading效果:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;style&gt;</span><br><span class="line">.loading &#123;</span><br><span class="line">  text-align: center;</span><br><span class="line">  padding: 20px;</span><br><span class="line">&#125;</span><br><span class="line">.loading:after &#123;</span><br><span class="line">  content: &#x27;正在随机选择文章...&#x27;;</span><br><span class="line">  color: #666;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br><span class="line">&lt;div class=&quot;loading&quot;&gt;&lt;/div&gt;</span><br></pre></td></tr></table></figure><h3 id="4-2-重复访问"><a href="#4-2-重复访问" class="headerlink" title="4.2 重复访问"></a>4.2 重复访问</h3><p>如果想避免连续访问同一篇文章,可以使用sessionStorage记录历史:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取历史记录</span></span><br><span class="line"><span class="keyword">const</span> history = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(<span class="variable language_">sessionStorage</span>.<span class="title function_">getItem</span>(<span class="string">&#x27;randomHistory&#x27;</span>) || <span class="string">&#x27;[]&#x27;</span>);</span><br><span class="line"><span class="comment">// 过滤已访问的文章</span></span><br><span class="line"><span class="keyword">const</span> availablePosts = posts.<span class="title function_">filter</span>(<span class="function"><span class="params">post</span> =&gt;</span> !history.<span class="title function_">includes</span>(post.<span class="property">path</span>));</span><br><span class="line"><span class="comment">// 如果所有文章都访问过,清空历史</span></span><br><span class="line"><span class="keyword">if</span> (availablePosts.<span class="property">length</span> === <span class="number">0</span>) &#123;</span><br><span class="line">  <span class="variable language_">sessionStorage</span>.<span class="title function_">removeItem</span>(<span class="string">&#x27;randomHistory&#x27;</span>);</span><br><span class="line">  availablePosts = posts;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 随机选择文章</span></span><br><span class="line"><span class="keyword">const</span> randomPost = availablePosts[<span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * availablePosts.<span class="property">length</span>)];</span><br><span class="line"><span class="comment">// 记录到历史</span></span><br><span class="line">history.<span class="title function_">push</span>(randomPost.<span class="property">path</span>);</span><br><span class="line"><span class="variable language_">sessionStorage</span>.<span class="title function_">setItem</span>(<span class="string">&#x27;randomHistory&#x27;</span>, <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(history));</span><br></pre></td></tr></table></figure><h2 id="5-总结"><a href="#5-总结" class="headerlink" title="5. 总结"></a>5. 总结</h2><p>随机文章功能虽然实现简单,但能大大提升博客的趣味性和用户体验。你还可以基于这个基础功能,添加更多个性化的扩展,比如按照文章热度随机、按照阅读时间随机等。</p><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">详细介绍如何在Hexo博客中实现随机文章功能,包括创建模板文件、配置路由、添加菜单项等完整步骤,帮助你的博客增添趣味性。</summary>
    
    
    
    <category term="Web开发" scheme="https://www.hzv5.cn/categories/Web%E5%BC%80%E5%8F%91/"/>
    
    <category term="Hexo" scheme="https://www.hzv5.cn/categories/Web%E5%BC%80%E5%8F%91/Hexo/"/>
    
    
    <category term="博客优化" scheme="https://www.hzv5.cn/tags/%E5%8D%9A%E5%AE%A2%E4%BC%98%E5%8C%96/"/>
    
    <category term="Hexo" scheme="https://www.hzv5.cn/tags/Hexo/"/>
    
    <category term="JavaScript" scheme="https://www.hzv5.cn/tags/JavaScript/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
  </entry>
  
  <entry>
    <title>QQ频道机器人Android客户端使用指南</title>
    <link href="https://www.hzv5.cn/2024/12/19/qqch-bot-readme/"/>
    <id>https://www.hzv5.cn/2024/12/19/qqch-bot-readme/</id>
    <published>2024-12-18T18:58:36.000Z</published>
    <updated>2024-12-19T09:11:06.114Z</updated>
    
    <content type="html"><![CDATA[<h1 id="QQ频道机器人-Android客户端"><a href="#QQ频道机器人-Android客户端" class="headerlink" title="QQ频道机器人 Android客户端"></a>QQ频道机器人 Android客户端</h1><p>一个用于管理和操作QQ频道机器人的Android客户端应用，基于uniapp开发，提供了直观的用户界面和丰富的功能特性。</p><h2 id="客户端界面预览"><a href="#客户端界面预览" class="headerlink" title="客户端界面预览"></a>客户端界面预览</h2><p><img src="/img/qqBot/login_chat.png" alt="登录频道聊天查看和发送消息"></p><p><img src="/img/qqBot/plugin_setting_log.png" alt="插件功能运行日志和设置"></p><h2 id="功能特性"><a href="#功能特性" class="headerlink" title="功能特性"></a>功能特性</h2><h3 id="1-账号管理"><a href="#1-账号管理" class="headerlink" title="1. 账号管理"></a>1. 账号管理</h3><ul><li>App ID和Token登录</li><li>记住登录状态</li><li>自动登录选项</li><li>沙盒/正式环境切换</li><li>多账号管理</li><li>账号安全保护</li></ul><h3 id="2-频道管理"><a href="#2-频道管理" class="headerlink" title="2. 频道管理"></a>2. 频道管理</h3><ul><li>频道列表显示<ul><li>分组展示</li><li>在线人数显示</li><li>频道类型图标</li><li>频道状态标识</li></ul></li><li>未读消息统计<ul><li>普通消息计数</li><li>@消息特别标记</li><li>按频道分类统计</li></ul></li><li>频道权限管理<ul><li>自动识别管理员权限</li><li>权限值实时计算</li><li>权限检查功能</li></ul></li></ul><h3 id="3-消息功能"><a href="#3-消息功能" class="headerlink" title="3. 消息功能"></a>3. 消息功能</h3><ul><li><p>实时消息接收</p><span id="more"></span><ul><li>WebSocket长连接</li><li>断线自动重连</li><li>心跳保活机制</li></ul></li><li><p>消息发送功能</p><ul><li>文本消息支持</li><li>消息审核处理</li><li>审核状态显示</li></ul></li><li><p>消息管理</p><ul><li>消息撤回</li><li>历史记录查看</li><li>系统消息显示</li><li>在线状态更新</li></ul></li><li><p>消息展示</p><ul><li>时间戳显示</li><li>用户身份标识</li><li>消息状态图标</li><li>长按菜单操作</li></ul></li></ul><h3 id="4-插件系统"><a href="#4-插件系统" class="headerlink" title="4. 插件系统"></a>4. 插件系统</h3><ul><li>插件管理<ul><li>启用/禁用控制</li><li>本地存储支持</li><li>配置项管理</li></ul></li><li>插件功能<ul><li>命令处理</li><li>数据持久化</li><li>日志记录</li><li>API调用</li></ul></li><li>内置插件<ul><li>每日签到</li><li>百度百科</li></ul></li><li>开发支持<ul><li>完整API文档</li><li>示例代码</li><li>开发指南</li></ul></li></ul><h3 id="5-通知系统"><a href="#5-通知系统" class="headerlink" title="5. 通知系统"></a>5. 通知系统</h3><ul><li>消息通知<ul><li>新消息提醒</li><li>@消息特殊提示</li><li>消息合并显示</li><li>通知延迟处理</li></ul></li><li>通知管理<ul><li>是否开启通知</li><li>是否震动提醒</li><li>是否系统通知</li><li>免打扰设置</li></ul></li><li>通知优化<ul><li>消息去重</li><li>批量处理</li><li>智能延迟</li><li>性能优化</li></ul></li></ul><h2 id="系统要求"><a href="#系统要求" class="headerlink" title="系统要求"></a>系统要求</h2><h3 id="基本要求"><a href="#基本要求" class="headerlink" title="基本要求"></a>基本要求</h3><ul><li>Android 5.0+</li><li>网络连接</li><li>存储空间 &gt;= 50MB</li><li>通知权限(可选)</li><li>后台运行权限(推荐)</li></ul><h3 id="权限说明"><a href="#权限说明" class="headerlink" title="权限说明"></a>权限说明</h3><ol><li><p>必需权限</p><ul><li>网络访问</li><li>存储读写</li><li>后台运行</li></ul></li><li><p>可选权限</p><ul><li>通知显示</li><li>开机自启</li><li>震动控制</li></ul></li></ol><h2 id="安装说明"><a href="#安装说明" class="headerlink" title="安装说明"></a>安装说明</h2><ol><li><p>下载安装</p><ul><li>从Release页面下载最新APK</li><li>允许安装未知来源应用</li><li>按提示完成安装</li></ul></li><li><p>首次配置</p><ul><li>授予必要权限</li><li>登录机器人账号</li><li>配置基本设置</li></ul></li></ol><h2 id="使用指南"><a href="#使用指南" class="headerlink" title="使用指南"></a>使用指南</h2><h3 id="1-登录配置"><a href="#1-登录配置" class="headerlink" title="1. 登录配置"></a>1. 登录配置</h3><h4 id="1-1-获取凭据"><a href="#1-1-获取凭据" class="headerlink" title="1.1 获取凭据"></a>1.1 获取凭据</h4><ol><li>访问<a href="https://q.qq.com">QQ机器人管理平台</a></li><li>创建/选择机器人</li><li>获取App ID和Token</li><li>确认机器人状态正常</li></ol><h4 id="1-2-登录设置"><a href="#1-2-登录设置" class="headerlink" title="1.2 登录设置"></a>1.2 登录设置</h4><ol><li>输入App ID和Token</li><li>选择环境(沙盒/正式)</li><li>设置自动登录(可选)</li><li>配置安全选项</li></ol><h3 id="2-频道操作"><a href="#2-频道操作" class="headerlink" title="2. 频道操作"></a>2. 频道操作</h3><h4 id="2-1-查看频道"><a href="#2-1-查看频道" class="headerlink" title="2.1 查看频道"></a>2.1 查看频道</h4><ol><li><p>打开频道列表</p><ul><li>点击顶部频道信息展开列表</li><li>查看分组和子频道</li><li>观察在线人数和状态</li></ul></li><li><p>频道分类</p><ul><li>文字频道(#)</li><li>语音频道(🔊)</li><li>直播频道(📺)</li><li>公告频道(📢)</li><li>应用频道(💬)</li><li>论坛频道(🎮)</li></ul></li><li><p>未读消息</p><ul><li>红点显示未读数</li><li>橙色标记@消息</li><li>点击清除未读</li></ul></li></ol><h4 id="2-2-消息管理"><a href="#2-2-消息管理" class="headerlink" title="2.2 消息管理"></a>2.2 消息管理</h4><ol><li><p>发送消息</p><ul><li>在输入框输入内容</li><li>点击发送按钮</li><li>等待发送状态</li><li>查看审核结果</li></ul></li><li><p>消息操作</p><ul><li>长按消息显示菜单</li><li>选择撤回等操作</li><li>查看消息详情</li></ul></li><li><p>消息状态</p><ul><li>正常消息</li><li>审核中(灰色)</li><li>审核拒绝(红色)</li><li>已撤回(灰色斜体)</li></ul></li></ol><h3 id="3-插件使用"><a href="#3-插件使用" class="headerlink" title="3. 插件使用"></a>3. 插件使用</h3><h4 id="3-1-插件管理"><a href="#3-1-插件管理" class="headerlink" title="3.1 插件管理"></a>3.1 插件管理</h4><ol><li><p>内置插件</p><ul><li>每日签到(/签到)</li><li>百度百科(/百科)</li></ul></li><li><p>插件控制</p><ul><li>启用/禁用插件</li><li>查看插件信息</li><li>管理插件数据</li></ul></li></ol><h4 id="3-2-插件命令"><a href="#3-2-插件命令" class="headerlink" title="3.2 插件命令"></a>3.2 插件命令</h4><ol><li><p>命令格式</p><ul><li>以/开头</li><li>严格匹配命令名</li><li>空格分隔参数</li></ul></li><li><p>使用示例</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">/签到              # 执行签到</span><br><span class="line">/百科 太阳         # 查询百科</span><br></pre></td></tr></table></figure></li></ol><h3 id="4-通知设置"><a href="#4-通知设置" class="headerlink" title="4. 通知设置"></a>4. 通知设置</h3><h4 id="4-1-通知选项"><a href="#4-1-通知选项" class="headerlink" title="4.1 通知选项"></a>4.1 通知选项</h4><ol><li><p>基本设置</p><ul><li>启用通知</li><li>震动提醒</li><li>系统通知</li></ul></li><li><p>通知规则</p><ul><li>新消息延迟2秒</li><li>多条消息合并</li><li>@消息立即提醒</li><li>非当前频道通知</li></ul></li></ol><h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><h3 id="1-连接问题"><a href="#1-连接问题" class="headerlink" title="1. 连接问题"></a>1. 连接问题</h3><ul><li>问题: 无法连接或频繁断开</li><li>解决: <ol><li>检查网络连接</li><li>确认Token正确</li><li>查看机器人状态</li><li>等待自动重连</li></ol></li></ul><h3 id="2-消息问题"><a href="#2-消息问题" class="headerlink" title="2. 消息问题"></a>2. 消息问题</h3><ul><li>问题: 消息发送失败</li><li>解决:<ol><li>检查频道权限</li><li>确认消息格式</li><li>等待审核通过</li><li>查看错误提示</li></ol></li></ul><h3 id="3-插件问题"><a href="#3-插件问题" class="headerlink" title="3. 插件问题"></a>3. 插件问题</h3><ul><li>问题: 插件无响应</li><li>解决:<ol><li>检查插件状态</li><li>确认命令格式</li><li>查看错误日志</li><li>重启应用</li></ol></li></ul><h3 id="4-通知问题"><a href="#4-通知问题" class="headerlink" title="4. 通知问题"></a>4. 通知问题</h3><ul><li>问题: 收不到通知</li><li>解决:<ol><li>检查通知权限</li><li>确认通知设置</li><li>关闭省电模式</li><li>允许后台运行</li></ol></li></ul><h2 id="更新日志"><a href="#更新日志" class="headerlink" title="更新日志"></a>更新日志</h2><h3 id="v1-1-0-2024-01-20"><a href="#v1-1-0-2024-01-20" class="headerlink" title="v1.1.0 (2024-01-20)"></a>v1.1.0 (2024-01-20)</h3><ul><li>优化WebSocket连接</li><li>改进消息处理逻辑</li><li>完善插件系统</li><li>优化通知机制</li><li>修复已知问题</li></ul><h3 id="v1-0-0-2023-12-25"><a href="#v1-0-0-2023-12-25" class="headerlink" title="v1.0.0 (2023-12-25)"></a>v1.0.0 (2023-12-25)</h3><ul><li>首次发布</li><li>基础功能实现</li><li>插件系统支持</li><li>通知系统集成</li></ul><h2 id="更多待补充"><a href="#更多待补充" class="headerlink" title="更多待补充"></a>更多待补充</h2><p>么么哒~~</p>]]></content>
    
    
    <summary type="html">&lt;h1 id=&quot;QQ频道机器人-Android客户端&quot;&gt;&lt;a href=&quot;#QQ频道机器人-Android客户端&quot; class=&quot;headerlink&quot; title=&quot;QQ频道机器人 Android客户端&quot;&gt;&lt;/a&gt;QQ频道机器人 Android客户端&lt;/h1&gt;&lt;p&gt;一个用于管理和操作QQ频道机器人的Android客户端应用，基于uniapp开发，提供了直观的用户界面和丰富的功能特性。&lt;/p&gt;
&lt;h2 id=&quot;客户端界面预览&quot;&gt;&lt;a href=&quot;#客户端界面预览&quot; class=&quot;headerlink&quot; title=&quot;客户端界面预览&quot;&gt;&lt;/a&gt;客户端界面预览&lt;/h2&gt;&lt;p&gt;&lt;img src=&quot;/img/qqBot/login_chat.png&quot; alt=&quot;登录频道聊天查看和发送消息&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/qqBot/plugin_setting_log.png&quot; alt=&quot;插件功能运行日志和设置&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;功能特性&quot;&gt;&lt;a href=&quot;#功能特性&quot; class=&quot;headerlink&quot; title=&quot;功能特性&quot;&gt;&lt;/a&gt;功能特性&lt;/h2&gt;&lt;h3 id=&quot;1-账号管理&quot;&gt;&lt;a href=&quot;#1-账号管理&quot; class=&quot;headerlink&quot; title=&quot;1. 账号管理&quot;&gt;&lt;/a&gt;1. 账号管理&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;App ID和Token登录&lt;/li&gt;
&lt;li&gt;记住登录状态&lt;/li&gt;
&lt;li&gt;自动登录选项&lt;/li&gt;
&lt;li&gt;沙盒/正式环境切换&lt;/li&gt;
&lt;li&gt;多账号管理&lt;/li&gt;
&lt;li&gt;账号安全保护&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-频道管理&quot;&gt;&lt;a href=&quot;#2-频道管理&quot; class=&quot;headerlink&quot; title=&quot;2. 频道管理&quot;&gt;&lt;/a&gt;2. 频道管理&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;频道列表显示&lt;ul&gt;
&lt;li&gt;分组展示&lt;/li&gt;
&lt;li&gt;在线人数显示&lt;/li&gt;
&lt;li&gt;频道类型图标&lt;/li&gt;
&lt;li&gt;频道状态标识&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;未读消息统计&lt;ul&gt;
&lt;li&gt;普通消息计数&lt;/li&gt;
&lt;li&gt;@消息特别标记&lt;/li&gt;
&lt;li&gt;按频道分类统计&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;频道权限管理&lt;ul&gt;
&lt;li&gt;自动识别管理员权限&lt;/li&gt;
&lt;li&gt;权限值实时计算&lt;/li&gt;
&lt;li&gt;权限检查功能&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-消息功能&quot;&gt;&lt;a href=&quot;#3-消息功能&quot; class=&quot;headerlink&quot; title=&quot;3. 消息功能&quot;&gt;&lt;/a&gt;3. 消息功能&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;p&gt;实时消息接收&lt;/p&gt;</summary>
    
    
    
    <category term="知识点" scheme="https://www.hzv5.cn/categories/%E7%9F%A5%E8%AF%86%E7%82%B9/"/>
    
    
    <category term="笔记" scheme="https://www.hzv5.cn/tags/%E7%AC%94%E8%AE%B0/"/>
    
    <category term="QQ" scheme="https://www.hzv5.cn/tags/QQ/"/>
    
    <category term="QQ频道" scheme="https://www.hzv5.cn/tags/QQ%E9%A2%91%E9%81%93/"/>
    
    <category term="QQ机器人" scheme="https://www.hzv5.cn/tags/QQ%E6%9C%BA%E5%99%A8%E4%BA%BA/"/>
    
    <category term="使用文档" scheme="https://www.hzv5.cn/tags/%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3/"/>
    
  </entry>
  
  <entry>
    <title>安卓版QQ频道机器人APP客户端插件开发指南</title>
    <link href="https://www.hzv5.cn/2024/12/19/qqch-bot-plugin/"/>
    <id>https://www.hzv5.cn/2024/12/19/qqch-bot-plugin/</id>
    <published>2024-12-18T17:50:56.000Z</published>
    <updated>2024-12-19T09:14:03.687Z</updated>
    
    <content type="html"><![CDATA[<p>本文档将指导您如何为QQ频道机器人客户端开发插件。</p><h2 id="插件结构"><a href="#插件结构" class="headerlink" title="插件结构"></a>插件结构</h2><p>每个插件都是一个标准的 JavaScript 文件，需要导出一个包含以下字段的对象:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 插件对象</span></span><br><span class="line"><span class="keyword">const</span> plugin = &#123;</span><br><span class="line">  <span class="comment">// 基本信息(必需)</span></span><br><span class="line">  <span class="attr">id</span>: <span class="string">&#x27;plugin-id&#x27;</span>,          <span class="comment">// 插件ID,只能包含小写字母、数字、下划线和横线</span></span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;插件名称&#x27;</span>,         <span class="comment">// 插件显示名称</span></span><br><span class="line">  <span class="attr">description</span>: <span class="string">&#x27;插件描述&#x27;</span>,  <span class="comment">// 插件功能描述</span></span><br><span class="line">  <span class="attr">command</span>: <span class="string">&#x27;/命令&#x27;</span>,         <span class="comment">// 触发命令,必须以/开头</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 基本信息(可选)</span></span><br><span class="line">  <span class="attr">version</span>: <span class="string">&#x27;1.0.0&#x27;</span>,        <span class="comment">// 插件版本号</span></span><br><span class="line">  <span class="attr">author</span>: <span class="string">&#x27;作者名称&#x27;</span>,      <span class="comment">// 插件作者</span></span><br><span class="line">  <span class="attr">enabled</span>: <span class="literal">true</span>,           <span class="comment">// 插件是否启用</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 配置项(可选)</span></span><br><span class="line">  <span class="attr">config</span>: &#123;</span><br><span class="line">    <span class="comment">// 插件的配置项</span></span><br><span class="line">    <span class="attr">minPoints</span>: <span class="number">10</span>,         <span class="comment">// 示例:最小积分</span></span><br><span class="line">    <span class="attr">maxPoints</span>: <span class="number">100</span>,        <span class="comment">// 示例:最大积分</span></span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 数据存储(可选)</span></span><br><span class="line">  <span class="attr">storage</span>: &#123;</span><br><span class="line">    <span class="comment">// 插件的数据存储</span></span><br><span class="line">    <span class="attr">records</span>: <span class="keyword">new</span> <span class="title class_">Map</span>()     <span class="comment">// 示例:记录存储</span></span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 消息处理函数(必需)</span></span><br><span class="line">  <span class="attr">handler</span>: <span class="title function_">async</span> (message, channel, context) =&gt; &#123;</span><br><span class="line">    <span class="comment">// 返回值:</span></span><br><span class="line">    <span class="comment">// - 字符串: 要发送的回复消息</span></span><br><span class="line">    <span class="comment">// - null/undefined: 不发送回复</span></span><br><span class="line">    <span class="comment">// - Promise&lt;string&gt;: 异步返回回复消息</span></span><br><span class="line">    <span class="keyword">return</span> <span class="string">&#x27;回复消息&#x27;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 导出插件</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = plugin</span><br></pre></td></tr></table></figure><h2 id="API-说明"><a href="#API-说明" class="headerlink" title="API 说明"></a>API 说明</h2><h3 id="1-消息对象-message"><a href="#1-消息对象-message" class="headerlink" title="1. 消息对象(message)"></a>1. 消息对象(message)</h3>  <span id="more"></span><p>消息对象包含了消息的完整信息：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">id</span>: <span class="string">&quot;消息ID&quot;</span>,</span><br><span class="line">  <span class="attr">channel_id</span>: <span class="string">&quot;频道ID&quot;</span>, </span><br><span class="line">  <span class="attr">guild_id</span>: <span class="string">&quot;服务器ID&quot;</span>,</span><br><span class="line">  <span class="attr">content</span>: <span class="string">&quot;消息内容&quot;</span>,</span><br><span class="line">  <span class="attr">cleanContent</span>: <span class="string">&quot;去除命令前缀的消息内容&quot;</span>, <span class="comment">// 新增:清理后的内容</span></span><br><span class="line">  <span class="attr">timestamp</span>: <span class="string">&quot;2023-01-01T00:00:00.000Z&quot;</span>,</span><br><span class="line">  <span class="attr">status</span>: <span class="string">&quot;normal&quot;</span>, <span class="comment">// 消息状态: normal-正常, auditing-审核中, rejected-审核拒绝</span></span><br><span class="line">  <span class="attr">author</span>: &#123;</span><br><span class="line">    <span class="attr">id</span>: <span class="string">&quot;用户ID&quot;</span>,</span><br><span class="line">    <span class="attr">username</span>: <span class="string">&quot;用户名&quot;</span>,</span><br><span class="line">    <span class="attr">bot</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">avatar</span>: <span class="string">&quot;头像URL&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">member</span>: &#123;</span><br><span class="line">    <span class="attr">roles</span>: [<span class="string">&quot;角色ID1&quot;</span>, <span class="string">&quot;角色ID2&quot;</span>],</span><br><span class="line">    <span class="attr">joined_at</span>: <span class="string">&quot;加入时间&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">mentions</span>: [</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">id</span>: <span class="string">&quot;被@用户ID&quot;</span>,</span><br><span class="line">      <span class="attr">username</span>: <span class="string">&quot;被@用户名&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">  ],</span><br><span class="line">  <span class="attr">mention_everyone</span>: <span class="literal">false</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="2-频道对象-channel"><a href="#2-频道对象-channel" class="headerlink" title="2. 频道对象(channel)"></a>2. 频道对象(channel)</h3><p>频道对象包含了频道的基本信息：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">id</span>: <span class="string">&quot;频道ID&quot;</span>,</span><br><span class="line">  <span class="attr">guild_id</span>: <span class="string">&quot;服务器ID&quot;</span>,</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&quot;频道名称&quot;</span>,</span><br><span class="line">  <span class="attr">type</span>: <span class="number">0</span>, <span class="comment">// 频道类型</span></span><br><span class="line">  <span class="attr">position</span>: <span class="number">1</span>, <span class="comment">// 显示位置</span></span><br><span class="line">  <span class="attr">parent_id</span>: <span class="string">&quot;父频道ID&quot;</span>,</span><br><span class="line">  <span class="attr">owner_id</span>: <span class="string">&quot;创建者ID&quot;</span>,</span><br><span class="line">  <span class="attr">permissions</span>: <span class="string">&quot;权限值&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3-上下文对象-context"><a href="#3-上下文对象-context" class="headerlink" title="3. 上下文对象(context)"></a>3. 上下文对象(context)</h3><p>上下文对象提供了插件运行时的环境和工具：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="comment">// 存储API - 持久化存储插件数据</span></span><br><span class="line">  <span class="attr">storage</span>: &#123;</span><br><span class="line">    <span class="attr">get</span>: <span class="function">(<span class="params">key</span>) =&gt;</span> value, <span class="comment">// 获取存储的值</span></span><br><span class="line">    <span class="attr">set</span>: <span class="function">(<span class="params">key, value</span>) =&gt;</span> <span class="keyword">void</span>, <span class="comment">// 设置存储的值</span></span><br><span class="line">    <span class="attr">delete</span>: <span class="function">(<span class="params">key</span>) =&gt;</span> <span class="keyword">void</span>, <span class="comment">// 删除存储的值</span></span><br><span class="line">    <span class="attr">clear</span>: <span class="function">() =&gt;</span> <span class="keyword">void</span>, <span class="comment">// 清空存储</span></span><br><span class="line">    <span class="attr">has</span>: <span class="function">(<span class="params">key</span>) =&gt;</span> boolean <span class="comment">// 检查键是否存在</span></span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 配置API - 管理插件配置</span></span><br><span class="line">  <span class="attr">config</span>: &#123;</span><br><span class="line">    <span class="attr">get</span>: <span class="function">(<span class="params">key</span>) =&gt;</span> value, <span class="comment">// 获取配置项</span></span><br><span class="line">    <span class="attr">set</span>: <span class="function">(<span class="params">key, value</span>) =&gt;</span> <span class="keyword">void</span>, <span class="comment">// 设置配置项</span></span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 日志API - 记录插件运行日志</span></span><br><span class="line">  <span class="attr">log</span>: &#123;</span><br><span class="line">    <span class="attr">info</span>: <span class="function">(<span class="params">message, details</span>) =&gt;</span> <span class="keyword">void</span>, <span class="comment">// 记录信息日志</span></span><br><span class="line">    <span class="attr">success</span>: <span class="function">(<span class="params">message, details</span>) =&gt;</span> <span class="keyword">void</span>, <span class="comment">// 记录成功日志</span></span><br><span class="line">    <span class="attr">warning</span>: <span class="function">(<span class="params">message, details</span>) =&gt;</span> <span class="keyword">void</span>, <span class="comment">// 记录警告日志</span></span><br><span class="line">    <span class="attr">error</span>: <span class="function">(<span class="params">message, details</span>) =&gt;</span> <span class="keyword">void</span> <span class="comment">// 记录错误日志</span></span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 工具API</span></span><br><span class="line">  <span class="attr">api</span>: &#123;</span><br><span class="line">    <span class="comment">// 发送消息</span></span><br><span class="line">    <span class="attr">sendMessage</span>: <span class="title function_">async</span> (channelId, content, options) =&gt; &#123;</span><br><span class="line">      <span class="comment">// channelId: 频道ID</span></span><br><span class="line">      <span class="comment">// content: 消息内容</span></span><br><span class="line">      <span class="comment">// options: 可选参数</span></span><br><span class="line">      <span class="comment">//   - msg_id: 回复的消息ID</span></span><br><span class="line">      <span class="comment">//   - event_id: 事件ID</span></span><br><span class="line">      <span class="comment">// 返回:</span></span><br><span class="line">      <span class="comment">// - 成功: messageObject</span></span><br><span class="line">      <span class="comment">// - 审核: &#123; code: 304023, data: &#123; message_audit: &#123; audit_id: &quot;xxx&quot; &#125; &#125; &#125;</span></span><br><span class="line">      <span class="keyword">return</span> response</span><br><span class="line">    &#125;,</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 删除消息</span></span><br><span class="line">    <span class="attr">deleteMessage</span>: <span class="title function_">async</span> (channelId, messageId) =&gt; &#123;</span><br><span class="line">      <span class="comment">// channelId: 频道ID</span></span><br><span class="line">      <span class="comment">// messageId: 消息ID</span></span><br><span class="line">      <span class="keyword">return</span> boolean</span><br><span class="line">    &#125;,</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 获取成员信息</span></span><br><span class="line">    <span class="attr">getMember</span>: <span class="title function_">async</span> (guildId, userId) =&gt; &#123;</span><br><span class="line">      <span class="comment">// guildId: 服务器ID</span></span><br><span class="line">      <span class="comment">// userId: 用户ID</span></span><br><span class="line">      <span class="keyword">return</span> memberObject</span><br><span class="line">    &#125;,</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 获取服务器角色列表</span></span><br><span class="line">    <span class="attr">getGuildRoles</span>: <span class="title function_">async</span> (guildId) =&gt; &#123;</span><br><span class="line">      <span class="comment">// guildId: 服务器ID</span></span><br><span class="line">      <span class="keyword">return</span> rolesArray</span><br><span class="line">    &#125;,</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 检查权限</span></span><br><span class="line">    <span class="attr">hasPermission</span>: <span class="function">(<span class="params">permissions, permission</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">// permissions: 权限值</span></span><br><span class="line">      <span class="comment">// permission: 要检查的权限</span></span><br><span class="line">      <span class="keyword">return</span> boolean</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="插件功能界面预览"><a href="#插件功能界面预览" class="headerlink" title="插件功能界面预览"></a>插件功能界面预览</h2><p><img src="/img/qqBot/log.jpg" alt="插件功能界面"></p><h2 id="消息处理流程"><a href="#消息处理流程" class="headerlink" title="消息处理流程"></a>消息处理流程</h2><ol><li><p>消息接收</p><ul><li>系统接收到新消息时，会检查消息内容是否以配置的命令前缀开始</li><li>解析出命令和参数</li><li>查找所有匹配的已启用插件</li></ul></li><li><p>插件执行</p><ul><li>对每个匹配的插件：<ul><li>创建独立的插件上下文对象</li><li>调用插件的handler函数</li><li>等待处理结果</li></ul></li><li>多个插件可以使用相同的命令</li><li>插件按照加载顺序依次执行</li><li>某个插件执行失败不会影响其他插件</li></ul></li><li><p>响应处理</p><ul><li>每个插件的handler如果返回字符串，系统会自动发送响应消息</li><li>每个响应都是独立的，会分别发送到频道</li><li>发送的消息可能进入审核状态(code: 304023)</li><li>审核通过或拒绝会触发相应的事件</li></ul></li></ol><h2 id="权限处理"><a href="#权限处理" class="headerlink" title="权限处理"></a>权限处理</h2><p>系统会自动计算机器人的权限：</p><ol><li><p>管理员权限</p><ul><li>频道主</li><li>管理员</li><li>超级管理员</li><li>子频道管理员<br>拥有以上角色时自动获得所有权限(1099511627775)</li></ul></li><li><p>普通权限</p><ul><li>根据角色的permissions值按位计算</li><li>多个角色的权限值进行按位或运算</li><li>可以使用api.hasPermission检查特定权限</li></ul></li></ol><h2 id="最佳实践"><a href="#最佳实践" class="headerlink" title="最佳实践"></a>最佳实践</h2><ol><li><p>错误处理</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">handler</span>: <span class="title function_">async</span> (message, channel, context) =&gt; &#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="comment">// 处理逻辑</span></span><br><span class="line">    context.<span class="property">log</span>.<span class="title function_">info</span>(<span class="string">&#x27;处理成功&#x27;</span>, &#123; <span class="attr">messageId</span>: message.<span class="property">id</span> &#125;)</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&#x27;成功消息&#x27;</span></span><br><span class="line">  &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">    context.<span class="property">log</span>.<span class="title function_">error</span>(<span class="string">&#x27;处理失败&#x27;</span>, &#123; error, <span class="attr">messageId</span>: message.<span class="property">id</span> &#125;)</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&#x27;处理失败，请稍后重试&#x27;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>数据持久化</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用storage API保存数据</span></span><br><span class="line"><span class="keyword">const</span> records = context.<span class="property">storage</span>.<span class="title function_">get</span>(<span class="string">&#x27;records&#x27;</span>) || &#123;&#125;</span><br><span class="line">records[userId] = &#123; <span class="comment">/* 数据 */</span> &#125;</span><br><span class="line">context.<span class="property">storage</span>.<span class="title function_">set</span>(<span class="string">&#x27;records&#x27;</span>, records)</span><br></pre></td></tr></table></figure></li><li><p>消息审核处理</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> response = <span class="keyword">await</span> context.<span class="property">api</span>.<span class="title function_">sendMessage</span>(channelId, content)</span><br><span class="line"><span class="keyword">if</span> (response.<span class="property">code</span> === <span class="number">304023</span>) &#123;</span><br><span class="line">  context.<span class="property">log</span>.<span class="title function_">info</span>(<span class="string">&#x27;消息进入审核&#x27;</span>, &#123;</span><br><span class="line">    <span class="attr">auditId</span>: response.<span class="property">data</span>.<span class="property">message_audit</span>.<span class="property">audit_id</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>权限检查</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (!context.<span class="property">api</span>.<span class="title function_">hasPermission</span>(channel.<span class="property">permissions</span>, <span class="string">&#x27;MANAGE_MESSAGES&#x27;</span>)) &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="string">&#x27;权限不足，需要管理消息的权限&#x27;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><p>么么扎~~</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;本文档将指导您如何为QQ频道机器人客户端开发插件。&lt;/p&gt;
&lt;h2 id=&quot;插件结构&quot;&gt;&lt;a href=&quot;#插件结构&quot; class=&quot;headerlink&quot; title=&quot;插件结构&quot;&gt;&lt;/a&gt;插件结构&lt;/h2&gt;&lt;p&gt;每个插件都是一个标准的 JavaScript 文件，需要导出一个包含以下字段的对象:&lt;/p&gt;
&lt;figure class=&quot;highlight javascript&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;7&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;8&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;9&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;10&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;11&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;12&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;13&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;14&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;15&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;16&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;17&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;18&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;19&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;20&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;21&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;22&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;23&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;24&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;25&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;26&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;27&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;28&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;29&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;30&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;31&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;32&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;33&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;34&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;35&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;36&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;37&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;38&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// 插件对象&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; plugin = &amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;// 基本信息(必需)&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;attr&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&amp;#x27;plugin-id&amp;#x27;&lt;/span&gt;,          &lt;span class=&quot;comment&quot;&gt;// 插件ID,只能包含小写字母、数字、下划线和横线&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&amp;#x27;插件名称&amp;#x27;&lt;/span&gt;,         &lt;span class=&quot;comment&quot;&gt;// 插件显示名称&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;attr&quot;&gt;description&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&amp;#x27;插件描述&amp;#x27;&lt;/span&gt;,  &lt;span class=&quot;comment&quot;&gt;// 插件功能描述&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;attr&quot;&gt;command&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&amp;#x27;/命令&amp;#x27;&lt;/span&gt;,         &lt;span class=&quot;comment&quot;&gt;// 触发命令,必须以/开头&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;// 基本信息(可选)&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;attr&quot;&gt;version&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&amp;#x27;1.0.0&amp;#x27;&lt;/span&gt;,        &lt;span class=&quot;comment&quot;&gt;// 插件版本号&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;attr&quot;&gt;author&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&amp;#x27;作者名称&amp;#x27;&lt;/span&gt;,      &lt;span class=&quot;comment&quot;&gt;// 插件作者&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;attr&quot;&gt;enabled&lt;/span&gt;: &lt;span class=&quot;literal&quot;&gt;true&lt;/span&gt;,           &lt;span class=&quot;comment&quot;&gt;// 插件是否启用&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;// 配置项(可选)&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;attr&quot;&gt;config&lt;/span&gt;: &amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;// 插件的配置项&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;attr&quot;&gt;minPoints&lt;/span&gt;: &lt;span class=&quot;number&quot;&gt;10&lt;/span&gt;,         &lt;span class=&quot;comment&quot;&gt;// 示例:最小积分&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;attr&quot;&gt;maxPoints&lt;/span&gt;: &lt;span class=&quot;number&quot;&gt;100&lt;/span&gt;,        &lt;span class=&quot;comment&quot;&gt;// 示例:最大积分&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &amp;#125;,&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;// 数据存储(可选)&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;attr&quot;&gt;storage&lt;/span&gt;: &amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;// 插件的数据存储&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;attr&quot;&gt;records&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;title class_&quot;&gt;Map&lt;/span&gt;()     &lt;span class=&quot;comment&quot;&gt;// 示例:记录存储&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &amp;#125;,&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;// 消息处理函数(必需)&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;attr&quot;&gt;handler&lt;/span&gt;: &lt;span class=&quot;title function_&quot;&gt;async&lt;/span&gt; (message, channel, context) =&amp;gt; &amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;// 返回值:&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;// - 字符串: 要发送的回复消息&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;// - null/undefined: 不发送回复&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;// - Promise&amp;lt;string&amp;gt;: 异步返回回复消息&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;#x27;回复消息&amp;#x27;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &amp;#125;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// 导出插件&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;variable language_&quot;&gt;module&lt;/span&gt;.&lt;span class=&quot;property&quot;&gt;exports&lt;/span&gt; = plugin&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;

&lt;h2 id=&quot;API-说明&quot;&gt;&lt;a href=&quot;#API-说明&quot; class=&quot;headerlink&quot; title=&quot;API 说明&quot;&gt;&lt;/a&gt;API 说明&lt;/h2&gt;&lt;h3 id=&quot;1-消息对象-message&quot;&gt;&lt;a href=&quot;#1-消息对象-message&quot; class=&quot;headerlink&quot; title=&quot;1. 消息对象(message)&quot;&gt;&lt;/a&gt;1. 消息对象(message)&lt;/h3&gt;</summary>
    
    
    
    <category term="知识点" scheme="https://www.hzv5.cn/categories/%E7%9F%A5%E8%AF%86%E7%82%B9/"/>
    
    
    <category term="笔记" scheme="https://www.hzv5.cn/tags/%E7%AC%94%E8%AE%B0/"/>
    
    <category term="QQ" scheme="https://www.hzv5.cn/tags/QQ/"/>
    
    <category term="QQ频道" scheme="https://www.hzv5.cn/tags/QQ%E9%A2%91%E9%81%93/"/>
    
    <category term="QQ机器人" scheme="https://www.hzv5.cn/tags/QQ%E6%9C%BA%E5%99%A8%E4%BA%BA/"/>
    
    <category term="开发文档" scheme="https://www.hzv5.cn/tags/%E5%BC%80%E5%8F%91%E6%96%87%E6%A1%A3/"/>
    
  </entry>
  
  <entry>
    <title>2024年AI编程助手深度评测：哪款最适合你？</title>
    <link href="https://www.hzv5.cn/2024/10/15/ai-coding-assistants/"/>
    <id>https://www.hzv5.cn/2024/10/15/ai-coding-assistants/</id>
    <published>2024-10-15T06:30:00.000Z</published>
    <updated>2024-10-15T06:30:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>随着AI技术的快速发展，各种AI编程助手层出不穷。本文将深入对比主流AI编程助手的优缺点，帮助你找到最适合自己的AI编程伙伴。</p></blockquote><span id="more"></span><h2 id="1-Cursor-专注高效的AI编程助手"><a href="#1-Cursor-专注高效的AI编程助手" class="headerlink" title="1. Cursor - 专注高效的AI编程助手"></a>1. Cursor - 专注高效的AI编程助手</h2><h3 id="1-1-主要特点"><a href="#1-1-主要特点" class="headerlink" title="1.1 主要特点"></a>1.1 主要特点</h3><ul><li>基于先进的AI模型</li><li>完整的IDE功能</li><li>强大的代码补全和生成能力</li><li>支持多种编程语言</li><li>实时代码分析和建议</li></ul><h3 id="1-2-优点"><a href="#1-2-优点" class="headerlink" title="1.2 优点"></a>1.2 优点</h3><ol><li><p><strong>代码理解能力强</strong></p><ul><li>能准确理解项目上下文</li><li>提供精准的代码建议</li><li>支持复杂代码重构</li></ul></li><li><p><strong>交互体验优秀</strong></p><ul><li>界面简洁直观</li><li>响应速度快</li><li>支持自然语言交互</li></ul></li><li><p><strong>功能完整性</strong></p><ul><li>集成Git版本控制</li><li>支持代码调试</li><li>内置终端功能</li></ul></li></ol><h3 id="1-3-缺点"><a href="#1-3-缺点" class="headerlink" title="1.3 缺点"></a>1.3 缺点</h3><ol><li><p><strong>资源占用较高</strong></p><ul><li>运行需要较好的硬件配置</li><li>启动速度较慢</li></ul></li><li><p><strong>收费较高</strong></p><ul><li>完整功能需要付费订阅</li><li>价格对个人开发者略高</li></ul></li></ol><h2 id="2-CodeGeeX-国产优秀AI编程助手"><a href="#2-CodeGeeX-国产优秀AI编程助手" class="headerlink" title="2. CodeGeeX - 国产优秀AI编程助手"></a>2. CodeGeeX - 国产优秀AI编程助手</h2><h3 id="2-1-主要特点"><a href="#2-1-主要特点" class="headerlink" title="2.1 主要特点"></a>2.1 主要特点</h3><ul><li>支持中文交互</li><li>离线运行能力</li><li>跨平台支持</li><li>多种编辑器插件</li></ul><h3 id="2-2-优点"><a href="#2-2-优点" class="headerlink" title="2.2 优点"></a>2.2 优点</h3><ol><li><p><strong>本地化优势</strong></p><ul><li>完善的中文支持</li><li>符合国内开发习惯</li><li>响应速度快</li></ul></li><li><p><strong>性价比高</strong></p><ul><li>基础功能免费</li><li>企业版价格合理</li><li>教育优惠政策</li></ul></li><li><p><strong>安全性好</strong></p><ul><li>支持私有部署</li><li>代码不出境</li><li>数据安全有保障</li></ul></li></ol><h3 id="2-3-缺点"><a href="#2-3-缺点" class="headerlink" title="2.3 缺点"></a>2.3 缺点</h3><ol><li><p><strong>功能完整度</strong></p><ul><li>部分高级功能不如国外产品</li><li>IDE集成度有待提高</li></ul></li><li><p><strong>模型能力</strong></p><ul><li>在某些专业领域理解不够深入</li><li>代码生成质量略低于顶级产品</li></ul></li></ol><h2 id="3-GitHub-Copilot-最受欢迎的AI助手"><a href="#3-GitHub-Copilot-最受欢迎的AI助手" class="headerlink" title="3. GitHub Copilot - 最受欢迎的AI助手"></a>3. GitHub Copilot - 最受欢迎的AI助手</h2><h3 id="3-1-主要特点"><a href="#3-1-主要特点" class="headerlink" title="3.1 主要特点"></a>3.1 主要特点</h3><ul><li>微软和GitHub联合开发</li><li>基于OpenAI技术</li><li>支持主流编辑器</li><li>强大的代码生成能力</li></ul><h3 id="3-2-优点"><a href="#3-2-优点" class="headerlink" title="3.2 优点"></a>3.2 优点</h3><ol><li><p><strong>代码质量高</strong></p><ul><li>基于海量GitHub代码训练</li><li>生成代码可读性好</li><li>注释详细准确</li></ul></li><li><p><strong>集成度高</strong></p><ul><li>支持VS Code等主流IDE</li><li>操作便捷</li><li>学习成本低</li></ul></li><li><p><strong>更新频繁</strong></p><ul><li>持续改进和优化</li><li>Bug修复及时</li><li>新功能不断</li></ul></li></ol><h3 id="3-3-缺点"><a href="#3-3-缺点" class="headerlink" title="3.3 缺点"></a>3.3 缺点</h3><ol><li><p><strong>价格较贵</strong></p><ul><li>月付费用较高</li><li>没有永久授权选项</li></ul></li><li><p><strong>网络依赖</strong></p><ul><li>需要稳定的网络连接</li><li>无法离线使用</li></ul></li></ol><h2 id="4-国内其他AI编程助手"><a href="#4-国内其他AI编程助手" class="headerlink" title="4. 国内其他AI编程助手"></a>4. 国内其他AI编程助手</h2><h3 id="4-1-MarsCode-抖音官方AI编程助手"><a href="#4-1-MarsCode-抖音官方AI编程助手" class="headerlink" title="4.1 MarsCode - 抖音官方AI编程助手"></a>4.1 MarsCode - 抖音官方AI编程助手</h3><p><strong>主要特点：</strong></p><ul><li>字节跳动官方出品</li><li>基于先进的CodeFuse大模型</li><li>支持VSCode、JetBrains等主流IDE</li><li>提供Web版在线使用</li><li>完全免费使用</li></ul><p><strong>优点：</strong></p><ol><li><p><strong>强大的代码生成能力</strong></p><ul><li>基于海量字节跳动内部代码训练</li><li>支持40+种主流编程语言</li><li>代码质量和可用性较高</li><li>支持完整函数和类的生成</li></ul></li><li><p><strong>智能交互体验</strong></p><ul><li>支持自然语言对话</li><li>提供代码解释和优化建议</li><li>实时代码补全</li><li>多轮对话上下文理解</li></ul></li><li><p><strong>便捷的使用方式</strong></p><ul><li>完全免费，无需付费</li><li>支持Web端直接使用</li><li>IDE插件集成便捷</li><li>快速的响应速度</li></ul></li><li><p><strong>中文支持优秀</strong></p><ul><li>完善的中文交互</li><li>准确的中文需求理解</li><li>详细的中文注释生成</li><li>符合国内开发习惯</li></ul></li></ol><p><strong>缺点：</strong></p><ol><li><p><strong>功能限制</strong></p><ul><li>部分高级功能尚未开放</li><li>代码分析深度有限</li><li>重构功能相对基础</li></ul></li><li><p><strong>生态体系</strong></p><ul><li>插件数量较少</li><li>社区资源不够丰富</li><li>文档和教程较少</li></ul></li><li><p><strong>使用限制</strong></p><ul><li>需要抖音账号登录</li><li>可能有API调用限制</li><li>暂不支持私有部署</li></ul></li><li><p><strong>稳定性待提升</strong></p><ul><li>服务偶有波动</li><li>代码生成质量不够稳定</li><li>复杂场景支持有限</li></ul></li></ol><h3 id="4-2-百度智能编程助手"><a href="#4-2-百度智能编程助手" class="headerlink" title="4.2 百度智能编程助手"></a>4.2 百度智能编程助手</h3><p><strong>优点：</strong></p><ul><li>中文支持好</li><li>与百度生态集成</li><li>免费额度大</li></ul><p><strong>缺点：</strong></p><ul><li>功能相对简单</li><li>仅支持部分语言</li><li>社区活跃度低</li></ul><h3 id="4-3-阿里云代码智能助手"><a href="#4-3-阿里云代码智能助手" class="headerlink" title="4.3 阿里云代码智能助手"></a>4.3 阿里云代码智能助手</h3><p><strong>优点：</strong></p><ul><li>阿里云生态集成</li><li>企业级支持</li><li>安全性高</li></ul><p><strong>缺点：</strong></p><ul><li>需要阿里云账号</li><li>收费较高</li><li>通用性不足</li></ul><h2 id="5-选择建议"><a href="#5-选择建议" class="headerlink" title="5. 选择建议"></a>5. 选择建议</h2><h3 id="5-1-不同场景的选择建议"><a href="#5-1-不同场景的选择建议" class="headerlink" title="5.1 不同场景的选择建议"></a>5.1 不同场景的选择建议</h3><ol><li><p><strong>个人开发者</strong></p><ul><li>预算充足：Cursor或GitHub Copilot</li><li>预算有限：CodeGeeX</li><li>中文环境：CodeGeeX或百度智能编程助手</li></ul></li><li><p><strong>企业用户</strong></p><ul><li>注重安全：CodeGeeX企业版</li><li>团队协作：GitHub Copilot商业版</li><li>云生态：阿里云代码智能助手</li></ul></li><li><p><strong>学生用户</strong></p><ul><li>GitHub Copilot（有教育优惠）</li><li>CodeGeeX（免费版够用）</li></ul></li></ol><h3 id="5-2-选择考虑因素"><a href="#5-2-选择考虑因素" class="headerlink" title="5.2 选择考虑因素"></a>5.2 选择考虑因素</h3><ol><li><p><strong>预算</strong></p><ul><li>免费使用需求</li><li>性价比考虑</li><li>长期订阅成本</li></ul></li><li><p><strong>使用场景</strong></p><ul><li>个人/团队使用</li><li>项目规模</li><li>编程语言支持</li></ul></li><li><p><strong>特殊需求</strong></p><ul><li>中文支持</li><li>离线使用</li><li>安全合规</li></ul></li></ol><h2 id="6-使用技巧分享"><a href="#6-使用技巧分享" class="headerlink" title="6. 使用技巧分享"></a>6. 使用技巧分享</h2><h3 id="6-1-提高AI助手效率的技巧"><a href="#6-1-提高AI助手效率的技巧" class="headerlink" title="6.1 提高AI助手效率的技巧"></a>6.1 提高AI助手效率的技巧</h3><ol><li><p><strong>编写清晰的提示</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 好的提示示例</span></span><br><span class="line"><span class="comment">// 实现一个基于Promise的延迟函数，支持取消操作</span></span><br></pre></td></tr></table></figure></li><li><p><strong>善用上下文</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 先说明需求背景</span></span><br><span class="line"><span class="comment">// 再描述具体功能</span></span><br><span class="line"><span class="comment">// 最后指出关键点</span></span><br></pre></td></tr></table></figure></li><li><p><strong>结合文档使用</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 查看官方文档</span></span><br><span class="line"><span class="comment">// 参考示例代码</span></span><br><span class="line"><span class="comment">// 理解实现原理</span></span><br></pre></td></tr></table></figure></li></ol><h3 id="6-2-避免常见误区"><a href="#6-2-避免常见误区" class="headerlink" title="6.2 避免常见误区"></a>6.2 避免常见误区</h3><ol><li><p><strong>过度依赖</strong></p><ul><li>不要完全依赖AI生成代码</li><li>保持代码审查习惯</li><li>理解代码逻辑</li></ul></li><li><p><strong>忽视性能</strong></p><ul><li>注意代码质量</li><li>考虑性能影响</li><li>测试生成代码</li></ul></li></ol><h2 id="7-未来展望"><a href="#7-未来展望" class="headerlink" title="7. 未来展望"></a>7. 未来展望</h2><ol><li><p><strong>技术趋势</strong></p><ul><li>模型能力持续提升</li><li>多模态交互增强</li><li>个性化推荐加强</li></ul></li><li><p><strong>行业影响</strong></p><ul><li>提高开发效率</li><li>降低入门门槛</li><li>改变开发模式</li></ul></li><li><p><strong>注意事项</strong></p><ul><li>保持学习能力</li><li>提高代码素养</li><li>关注安全合规</li></ul></li></ol><h2 id="8-总结"><a href="#8-总结" class="headerlink" title="8. 总结"></a>8. 总结</h2><ol><li>选择合适的AI编程助手很重要</li><li>根据实际需求和场景选择</li><li>合理使用提高开发效率</li><li>避免过度依赖</li><li>持续关注新技术发展</li></ol><h2 id="5-产品对比分析"><a href="#5-产品对比分析" class="headerlink" title="5. 产品对比分析"></a>5. 产品对比分析</h2><h3 id="5-1-功能对比"><a href="#5-1-功能对比" class="headerlink" title="5.1 功能对比"></a>5.1 功能对比</h3><table><thead><tr><th>功能特性</th><th>Cursor</th><th>GitHub Copilot</th><th>CodeGeeX</th><th>MarsCode</th></tr></thead><tbody><tr><td>代码补全</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td></tr><tr><td>代码生成</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td></tr><tr><td>中文支持</td><td>⭐⭐⭐</td><td>⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td></tr><tr><td>IDE集成</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td><td>⭐⭐⭐</td></tr><tr><td>响应速度</td><td>⭐⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td></tr><tr><td>代码质量</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td><td>⭐⭐⭐⭐</td></tr></tbody></table><h3 id="5-2-价格对比"><a href="#5-2-价格对比" class="headerlink" title="5.2 价格对比"></a>5.2 价格对比</h3><table><thead><tr><th>产品</th><th>免费版</th><th>个人版</th><th>团队版</th><th>企业版</th></tr></thead><tbody><tr><td>Cursor</td><td>基础功能</td><td>$20/月</td><td>$40/人/月</td><td>联系商务</td></tr><tr><td>GitHub Copilot</td><td>无</td><td>$10/月</td><td>$19/人/月</td><td>联系商务</td></tr><tr><td>CodeGeeX</td><td>完整功能</td><td>免费</td><td>¥299/人/年</td><td>联系商务</td></tr><tr><td>MarsCode</td><td>完整功能</td><td>免费</td><td>免费</td><td>免费</td></tr></tbody></table><h3 id="5-3-适用场景对比"><a href="#5-3-适用场景对比" class="headerlink" title="5.3 适用场景对比"></a>5.3 适用场景对比</h3><ol><li><p><strong>个人开发者</strong></p><ul><li>预算充足：GitHub Copilot &gt; Cursor</li><li>预算有限：MarsCode &gt; CodeGeeX</li><li>中文环境：MarsCode = CodeGeeX &gt; 其他</li></ul></li><li><p><strong>团队使用</strong></p><ul><li>大型企业：GitHub Copilot &gt; Cursor &gt; CodeGeeX</li><li>中小企业：CodeGeeX &gt; MarsCode &gt; 其他</li><li>创业团队：MarsCode &gt; CodeGeeX &gt; 其他</li></ul></li><li><p><strong>特定需求</strong></p><ul><li>离线使用：CodeGeeX &gt; 其他</li><li>私有部署：CodeGeeX &gt; GitHub Copilot</li><li>中文支持：MarsCode = CodeGeeX &gt; 其他</li></ul></li></ol><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">深度评测2024年主流AI编程助手，包括Cursor、CodeGeeX等国内外知名工具，从多个维度对比分析各自优缺点，帮助开发者选择最适合的AI编程助手。</summary>
    
    
    
    <category term="技术评测" scheme="https://www.hzv5.cn/categories/%E6%8A%80%E6%9C%AF%E8%AF%84%E6%B5%8B/"/>
    
    <category term="AI工具" scheme="https://www.hzv5.cn/categories/%E6%8A%80%E6%9C%AF%E8%AF%84%E6%B5%8B/AI%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="AI编程" scheme="https://www.hzv5.cn/tags/AI%E7%BC%96%E7%A8%8B/"/>
    
    <category term="开发工具" scheme="https://www.hzv5.cn/tags/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/"/>
    
    <category term="Cursor" scheme="https://www.hzv5.cn/tags/Cursor/"/>
    
    <category term="CodeGeeX" scheme="https://www.hzv5.cn/tags/CodeGeeX/"/>
    
    <category term="编程助手" scheme="https://www.hzv5.cn/tags/%E7%BC%96%E7%A8%8B%E5%8A%A9%E6%89%8B/"/>
    
  </entry>
  
  <entry>
    <title>uni-app地图定位踩坑记：地图功能和定位的那些坑</title>
    <link href="https://www.hzv5.cn/2024/06/25/uniapp-map-location/"/>
    <id>https://www.hzv5.cn/2024/06/25/uniapp-map-location/</id>
    <published>2024-06-25T03:40:00.000Z</published>
    <updated>2024-06-25T03:40:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>在uni-app开发中，地图和定位功能经常会遇到各种问题。本文总结了一些常见的坑和解决方案，帮助大家更好地实现地图相关功能。</p></blockquote><span id="more"></span><h2 id="1-定位权限问题"><a href="#1-定位权限问题" class="headerlink" title="1. 定位权限问题"></a>1. 定位权限问题</h2><h3 id="1-1-获取定位权限"><a href="#1-1-获取定位权限" class="headerlink" title="1.1 获取定位权限"></a>1.1 获取定位权限</h3><p><strong>问题描述：</strong><br>用户拒绝定位权限后，无法正常使用定位功能。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 检查定位权限</span></span><br><span class="line"><span class="keyword">async</span> <span class="title function_">checkLocationAuth</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> res = <span class="keyword">await</span> uni.<span class="title function_">getSetting</span>()</span><br><span class="line">    <span class="keyword">if</span> (!res.<span class="property">authSetting</span>[<span class="string">&#x27;scope.userLocation&#x27;</span>]) &#123;</span><br><span class="line">      <span class="comment">// 未授权，引导用户开启</span></span><br><span class="line">      <span class="keyword">await</span> uni.<span class="title function_">showModal</span>(&#123;</span><br><span class="line">        <span class="attr">title</span>: <span class="string">&#x27;提示&#x27;</span>,</span><br><span class="line">        <span class="attr">content</span>: <span class="string">&#x27;需要获取您的位置信息，是否授权？&#x27;</span>,</span><br><span class="line">        <span class="attr">success</span>: <span class="title function_">async</span> (res) =&gt; &#123;</span><br><span class="line">          <span class="keyword">if</span> (res.<span class="property">confirm</span>) &#123;</span><br><span class="line">            <span class="keyword">await</span> uni.<span class="title function_">openSetting</span>()</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> res.<span class="property">authSetting</span>[<span class="string">&#x27;scope.userLocation&#x27;</span>]</span><br><span class="line">  &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;获取权限失败：&#x27;</span>, e)</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="1-2-定位失败处理"><a href="#1-2-定位失败处理" class="headerlink" title="1.2 定位失败处理"></a>1.2 定位失败处理</h3><p><strong>问题描述：</strong><br>定位失败时没有合适的提示和处理。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取位置信息</span></span><br><span class="line"><span class="keyword">async</span> <span class="title function_">getLocation</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> auth = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">checkLocationAuth</span>()</span><br><span class="line">    <span class="keyword">if</span> (!auth) &#123;</span><br><span class="line">      uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">        <span class="attr">title</span>: <span class="string">&#x27;请先开启定位权限&#x27;</span>,</span><br><span class="line">        <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span></span><br><span class="line">      &#125;)</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">const</span> location = <span class="keyword">await</span> uni.<span class="title function_">getLocation</span>(&#123;</span><br><span class="line">      <span class="attr">type</span>: <span class="string">&#x27;gcj02&#x27;</span>, <span class="comment">// gcj02火星坐标系</span></span><br><span class="line">      <span class="attr">isHighAccuracy</span>: <span class="literal">true</span>, <span class="comment">// 开启高精度定位</span></span><br><span class="line">      <span class="attr">highAccuracyExpireTime</span>: <span class="number">3000</span> <span class="comment">// 超时时间</span></span><br><span class="line">    &#125;)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> location</span><br><span class="line">  &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">    <span class="keyword">let</span> message = <span class="string">&#x27;定位失败&#x27;</span></span><br><span class="line">    <span class="keyword">switch</span> (e.<span class="property">errMsg</span>) &#123;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;getLocation:fail system permission denied&#x27;</span>:</span><br><span class="line">        message = <span class="string">&#x27;系统定位权限已关闭&#x27;</span></span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;getLocation:fail timeout&#x27;</span>:</span><br><span class="line">        message = <span class="string">&#x27;定位超时，请重试&#x27;</span></span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">      <span class="attr">default</span>:</span><br><span class="line">        message = <span class="string">&#x27;定位失败，请检查网络&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">      <span class="attr">title</span>: message,</span><br><span class="line">      <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span></span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="2-地图显示问题"><a href="#2-地图显示问题" class="headerlink" title="2. 地图显示问题"></a>2. 地图显示问题</h2><h3 id="2-1-地图加载失败"><a href="#2-1-地图加载失败" class="headerlink" title="2.1 地图加载失败"></a>2.1 地图加载失败</h3><p><strong>问题描述：</strong><br>地图组件加载失败或显示空白。</p><p><strong>解决方案：</strong></p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 地图组件使用 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">view</span> <span class="attr">class</span>=<span class="string">&quot;map-container&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">map</span></span></span><br><span class="line"><span class="tag">      <span class="attr">id</span>=<span class="string">&quot;map&quot;</span></span></span><br><span class="line"><span class="tag">      <span class="attr">:style</span>=<span class="string">&quot;mapStyle&quot;</span></span></span><br><span class="line"><span class="tag">      <span class="attr">:latitude</span>=<span class="string">&quot;latitude&quot;</span></span></span><br><span class="line"><span class="tag">      <span class="attr">:longitude</span>=<span class="string">&quot;longitude&quot;</span></span></span><br><span class="line"><span class="tag">      <span class="attr">:markers</span>=<span class="string">&quot;markers&quot;</span></span></span><br><span class="line"><span class="tag">      <span class="attr">:scale</span>=<span class="string">&quot;scale&quot;</span></span></span><br><span class="line"><span class="tag">      @<span class="attr">regionchange</span>=<span class="string">&quot;onRegionChange&quot;</span></span></span><br><span class="line"><span class="tag">      @<span class="attr">markertap</span>=<span class="string">&quot;onMarkerTap&quot;</span></span></span><br><span class="line"><span class="tag">      <span class="attr">:show-location</span>=<span class="string">&quot;true&quot;</span></span></span><br><span class="line"><span class="tag">    &gt;</span><span class="tag">&lt;/<span class="name">map</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">view</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="language-javascript">  <span class="title function_">data</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">mapStyle</span>: <span class="string">&#x27;width: 100%; height: 300px;&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">latitude</span>: <span class="number">0</span>,</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">longitude</span>: <span class="number">0</span>,</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">markers</span>: [],</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">scale</span>: <span class="number">16</span></span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">  &#125;,</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">async</span> <span class="title function_">onReady</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="comment">// 等待地图组件创建完成</span></span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">this</span>.<span class="property">mapContext</span> = uni.<span class="title function_">createMapContext</span>(<span class="string">&#x27;map&#x27;</span>, <span class="variable language_">this</span>)</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">initMap</span>()</span></span><br><span class="line"><span class="language-javascript">  &#125;,</span></span><br><span class="line"><span class="language-javascript">  <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">async</span> <span class="title function_">initMap</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">try</span> &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">const</span> location = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">getLocation</span>()</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">if</span> (location) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="variable language_">this</span>.<span class="property">latitude</span> = location.<span class="property">latitude</span></span></span><br><span class="line"><span class="language-javascript">          <span class="variable language_">this</span>.<span class="property">longitude</span> = location.<span class="property">longitude</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// 添加当前位置标记</span></span></span><br><span class="line"><span class="language-javascript">          <span class="variable language_">this</span>.<span class="title function_">addMarker</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">id</span>: <span class="number">0</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">latitude</span>: location.<span class="property">latitude</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">longitude</span>: location.<span class="property">longitude</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">title</span>: <span class="string">&#x27;当前位置&#x27;</span></span></span><br><span class="line"><span class="language-javascript">          &#125;)</span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">      &#125; <span class="keyword">catch</span> (e) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;初始化地图失败：&#x27;</span>, e)</span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript">&#125;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="2-2-标记点显示问题"><a href="#2-2-标记点显示问题" class="headerlink" title="2.2 标记点显示问题"></a>2.2 标记点显示问题</h3><p><strong>问题描述：</strong><br>自定义标记点样式不生效或显示异常。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 添加自定义标记</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">addMarker</span>(<span class="params">point</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> marker = &#123;</span><br><span class="line">    <span class="attr">id</span>: point.<span class="property">id</span>,</span><br><span class="line">    <span class="attr">latitude</span>: point.<span class="property">latitude</span>,</span><br><span class="line">    <span class="attr">longitude</span>: point.<span class="property">longitude</span>,</span><br><span class="line">    <span class="attr">title</span>: point.<span class="property">title</span>,</span><br><span class="line">    <span class="attr">width</span>: <span class="number">32</span>,</span><br><span class="line">    <span class="attr">height</span>: <span class="number">32</span>,</span><br><span class="line">    <span class="attr">callout</span>: &#123;</span><br><span class="line">      <span class="attr">content</span>: point.<span class="property">title</span>,</span><br><span class="line">      <span class="attr">color</span>: <span class="string">&#x27;#ffffff&#x27;</span>,</span><br><span class="line">      <span class="attr">fontSize</span>: <span class="number">14</span>,</span><br><span class="line">      <span class="attr">borderRadius</span>: <span class="number">4</span>,</span><br><span class="line">      <span class="attr">bgColor</span>: <span class="string">&#x27;#1989fa&#x27;</span>,</span><br><span class="line">      <span class="attr">padding</span>: <span class="number">8</span>,</span><br><span class="line">      <span class="attr">display</span>: <span class="string">&#x27;ALWAYS&#x27;</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">// 自定义图标</span></span><br><span class="line">    <span class="attr">iconPath</span>: point.<span class="property">iconPath</span> || <span class="string">&#x27;/static/images/marker.png&#x27;</span>,</span><br><span class="line">    <span class="comment">// 自定义气泡</span></span><br><span class="line">    <span class="attr">customCallout</span>: &#123;</span><br><span class="line">      <span class="attr">display</span>: <span class="string">&#x27;ALWAYS&#x27;</span>,</span><br><span class="line">      <span class="attr">anchorY</span>: <span class="number">0</span>,</span><br><span class="line">      <span class="attr">anchorX</span>: <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">markers</span>.<span class="title function_">push</span>(marker)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="3-路线规划问题"><a href="#3-路线规划问题" class="headerlink" title="3. 路线规划问题"></a>3. 路线规划问题</h2><h3 id="3-1-路线绘制错误"><a href="#3-1-路线绘制错误" class="headerlink" title="3.1 路线绘制错误"></a>3.1 路线绘制错误</h3><p><strong>问题描述：</strong><br>路线规划时绘制的路线不准确或无法显示。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 规划路线</span></span><br><span class="line"><span class="keyword">async</span> <span class="title function_">planRoute</span>(<span class="params">start, end</span>) &#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="comment">// 清除旧路线</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">polyline</span> = []</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 获取路线规划</span></span><br><span class="line">    <span class="keyword">const</span> route = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">getRoutePoints</span>(start, end)</span><br><span class="line">    <span class="keyword">if</span> (!route) <span class="keyword">return</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 绘制路线</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">polyline</span> = [&#123;</span><br><span class="line">      <span class="attr">points</span>: route,</span><br><span class="line">      <span class="attr">color</span>: <span class="string">&#x27;#1989fa&#x27;</span>,</span><br><span class="line">      <span class="attr">width</span>: <span class="number">4</span>,</span><br><span class="line">      <span class="attr">arrowLine</span>: <span class="literal">true</span>,</span><br><span class="line">      <span class="attr">borderColor</span>: <span class="string">&#x27;#ffffff&#x27;</span>,</span><br><span class="line">      <span class="attr">borderWidth</span>: <span class="number">2</span></span><br><span class="line">    &#125;]</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 调整视野以显示整条路线</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">mapContext</span>.<span class="title function_">includePoints</span>(&#123;</span><br><span class="line">      <span class="attr">points</span>: [start, end],</span><br><span class="line">      <span class="attr">padding</span>: [<span class="number">50</span>, <span class="number">50</span>, <span class="number">50</span>, <span class="number">50</span>]</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;规划路线失败：&#x27;</span>, e)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3-2-导航问题"><a href="#3-2-导航问题" class="headerlink" title="3.2 导航问题"></a>3.2 导航问题</h3><p><strong>问题描述：</strong><br>调用导航功能时出现兼容性问题。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 打开导航</span></span><br><span class="line"><span class="keyword">async</span> <span class="title function_">openNavigation</span>(<span class="params">destination</span>) &#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="comment">// 检查平台</span></span><br><span class="line">    <span class="comment">// #ifdef APP-PLUS</span></span><br><span class="line">    <span class="comment">// APP端使用系统导航</span></span><br><span class="line">    plus.<span class="property">runtime</span>.<span class="title function_">openURL</span>(</span><br><span class="line">      <span class="string">`androidamap://navi?sourceApplication=appname&amp;lat=<span class="subst">$&#123;destination.latitude&#125;</span>&amp;lon=<span class="subst">$&#123;destination.longitude&#125;</span>&amp;dev=0&amp;style=2`</span></span><br><span class="line">    )</span><br><span class="line">    <span class="comment">// #endif</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// #ifdef H5</span></span><br><span class="line">    <span class="comment">// H5端使用Web导航</span></span><br><span class="line">    <span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">href</span> = <span class="string">`https://uri.amap.com/navigation?to=<span class="subst">$&#123;destination.longitude&#125;</span>,<span class="subst">$&#123;destination.latitude&#125;</span>&amp;mode=car&amp;policy=1`</span></span><br><span class="line">    <span class="comment">// #endif</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// #ifdef MP-WEIXIN</span></span><br><span class="line">    <span class="comment">// 小程序端使用微信导航</span></span><br><span class="line">    uni.<span class="title function_">openLocation</span>(&#123;</span><br><span class="line">      <span class="attr">latitude</span>: destination.<span class="property">latitude</span>,</span><br><span class="line">      <span class="attr">longitude</span>: destination.<span class="property">longitude</span>,</span><br><span class="line">      <span class="attr">name</span>: destination.<span class="property">name</span>,</span><br><span class="line">      <span class="attr">address</span>: destination.<span class="property">address</span></span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="comment">// #endif</span></span><br><span class="line">  &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">    uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">      <span class="attr">title</span>: <span class="string">&#x27;打开导航失败&#x27;</span>,</span><br><span class="line">      <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span></span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="4-性能优化问题"><a href="#4-性能优化问题" class="headerlink" title="4. 性能优化问题"></a>4. 性能优化问题</h2><h3 id="4-1-标记点过多"><a href="#4-1-标记点过多" class="headerlink" title="4.1 标记点过多"></a>4.1 标记点过多</h3><p><strong>问题描述：</strong><br>地图上标记点太多导致卡顿。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 聚合标记点</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">clusterMarkers</span>(<span class="params">markers, distance = <span class="number">20</span></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> clusters = []</span><br><span class="line">  <span class="keyword">const</span> used = <span class="keyword">new</span> <span class="title class_">Set</span>()</span><br><span class="line">  </span><br><span class="line">  markers.<span class="title function_">forEach</span>(<span class="function">(<span class="params">marker, index</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (used.<span class="title function_">has</span>(index)) <span class="keyword">return</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">const</span> cluster = &#123;</span><br><span class="line">      <span class="attr">center</span>: &#123;</span><br><span class="line">        <span class="attr">latitude</span>: marker.<span class="property">latitude</span>,</span><br><span class="line">        <span class="attr">longitude</span>: marker.<span class="property">longitude</span></span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">points</span>: [marker]</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 查找附近的点</span></span><br><span class="line">    markers.<span class="title function_">forEach</span>(<span class="function">(<span class="params">m, i</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (i === index || used.<span class="title function_">has</span>(i)) <span class="keyword">return</span></span><br><span class="line">      </span><br><span class="line">      <span class="keyword">const</span> d = <span class="variable language_">this</span>.<span class="title function_">calculateDistance</span>(</span><br><span class="line">        marker.<span class="property">latitude</span>,</span><br><span class="line">        marker.<span class="property">longitude</span>,</span><br><span class="line">        m.<span class="property">latitude</span>,</span><br><span class="line">        m.<span class="property">longitude</span></span><br><span class="line">      )</span><br><span class="line">      </span><br><span class="line">      <span class="keyword">if</span> (d &lt;= distance) &#123;</span><br><span class="line">        cluster.<span class="property">points</span>.<span class="title function_">push</span>(m)</span><br><span class="line">        used.<span class="title function_">add</span>(i)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    </span><br><span class="line">    clusters.<span class="title function_">push</span>(cluster)</span><br><span class="line">  &#125;)</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> clusters</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="4-2-频繁更新"><a href="#4-2-频繁更新" class="headerlink" title="4.2 频繁更新"></a>4.2 频繁更新</h3><p><strong>问题描述：</strong><br>频繁更新标记点位置导致性能问题。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用节流更新位置</span></span><br><span class="line"><span class="keyword">const</span> throttleUpdate = <span class="title function_">throttle</span>(<span class="keyword">function</span>(<span class="params">markers</span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">markers</span> = markers</span><br><span class="line">&#125;, <span class="number">200</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 更新标记位置</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">updateMarkers</span>(<span class="params">newMarkers</span>) &#123;</span><br><span class="line">  <span class="title function_">throttleUpdate</span>(newMarkers)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 节流函数</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">throttle</span>(<span class="params">fn, delay</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> timer = <span class="literal">null</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">function</span>(<span class="params">...args</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (timer) <span class="keyword">return</span></span><br><span class="line">    timer = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">      fn.<span class="title function_">apply</span>(<span class="variable language_">this</span>, args)</span><br><span class="line">      timer = <span class="literal">null</span></span><br><span class="line">    &#125;, delay)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="5-实用功能分享"><a href="#5-实用功能分享" class="headerlink" title="5. 实用功能分享"></a>5. 实用功能分享</h2><h3 id="5-1-计算距离"><a href="#5-1-计算距离" class="headerlink" title="5.1 计算距离"></a>5.1 计算距离</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 计算两点距离</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">calculateDistance</span>(<span class="params">lat1, lng1, lat2, lng2</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> R = <span class="number">6371</span> <span class="comment">// 地球半径，单位km</span></span><br><span class="line">  <span class="keyword">const</span> dLat = (lat2 - lat1) * <span class="title class_">Math</span>.<span class="property">PI</span> / <span class="number">180</span></span><br><span class="line">  <span class="keyword">const</span> dLng = (lng2 - lng1) * <span class="title class_">Math</span>.<span class="property">PI</span> / <span class="number">180</span></span><br><span class="line">  </span><br><span class="line">  <span class="keyword">const</span> a = <span class="title class_">Math</span>.<span class="title function_">sin</span>(dLat/<span class="number">2</span>) * <span class="title class_">Math</span>.<span class="title function_">sin</span>(dLat/<span class="number">2</span>) +</span><br><span class="line">    <span class="title class_">Math</span>.<span class="title function_">cos</span>(lat1 * <span class="title class_">Math</span>.<span class="property">PI</span> / <span class="number">180</span>) * <span class="title class_">Math</span>.<span class="title function_">cos</span>(lat2 * <span class="title class_">Math</span>.<span class="property">PI</span> / <span class="number">180</span>) *</span><br><span class="line">    <span class="title class_">Math</span>.<span class="title function_">sin</span>(dLng/<span class="number">2</span>) * <span class="title class_">Math</span>.<span class="title function_">sin</span>(dLng/<span class="number">2</span>)</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">const</span> c = <span class="number">2</span> * <span class="title class_">Math</span>.<span class="title function_">atan2</span>(<span class="title class_">Math</span>.<span class="title function_">sqrt</span>(a), <span class="title class_">Math</span>.<span class="title function_">sqrt</span>(<span class="number">1</span>-a))</span><br><span class="line">  <span class="keyword">return</span> R * c</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="5-2-地址解析"><a href="#5-2-地址解析" class="headerlink" title="5.2 地址解析"></a>5.2 地址解析</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 地址转坐标</span></span><br><span class="line"><span class="keyword">async</span> <span class="title function_">geocode</span>(<span class="params">address</span>) &#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> res = <span class="keyword">await</span> uni.<span class="title function_">request</span>(&#123;</span><br><span class="line">      <span class="attr">url</span>: <span class="string">&#x27;geocode-api-url&#x27;</span>,</span><br><span class="line">      <span class="attr">data</span>: &#123;</span><br><span class="line">        <span class="attr">address</span>: address,</span><br><span class="line">        <span class="attr">key</span>: <span class="string">&#x27;your-api-key&#x27;</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (res.<span class="property">data</span>.<span class="property">status</span> === <span class="string">&#x27;1&#x27;</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="attr">latitude</span>: res.<span class="property">data</span>.<span class="property">result</span>.<span class="property">location</span>.<span class="property">lat</span>,</span><br><span class="line">        <span class="attr">longitude</span>: res.<span class="property">data</span>.<span class="property">result</span>.<span class="property">location</span>.<span class="property">lng</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;地址解析失败：&#x27;</span>, e)</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="6-最佳实践建议"><a href="#6-最佳实践建议" class="headerlink" title="6. 最佳实践建议"></a>6. 最佳实践建议</h2><ol><li>注意权限处理</li><li>做好错误提示</li><li>优化性能表现</li><li>处理兼容问题</li><li>注意用户体验</li></ol><h2 id="7-总结"><a href="#7-总结" class="headerlink" title="7. 总结"></a>7. 总结</h2><ol><li>权限问题要提前处理</li><li>地图显示要做好兼容</li><li>路线规划要考虑性能</li><li>导航功能要适配平台</li><li>注意优化用户体验</li></ol><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">详细介绍uni-app中地图功能和定位服务的常见问题及解决方案，包括权限处理、地图标记、路线规划等实用功能，适合新手阅读。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="地图功能" scheme="https://www.hzv5.cn/tags/%E5%9C%B0%E5%9B%BE%E5%8A%9F%E8%83%BD/"/>
    
    <category term="定位服务" scheme="https://www.hzv5.cn/tags/%E5%AE%9A%E4%BD%8D%E6%9C%8D%E5%8A%A1/"/>
    
  </entry>
  
  <entry>
    <title>uni-app文件上传踩坑记：图片处理和上传全攻略</title>
    <link href="https://www.hzv5.cn/2024/06/01/uniapp-file-upload/"/>
    <id>https://www.hzv5.cn/2024/06/01/uniapp-file-upload/</id>
    <published>2024-06-01T07:20:00.000Z</published>
    <updated>2024-06-01T07:20:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>在uni-app开发中，文件上传和图片处理是很常见的需求，但也经常会遇到各种问题。本文总结了一些常见问题和解决方案，希望能帮助大家更好地处理文件上传相关的需求。</p></blockquote><span id="more"></span><h2 id="1-图片选择问题"><a href="#1-图片选择问题" class="headerlink" title="1. 图片选择问题"></a>1. 图片选择问题</h2><h3 id="1-1-图片选择数量限制"><a href="#1-1-图片选择数量限制" class="headerlink" title="1.1 图片选择数量限制"></a>1.1 图片选择数量限制</h3><p><strong>问题描述：</strong><br>选择图片时没有限制数量，导致用户可能选择太多图片。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 限制选择数量和大小</span></span><br><span class="line"><span class="keyword">async</span> <span class="title function_">chooseImages</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> res = <span class="keyword">await</span> uni.<span class="title function_">chooseImage</span>(&#123;</span><br><span class="line">      <span class="attr">count</span>: <span class="number">9</span>, <span class="comment">// 最多选择9张</span></span><br><span class="line">      <span class="attr">sizeType</span>: [<span class="string">&#x27;original&#x27;</span>, <span class="string">&#x27;compressed&#x27;</span>], <span class="comment">// 原图和压缩图都可以</span></span><br><span class="line">      <span class="attr">sourceType</span>: [<span class="string">&#x27;album&#x27;</span>, <span class="string">&#x27;camera&#x27;</span>] <span class="comment">// 相册和相机都可以</span></span><br><span class="line">    &#125;)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 检查文件大小</span></span><br><span class="line">    <span class="keyword">const</span> maxSize = <span class="number">5</span> * <span class="number">1024</span> * <span class="number">1024</span> <span class="comment">// 5MB</span></span><br><span class="line">    <span class="keyword">const</span> overSizeFiles = res.<span class="property">tempFiles</span>.<span class="title function_">filter</span>(<span class="function"><span class="params">file</span> =&gt;</span> file.<span class="property">size</span> &gt; maxSize)</span><br><span class="line">    <span class="keyword">if</span> (overSizeFiles.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">      uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">        <span class="attr">title</span>: <span class="string">&#x27;图片大小不能超过5MB&#x27;</span>,</span><br><span class="line">        <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span></span><br><span class="line">      &#125;)</span><br><span class="line">      <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">handleUpload</span>(res.<span class="property">tempFilePaths</span>)</span><br><span class="line">  &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;选择图片失败：&#x27;</span>, e)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="1-2-图片格式限制"><a href="#1-2-图片格式限制" class="headerlink" title="1.2 图片格式限制"></a>1.2 图片格式限制</h3><p><strong>问题描述：</strong><br>用户上传了不支持的图片格式。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 检查图片格式</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">checkImageType</span>(<span class="params">filePath</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> allowTypes = [<span class="string">&#x27;jpg&#x27;</span>, <span class="string">&#x27;jpeg&#x27;</span>, <span class="string">&#x27;png&#x27;</span>, <span class="string">&#x27;gif&#x27;</span>]</span><br><span class="line">  <span class="keyword">const</span> extension = filePath.<span class="title function_">split</span>(<span class="string">&#x27;.&#x27;</span>).<span class="title function_">pop</span>().<span class="title function_">toLowerCase</span>()</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">if</span> (!allowTypes.<span class="title function_">includes</span>(extension)) &#123;</span><br><span class="line">    uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">      <span class="attr">title</span>: <span class="string">&#x27;只支持jpg、png、gif格式&#x27;</span>,</span><br><span class="line">      <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span></span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="2-图片压缩问题"><a href="#2-图片压缩问题" class="headerlink" title="2. 图片压缩问题"></a>2. 图片压缩问题</h2><h3 id="2-1-上传前压缩"><a href="#2-1-上传前压缩" class="headerlink" title="2.1 上传前压缩"></a>2.1 上传前压缩</h3><p><strong>问题描述：</strong><br>图片太大导致上传慢，浪费流量。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 压缩图片</span></span><br><span class="line"><span class="keyword">async</span> <span class="title function_">compressImage</span>(<span class="params">tempFilePath</span>) &#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> res = <span class="keyword">await</span> uni.<span class="title function_">compressImage</span>(&#123;</span><br><span class="line">      <span class="attr">src</span>: tempFilePath,</span><br><span class="line">      <span class="attr">quality</span>: <span class="number">80</span> <span class="comment">// 压缩质量0-100</span></span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">return</span> res.<span class="property">tempFilePath</span></span><br><span class="line">  &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;压缩失败：&#x27;</span>, e)</span><br><span class="line">    <span class="keyword">return</span> tempFilePath <span class="comment">// 压缩失败返回原图</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用示例</span></span><br><span class="line"><span class="keyword">async</span> <span class="title function_">handleUpload</span>(<span class="params">tempFilePaths</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> compressedPaths = []</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> path <span class="keyword">of</span> tempFilePaths) &#123;</span><br><span class="line">    <span class="keyword">const</span> compressed = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">compressImage</span>(path)</span><br><span class="line">    compressedPaths.<span class="title function_">push</span>(compressed)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="title function_">uploadFiles</span>(compressedPaths)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="2-2-大图预览优化"><a href="#2-2-大图预览优化" class="headerlink" title="2.2 大图预览优化"></a>2.2 大图预览优化</h3><p><strong>问题描述：</strong><br>直接预览原图占用内存大，可能导致卡顿。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 预览时使用缩略图，点击查看原图</span></span><br><span class="line"><span class="keyword">const</span> imageList = &#123;</span><br><span class="line">  <span class="attr">original</span>: [], <span class="comment">// 原图</span></span><br><span class="line">  <span class="attr">thumbnail</span>: [] <span class="comment">// 缩略图</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 预览图片</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">previewImage</span>(<span class="params">index</span>) &#123;</span><br><span class="line">  uni.<span class="title function_">previewImage</span>(&#123;</span><br><span class="line">    <span class="attr">urls</span>: imageList.<span class="property">original</span>,</span><br><span class="line">    <span class="attr">current</span>: index,</span><br><span class="line">    <span class="comment">// 显示加载提示</span></span><br><span class="line">    <span class="attr">showmenu</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="attr">success</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;预览成功&#x27;</span>)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">fail</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">      uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">        <span class="attr">title</span>: <span class="string">&#x27;预览失败&#x27;</span>,</span><br><span class="line">        <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span></span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="3-上传进度问题"><a href="#3-上传进度问题" class="headerlink" title="3. 上传进度问题"></a>3. 上传进度问题</h2><h3 id="3-1-进度显示不准"><a href="#3-1-进度显示不准" class="headerlink" title="3.1 进度显示不准"></a>3.1 进度显示不准</h3><p><strong>问题描述：</strong><br>上传进度显示不准确，影响用户体验。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 更精确的进度显示</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">uploadFile</span>(<span class="params">filePath</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> uploadTask = uni.<span class="title function_">uploadFile</span>(&#123;</span><br><span class="line">      <span class="attr">url</span>: <span class="string">&#x27;your-upload-url&#x27;</span>,</span><br><span class="line">      <span class="attr">filePath</span>: filePath,</span><br><span class="line">      <span class="attr">name</span>: <span class="string">&#x27;file&#x27;</span>,</span><br><span class="line">      <span class="attr">success</span>: <span class="function"><span class="params">res</span> =&gt;</span> <span class="title function_">resolve</span>(res),</span><br><span class="line">      <span class="attr">fail</span>: <span class="function"><span class="params">err</span> =&gt;</span> <span class="title function_">reject</span>(err)</span><br><span class="line">    &#125;)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 监听上传进度</span></span><br><span class="line">    uploadTask.<span class="title function_">onProgressUpdate</span>(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> progress = res.<span class="property">progress</span></span><br><span class="line">      <span class="keyword">const</span> speed = (res.<span class="property">totalBytesSent</span> / <span class="number">1024</span> / <span class="number">1024</span>).<span class="title function_">toFixed</span>(<span class="number">2</span>)</span><br><span class="line">      </span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">uploadInfo</span> = &#123;</span><br><span class="line">        <span class="attr">progress</span>: progress,</span><br><span class="line">        <span class="attr">speed</span>: speed + <span class="string">&#x27;MB/s&#x27;</span></span><br><span class="line">      &#125;</span><br><span class="line">      </span><br><span class="line">      <span class="comment">// 更新UI显示</span></span><br><span class="line">      <span class="variable language_">this</span>.$set(<span class="variable language_">this</span>.<span class="property">uploadProgress</span>, filePath, progress)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3-2-批量上传进度"><a href="#3-2-批量上传进度" class="headerlink" title="3.2 批量上传进度"></a>3.2 批量上传进度</h3><p><strong>问题描述：</strong><br>多文件上传时无法显示总体进度。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 批量上传进度管理</span></span><br><span class="line"><span class="keyword">async</span> <span class="title function_">uploadFiles</span>(<span class="params">files</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> total = files.<span class="property">length</span></span><br><span class="line">  <span class="keyword">let</span> completed = <span class="number">0</span></span><br><span class="line">  </span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">totalProgress</span> = <span class="number">0</span></span><br><span class="line">  </span><br><span class="line">  <span class="keyword">const</span> uploads = files.<span class="title function_">map</span>(<span class="title function_">async</span> (file, index) =&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">uploadFile</span>(file)</span><br><span class="line">      completed++</span><br><span class="line">      <span class="comment">// 更新总进度</span></span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">totalProgress</span> = <span class="title class_">Math</span>.<span class="title function_">floor</span>((completed / total) * <span class="number">100</span>)</span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">`文件<span class="subst">$&#123;index + <span class="number">1</span>&#125;</span>上传失败：`</span>, e)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">await</span> <span class="title class_">Promise</span>.<span class="title function_">all</span>(uploads)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="4-上传错误处理"><a href="#4-上传错误处理" class="headerlink" title="4. 上传错误处理"></a>4. 上传错误处理</h2><h3 id="4-1-断网重传"><a href="#4-1-断网重传" class="headerlink" title="4.1 断网重传"></a>4.1 断网重传</h3><p><strong>问题描述：</strong><br>上传过程中断网导致上传失败。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 添加重试机制</span></span><br><span class="line"><span class="keyword">async</span> <span class="title function_">uploadWithRetry</span>(<span class="params">file, maxRetries = <span class="number">3</span></span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> retries = <span class="number">0</span></span><br><span class="line">  </span><br><span class="line">  <span class="keyword">while</span> (retries &lt; maxRetries) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">uploadFile</span>(file)</span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">      retries++</span><br><span class="line">      <span class="keyword">if</span> (retries === maxRetries) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;上传失败，请检查网络后重试&#x27;</span>)</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">// 等待后重试</span></span><br><span class="line">      <span class="keyword">await</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function"><span class="params">resolve</span> =&gt;</span> <span class="built_in">setTimeout</span>(resolve, <span class="number">1000</span>))</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="4-2-错误提示优化"><a href="#4-2-错误提示优化" class="headerlink" title="4.2 错误提示优化"></a>4.2 错误提示优化</h3><p><strong>问题描述：</strong><br>上传失败时提示不够友好。</p><p><strong>解决方案：</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 优化错误提示</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">handleUploadError</span>(<span class="params">error</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> message = <span class="string">&#x27;上传失败&#x27;</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 根据错误类型显示不同提示</span></span><br><span class="line">  <span class="keyword">switch</span> (error.<span class="property">code</span>) &#123;</span><br><span class="line">    <span class="keyword">case</span> <span class="string">&#x27;NETWORK_ERROR&#x27;</span>:</span><br><span class="line">      message = <span class="string">&#x27;网络异常，请检查网络设置&#x27;</span></span><br><span class="line">      <span class="keyword">break</span></span><br><span class="line">    <span class="keyword">case</span> <span class="string">&#x27;SIZE_EXCEED&#x27;</span>:</span><br><span class="line">      message = <span class="string">&#x27;文件大小超出限制&#x27;</span></span><br><span class="line">      <span class="keyword">break</span></span><br><span class="line">    <span class="keyword">case</span> <span class="string">&#x27;TYPE_ERROR&#x27;</span>:</span><br><span class="line">      message = <span class="string">&#x27;不支持的文件类型&#x27;</span></span><br><span class="line">      <span class="keyword">break</span></span><br><span class="line">    <span class="attr">default</span>:</span><br><span class="line">      message = error.<span class="property">message</span> || <span class="string">&#x27;上传失败，请重试&#x27;</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">    <span class="attr">title</span>: message,</span><br><span class="line">    <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span>,</span><br><span class="line">    <span class="attr">duration</span>: <span class="number">2000</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="5-实用技巧分享"><a href="#5-实用技巧分享" class="headerlink" title="5. 实用技巧分享"></a>5. 实用技巧分享</h2><h3 id="5-1-自动重命名"><a href="#5-1-自动重命名" class="headerlink" title="5.1 自动重命名"></a>5.1 自动重命名</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 生成文件名</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">generateFileName</span>(<span class="params">file</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> date = <span class="keyword">new</span> <span class="title class_">Date</span>()</span><br><span class="line">  <span class="keyword">const</span> random = <span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="number">10000</span>)</span><br><span class="line">  <span class="keyword">const</span> extension = file.<span class="title function_">split</span>(<span class="string">&#x27;.&#x27;</span>).<span class="title function_">pop</span>()</span><br><span class="line">  <span class="keyword">return</span> <span class="string">`<span class="subst">$&#123;date.getTime()&#125;</span>_<span class="subst">$&#123;random&#125;</span>.<span class="subst">$&#123;extension&#125;</span>`</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="5-2-秒传优化"><a href="#5-2-秒传优化" class="headerlink" title="5.2 秒传优化"></a>5.2 秒传优化</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 检查文件是否已上传</span></span><br><span class="line"><span class="keyword">async</span> <span class="title function_">checkFileExists</span>(<span class="params">file</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> md5 = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">calculateMD5</span>(file)</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> res = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">checkMD5</span>(md5)</span><br><span class="line">    <span class="keyword">if</span> (res.<span class="property">exists</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> res.<span class="property">url</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">  &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="6-最佳实践建议"><a href="#6-最佳实践建议" class="headerlink" title="6. 最佳实践建议"></a>6. 最佳实践建议</h2><ol><li>上传前做好校验</li><li>合理使用压缩</li><li>添加重试机制</li><li>优化用户体验</li><li>做好错误处理</li></ol><h2 id="7-总结"><a href="#7-总结" class="headerlink" title="7. 总结"></a>7. 总结</h2><ol><li>注意文件大小限制</li><li>处理好进度显示</li><li>优化上传体验</li><li>做好容错处理</li><li>保持代码可维护</li></ol><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">详细介绍uni-app中文件上传和图片处理的各种问题及解决方案，包括图片压缩、批量上传、上传进度等实用技巧，适合新手阅读。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="文件上传" scheme="https://www.hzv5.cn/tags/%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0/"/>
    
    <category term="图片处理" scheme="https://www.hzv5.cn/tags/%E5%9B%BE%E7%89%87%E5%A4%84%E7%90%86/"/>
    
  </entry>
  
  <entry>
    <title>uni-app表单验证踩坑记：这些坑我替你踩过了</title>
    <link href="https://www.hzv5.cn/2024/05/10/uniapp-form-validation/"/>
    <id>https://www.hzv5.cn/2024/05/10/uniapp-form-validation/</id>
    <published>2024-05-10T02:30:00.000Z</published>
    <updated>2024-05-10T02:30:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>做过表单的同学都知道，表单验证看似简单，但总有一些意想不到的问题。本文整理了一些实用的表单验证经验，希望能帮你少走弯路。</p></blockquote><span id="more"></span><h2 id="1-常见验证踩坑"><a href="#1-常见验证踩坑" class="headerlink" title="1. 常见验证踩坑"></a>1. 常见验证踩坑</h2><h3 id="1-1-手机号验证不全面"><a href="#1-1-手机号验证不全面" class="headerlink" title="1.1 手机号验证不全面"></a>1.1 手机号验证不全面</h3><p><strong>问题描述：</strong><br>很多人只用一个简单的11位数字正则来验证手机号，但实际上这样并不严谨。</p><p><strong>解决方案：</strong></p><ol><li>更严谨的手机号验证：<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 更完整的手机号验证规则</span></span><br><span class="line"><span class="keyword">const</span> phoneReg = <span class="regexp">/^1[3-9]\d&#123;9&#125;$/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用方法</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">validatePhone</span>(<span class="params">phone</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (!phoneReg.<span class="title function_">test</span>(phone)) &#123;</span><br><span class="line">    uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">      <span class="attr">title</span>: <span class="string">&#x27;请输入正确的手机号&#x27;</span>,</span><br><span class="line">      <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span></span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><h3 id="1-2-密码强度验证不够"><a href="#1-2-密码强度验证不够" class="headerlink" title="1.2 密码强度验证不够"></a>1.2 密码强度验证不够</h3><p><strong>问题描述：</strong><br>简单的密码验证容易导致用户设置过于简单的密码。</p><p><strong>解决方案：</strong></p><ol><li>添加密码强度检查：<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 密码必须包含数字、字母、特殊字符</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">checkPasswordStrength</span>(<span class="params">password</span>) &#123;</span><br><span class="line">  <span class="comment">// 至少8位，包含数字和字母</span></span><br><span class="line">  <span class="keyword">const</span> baseReg = <span class="regexp">/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]&#123;8,&#125;$/</span></span><br><span class="line">  <span class="comment">// 增加特殊字符要求</span></span><br><span class="line">  <span class="keyword">const</span> strongReg = <span class="regexp">/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&amp;])[A-Za-z\d@$!%*#?&amp;]&#123;8,&#125;$/</span></span><br><span class="line">  </span><br><span class="line">  <span class="keyword">if</span> (!baseReg.<span class="title function_">test</span>(password)) &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">valid</span>: <span class="literal">false</span>,</span><br><span class="line">      <span class="attr">message</span>: <span class="string">&#x27;密码至少8位，必须包含数字和字母&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">if</span> (!strongReg.<span class="title function_">test</span>(password)) &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">valid</span>: <span class="literal">true</span>,</span><br><span class="line">      <span class="attr">level</span>: <span class="string">&#x27;normal&#x27;</span>,</span><br><span class="line">      <span class="attr">message</span>: <span class="string">&#x27;建议增加特殊字符提高安全性&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    <span class="attr">valid</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="attr">level</span>: <span class="string">&#x27;strong&#x27;</span>,</span><br><span class="line">    <span class="attr">message</span>: <span class="string">&#x27;密码强度很好&#x27;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><h2 id="2-实时验证问题"><a href="#2-实时验证问题" class="headerlink" title="2. 实时验证问题"></a>2. 实时验证问题</h2><h3 id="2-1-验证频率过高"><a href="#2-1-验证频率过高" class="headerlink" title="2.1 验证频率过高"></a>2.1 验证频率过高</h3><p><strong>问题描述：</strong><br>输入时实时验证，导致频繁提示，影响用户体验。</p><p><strong>解决方案：</strong></p><ol><li>使用防抖处理：<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> timer = <span class="literal">null</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">debounceValidate</span>(<span class="params">value, rule</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (timer) <span class="built_in">clearTimeout</span>(timer)</span><br><span class="line">  timer = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 执行验证</span></span><br><span class="line">    <span class="keyword">const</span> result = rule.<span class="title function_">test</span>(value)</span><br><span class="line">    <span class="keyword">if</span> (!result) &#123;</span><br><span class="line">      uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">        <span class="attr">title</span>: <span class="string">&#x27;格式不正确&#x27;</span>,</span><br><span class="line">        <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span></span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;, <span class="number">500</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><h3 id="2-2-失焦验证时机"><a href="#2-2-失焦验证时机" class="headerlink" title="2.2 失焦验证时机"></a>2.2 失焦验证时机</h3><p><strong>问题描述：</strong><br>在输入框失焦时才验证，但有时用户直接提交表单。</p><p><strong>解决方案：</strong></p><ol><li>结合多个验证时机：<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">input</span> </span></span><br><span class="line"><span class="tag">  <span class="attr">v-model</span>=<span class="string">&quot;form.phone&quot;</span></span></span><br><span class="line"><span class="tag">  @<span class="attr">input</span>=<span class="string">&quot;onPhoneInput&quot;</span></span></span><br><span class="line"><span class="tag">  @<span class="attr">blur</span>=<span class="string">&quot;validatePhone&quot;</span></span></span><br><span class="line"><span class="tag">  <span class="attr">placeholder</span>=<span class="string">&quot;请输入手机号&quot;</span></span></span><br><span class="line"><span class="tag">/&gt;</span></span><br></pre></td></tr></table></figure></li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="comment">// 输入时简单验证</span></span><br><span class="line">    <span class="title function_">onPhoneInput</span>(<span class="params">e</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> value = e.<span class="property">target</span>.<span class="property">value</span></span><br><span class="line">      <span class="comment">// 只允许输入数字</span></span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">form</span>.<span class="property">phone</span> = value.<span class="title function_">replace</span>(<span class="regexp">/\D/g</span>, <span class="string">&#x27;&#x27;</span>)</span><br><span class="line">    &#125;,</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 失焦时完整验证</span></span><br><span class="line">    <span class="title function_">validatePhone</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">form</span>.<span class="property">phone</span>) <span class="keyword">return</span></span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">checkPhone</span>(<span class="variable language_">this</span>.<span class="property">form</span>.<span class="property">phone</span>)</span><br><span class="line">    &#125;,</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 提交时再次验证</span></span><br><span class="line">    <span class="title function_">submitForm</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">validatePhone</span>()) <span class="keyword">return</span></span><br><span class="line">      <span class="comment">// 继续提交流程</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="3-特殊场景验证"><a href="#3-特殊场景验证" class="headerlink" title="3. 特殊场景验证"></a>3. 特殊场景验证</h2><h3 id="3-1-身份证号验证"><a href="#3-1-身份证号验证" class="headerlink" title="3.1 身份证号验证"></a>3.1 身份证号验证</h3><p><strong>问题描述：</strong><br>简单的18位验证无法识别假身份证号。</p><p><strong>解决方案：</strong></p><ol><li>完整的身份证验证：<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">validateIdCard</span>(<span class="params">idCard</span>) &#123;</span><br><span class="line">  <span class="comment">// 基本格式验证</span></span><br><span class="line">  <span class="keyword">const</span> reg = <span class="regexp">/(^\d&#123;15&#125;$)|(^\d&#123;18&#125;$)|(^\d&#123;17&#125;(\d|X|x)$)/</span></span><br><span class="line">  <span class="keyword">if</span> (!reg.<span class="title function_">test</span>(idCard)) <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 验证出生日期</span></span><br><span class="line">  <span class="keyword">const</span> year = idCard.<span class="title function_">substr</span>(<span class="number">6</span>, <span class="number">4</span>)</span><br><span class="line">  <span class="keyword">const</span> month = idCard.<span class="title function_">substr</span>(<span class="number">10</span>, <span class="number">2</span>)</span><br><span class="line">  <span class="keyword">const</span> day = idCard.<span class="title function_">substr</span>(<span class="number">12</span>, <span class="number">2</span>)</span><br><span class="line">  <span class="keyword">const</span> date = <span class="keyword">new</span> <span class="title class_">Date</span>(year + <span class="string">&#x27;-&#x27;</span> + month + <span class="string">&#x27;-&#x27;</span> + day)</span><br><span class="line">  <span class="keyword">if</span> (date &gt; <span class="keyword">new</span> <span class="title class_">Date</span>()) <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 验证校验码（略）</span></span><br><span class="line">  <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><h3 id="3-2-金额输入验证"><a href="#3-2-金额输入验证" class="headerlink" title="3.2 金额输入验证"></a>3.2 金额输入验证</h3><p><strong>问题描述：</strong><br>金额输入需要限制小数位数和输入格式。</p><p><strong>解决方案：</strong></p><ol><li>金额输入处理：<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 限制只能输入数字和小数点，最多两位小数</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">validateAmount</span>(<span class="params">value</span>) &#123;</span><br><span class="line">  <span class="comment">// 先去除非数字和小数点</span></span><br><span class="line">  value = value.<span class="title function_">replace</span>(<span class="regexp">/[^\d.]/g</span>, <span class="string">&#x27;&#x27;</span>)</span><br><span class="line">  <span class="comment">// 只保留第一个小数点</span></span><br><span class="line">  value = value.<span class="title function_">replace</span>(<span class="regexp">/\.&#123;2,&#125;/g</span>, <span class="string">&#x27;.&#x27;</span>)</span><br><span class="line">  <span class="comment">// 保留两位小数</span></span><br><span class="line">  value = value.<span class="title function_">replace</span>(<span class="regexp">/^(\d+)\.(\d\d).*$/</span>, <span class="string">&#x27;$1.$2&#x27;</span>)</span><br><span class="line">  <span class="keyword">return</span> value</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用示例</span></span><br><span class="line"><span class="title function_">onAmountInput</span>(<span class="params">e</span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">form</span>.<span class="property">amount</span> = <span class="title function_">validateAmount</span>(e.<span class="property">target</span>.<span class="property">value</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><h2 id="4-表单提交验证"><a href="#4-表单提交验证" class="headerlink" title="4. 表单提交验证"></a>4. 表单提交验证</h2><h3 id="4-1-重复提交问题"><a href="#4-1-重复提交问题" class="headerlink" title="4.1 重复提交问题"></a>4.1 重复提交问题</h3><p><strong>问题描述：</strong><br>用户快速点击提交按钮，导致表单重复提交。</p><p><strong>解决方案：</strong></p><ol><li>添加提交锁：<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="title function_">data</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">submitting</span>: <span class="literal">false</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="keyword">async</span> <span class="title function_">submitForm</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">submitting</span>) <span class="keyword">return</span></span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">submitting</span> = <span class="literal">true</span></span><br><span class="line">      </span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">submit</span>()</span><br><span class="line">        uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">          <span class="attr">title</span>: <span class="string">&#x27;提交成功&#x27;</span></span><br><span class="line">        &#125;)</span><br><span class="line">      &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">        uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">          <span class="attr">title</span>: <span class="string">&#x27;提交失败&#x27;</span>,</span><br><span class="line">          <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span></span><br><span class="line">        &#125;)</span><br><span class="line">      &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">submitting</span> = <span class="literal">false</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><h3 id="4-2-必填项检查"><a href="#4-2-必填项检查" class="headerlink" title="4.2 必填项检查"></a>4.2 必填项检查</h3><p><strong>问题描述：</strong><br>提交时才发现有必填项未填写，体验不好。</p><p><strong>解决方案：</strong></p><ol><li>实时显示必填状态：<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">view</span> <span class="attr">class</span>=<span class="string">&quot;form-item&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">text</span> <span class="attr">class</span>=<span class="string">&quot;label&quot;</span>&gt;</span></span><br><span class="line">    手机号</span><br><span class="line">    <span class="tag">&lt;<span class="name">text</span> <span class="attr">class</span>=<span class="string">&quot;required&quot;</span>&gt;</span>*<span class="tag">&lt;/<span class="name">text</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">text</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span> </span></span><br><span class="line"><span class="tag">    <span class="attr">v-model</span>=<span class="string">&quot;form.phone&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">:class</span>=<span class="string">&quot;&#123;&#x27;is-error&#x27;: showError &amp;&amp; !form.phone&#125;&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">placeholder</span>=<span class="string">&quot;请输入手机号&quot;</span></span></span><br><span class="line"><span class="tag">  /&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">text</span> <span class="attr">v-if</span>=<span class="string">&quot;showError &amp;&amp; !form.phone&quot;</span> <span class="attr">class</span>=<span class="string">&quot;error-tip&quot;</span>&gt;</span></span><br><span class="line">    手机号不能为空</span><br><span class="line">  <span class="tag">&lt;/<span class="name">text</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">view</span>&gt;</span></span><br></pre></td></tr></table></figure></li></ol><h2 id="5-常用验证规则"><a href="#5-常用验证规则" class="headerlink" title="5. 常用验证规则"></a>5. 常用验证规则</h2><h3 id="5-1-常用正则表达式"><a href="#5-1-常用正则表达式" class="headerlink" title="5.1 常用正则表达式"></a>5.1 常用正则表达式</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> rules = &#123;</span><br><span class="line">  <span class="comment">// 手机号</span></span><br><span class="line">  <span class="attr">phone</span>: <span class="regexp">/^1[3-9]\d&#123;9&#125;$/</span>,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 邮箱</span></span><br><span class="line">  <span class="attr">email</span>: <span class="regexp">/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]&#123;2,&#125;$/</span>,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 车牌号</span></span><br><span class="line">  <span class="attr">carNo</span>: <span class="regexp">/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]&#123;1&#125;[A-Z]&#123;1&#125;[A-Z0-9]&#123;4&#125;[A-Z0-9挂学警港澳]&#123;1&#125;$/</span>,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 银行卡号</span></span><br><span class="line">  <span class="attr">bankCard</span>: <span class="regexp">/^([1-9]&#123;1&#125;)(\d&#123;15&#125;|\d&#123;18&#125;)$/</span>,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 密码强度</span></span><br><span class="line">  <span class="attr">password</span>: <span class="regexp">/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&amp;])[A-Za-z\d@$!%*#?&amp;]&#123;8,&#125;$/</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="5-2-自定义验证函数"><a href="#5-2-自定义验证函数" class="headerlink" title="5.2 自定义验证函数"></a>5.2 自定义验证函数</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> validators = &#123;</span><br><span class="line">  <span class="comment">// 年龄验证</span></span><br><span class="line">  <span class="title function_">age</span>(<span class="params">value</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> age = <span class="built_in">parseInt</span>(value)</span><br><span class="line">    <span class="keyword">return</span> age &gt;= <span class="number">0</span> &amp;&amp; age &lt;= <span class="number">120</span></span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 日期验证</span></span><br><span class="line">  <span class="title function_">date</span>(<span class="params">value</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> !<span class="built_in">isNaN</span>(<span class="keyword">new</span> <span class="title class_">Date</span>(value).<span class="title function_">getTime</span>())</span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 金额验证</span></span><br><span class="line">  <span class="title function_">amount</span>(<span class="params">value</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="regexp">/^\d+(\.\d&#123;1,2&#125;)?$/</span>.<span class="title function_">test</span>(value)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="6-最佳实践建议"><a href="#6-最佳实践建议" class="headerlink" title="6. 最佳实践建议"></a>6. 最佳实践建议</h2><ol><li>合理使用验证时机</li><li>注意验证提示的友好性</li><li>考虑特殊情况处理</li><li>做好防重复提交</li><li>保持代码可维护性</li></ol><h2 id="7-总结"><a href="#7-总结" class="headerlink" title="7. 总结"></a>7. 总结</h2><ol><li>验证规则要严谨但不过度</li><li>注意用户体验</li><li>考虑各种异常情况</li><li>做好性能优化</li><li>保持代码整洁</li></ol><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">总结uni-app表单验证中的常见问题和解决方案，包括手机号验证、密码验证、自定义验证等实用技巧，通俗易懂的语言讲解开发经验。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="表单验证" scheme="https://www.hzv5.cn/tags/%E8%A1%A8%E5%8D%95%E9%AA%8C%E8%AF%81/"/>
    
    <category term="实战经验" scheme="https://www.hzv5.cn/tags/%E5%AE%9E%E6%88%98%E7%BB%8F%E9%AA%8C/"/>
    
  </entry>
  
  <entry>
    <title>uni-app开发踩坑记录：新手必看的常见问题与解决方案</title>
    <link href="https://www.hzv5.cn/2024/04/20/uniapp-common-issues/"/>
    <id>https://www.hzv5.cn/2024/04/20/uniapp-common-issues/</id>
    <published>2024-04-20T08:45:00.000Z</published>
    <updated>2024-04-20T08:45:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>在uni-app开发中，总会遇到一些让人头疼的问题。本文整理了一些常见的坑和解决方案，希望能帮助大家少走弯路。</p></blockquote><span id="more"></span><h2 id="1-页面相关问题"><a href="#1-页面相关问题" class="headerlink" title="1. 页面相关问题"></a>1. 页面相关问题</h2><h3 id="1-1-页面返回数据刷新问题"><a href="#1-1-页面返回数据刷新问题" class="headerlink" title="1.1 页面返回数据刷新问题"></a>1.1 页面返回数据刷新问题</h3><p><strong>问题描述：</strong><br>从A页面跳转到B页面，在B页面修改了数据后返回A页面，发现A页面的数据没有更新。</p><p><strong>解决方案：</strong></p><ol><li><p>使用事件总线：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 在B页面修改数据后发送事件</span></span><br><span class="line">uni.$emit(<span class="string">&#x27;updateData&#x27;</span>, &#123; <span class="attr">data</span>: <span class="string">&#x27;新数据&#x27;</span> &#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 在A页面监听事件</span></span><br><span class="line"><span class="title function_">onShow</span>(<span class="params"></span>) &#123;</span><br><span class="line">  uni.$on(<span class="string">&#x27;updateData&#x27;</span>, <span class="variable language_">this</span>.<span class="property">handleUpdate</span>)</span><br><span class="line">&#125;,</span><br><span class="line"><span class="title function_">onHide</span>(<span class="params"></span>) &#123;</span><br><span class="line">  uni.$off(<span class="string">&#x27;updateData&#x27;</span>, <span class="variable language_">this</span>.<span class="property">handleUpdate</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>使用页面生命周期：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 在A页面的onShow中刷新数据</span></span><br><span class="line"><span class="title function_">onShow</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="title function_">loadData</span>() <span class="comment">// 重新加载数据</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><h3 id="1-2-页面返回卡顿问题"><a href="#1-2-页面返回卡顿问题" class="headerlink" title="1.2 页面返回卡顿问题"></a>1.2 页面返回卡顿问题</h3><p><strong>问题描述：</strong><br>使用uni.navigateBack返回上一页时出现明显卡顿。</p><p><strong>解决方案：</strong></p><ol><li>检查页面是否有大量数据或复杂计算</li><li>使用分页加载代替一次性加载</li><li>在返回前清理不必要的定时器和监听器</li><li>避免在onShow中进行耗时操作</li></ol><h2 id="2-样式兼容问题"><a href="#2-样式兼容问题" class="headerlink" title="2. 样式兼容问题"></a>2. 样式兼容问题</h2><h3 id="2-1-不同平台样式差异"><a href="#2-1-不同平台样式差异" class="headerlink" title="2.1 不同平台样式差异"></a>2.1 不同平台样式差异</h3><p><strong>问题描述：</strong><br>同样的样式在不同平台（iOS、Android、H5）显示效果不一致。</p><p><strong>解决方案：</strong></p><ol><li>使用flex布局代替固定宽高</li><li>避免使用复杂的CSS3特性</li><li>使用条件编译处理平台差异：<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* #ifdef H5 */</span></span><br><span class="line"><span class="selector-class">.box</span> &#123; <span class="attribute">height</span>: <span class="number">100vh</span>; &#125;</span><br><span class="line"><span class="comment">/* #endif */</span></span><br><span class="line"><span class="comment">/* #ifdef MP */</span></span><br><span class="line"><span class="selector-class">.box</span> &#123; <span class="attribute">height</span>: <span class="number">100%</span>; &#125;</span><br><span class="line"><span class="comment">/* #endif */</span></span><br></pre></td></tr></table></figure></li></ol><h3 id="2-2-滚动穿透问题"><a href="#2-2-滚动穿透问题" class="headerlink" title="2.2 滚动穿透问题"></a>2.2 滚动穿透问题</h3><p><strong>问题描述：</strong><br>弹窗打开时，背景页面仍可滚动。</p><p><strong>解决方案：</strong></p><ol><li><p>弹窗打开时给body添加类：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 打开弹窗时</span></span><br><span class="line"><span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">style</span>.<span class="property">overflow</span> = <span class="string">&#x27;hidden&#x27;</span></span><br><span class="line"><span class="comment">// 关闭弹窗时</span></span><br><span class="line"><span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">style</span>.<span class="property">overflow</span> = <span class="string">&#x27;auto&#x27;</span></span><br></pre></td></tr></table></figure></li><li><p>使用@touchmove.prevent阻止滚动：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">view</span> <span class="attr">class</span>=<span class="string">&quot;mask&quot;</span> @<span class="attr">touchmove.prevent</span>&gt;</span><span class="tag">&lt;/<span class="name">view</span>&gt;</span></span><br></pre></td></tr></table></figure></li></ol><h2 id="3-网络请求问题"><a href="#3-网络请求问题" class="headerlink" title="3. 网络请求问题"></a>3. 网络请求问题</h2><h3 id="3-1-请求超时处理"><a href="#3-1-请求超时处理" class="headerlink" title="3.1 请求超时处理"></a>3.1 请求超时处理</h3><p><strong>问题描述：</strong><br>网络请求偶尔超时，导致页面卡死。</p><p><strong>解决方案：</strong></p><ol><li>设置合理的超时时间</li><li>添加重试机制</li><li>显示加载提示和错误提示：<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">uni.<span class="title function_">showLoading</span>(&#123;</span><br><span class="line">  <span class="attr">title</span>: <span class="string">&#x27;加载中...&#x27;</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">  <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">loadData</span>()</span><br><span class="line">&#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">  uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">    <span class="attr">title</span>: <span class="string">&#x27;加载失败，请重试&#x27;</span>,</span><br><span class="line">    <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">  uni.<span class="title function_">hideLoading</span>()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><h3 id="3-2-登录失效处理"><a href="#3-2-登录失效处理" class="headerlink" title="3.2 登录失效处理"></a>3.2 登录失效处理</h3><p><strong>问题描述：</strong><br>token过期后继续请求接口导致报错。</p><p><strong>解决方案：</strong></p><ol><li>统一处理token过期：<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 请求拦截器中处理</span></span><br><span class="line"><span class="keyword">if</span> (response.<span class="property">code</span> === <span class="number">401</span>) &#123;</span><br><span class="line">  <span class="comment">// 清除登录信息</span></span><br><span class="line">  uni.<span class="title function_">clearStorageSync</span>()</span><br><span class="line">  <span class="comment">// 跳转登录页</span></span><br><span class="line">  uni.<span class="title function_">reLaunch</span>(&#123;</span><br><span class="line">    <span class="attr">url</span>: <span class="string">&#x27;/pages/login/index&#x27;</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><h2 id="4-性能优化问题"><a href="#4-性能优化问题" class="headerlink" title="4. 性能优化问题"></a>4. 性能优化问题</h2><h3 id="4-1-图片加载优化"><a href="#4-1-图片加载优化" class="headerlink" title="4.1 图片加载优化"></a>4.1 图片加载优化</h3><p><strong>问题描述：</strong><br>页面中图片较多，加载慢且占用内存。</p><p><strong>解决方案：</strong></p><ol><li><p>使用懒加载：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">image</span> <span class="attr">:src</span>=<span class="string">&quot;url&quot;</span> <span class="attr">lazy-load</span>&gt;</span><span class="tag">&lt;/<span class="name">image</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li><p>压缩图片</p></li><li><p>使用CDN加速</p></li><li><p>预加载重要图片</p></li></ol><h3 id="4-2-列表卡顿问题"><a href="#4-2-列表卡顿问题" class="headerlink" title="4.2 列表卡顿问题"></a>4.2 列表卡顿问题</h3><p><strong>问题描述：</strong><br>长列表滚动时出现卡顿。</p><p><strong>解决方案：</strong></p><ol><li>使用分页加载</li><li>避免在滚动时进行复杂计算</li><li>使用骨架屏优化体验</li><li>减少不必要的数据绑定</li></ol><h2 id="5-小程序相关问题"><a href="#5-小程序相关问题" class="headerlink" title="5. 小程序相关问题"></a>5. 小程序相关问题</h2><h3 id="5-1-包体积超限"><a href="#5-1-包体积超限" class="headerlink" title="5.1 包体积超限"></a>5.1 包体积超限</h3><p><strong>问题描述：</strong><br>小程序打包后提示超出大小限制。</p><p><strong>解决方案：</strong></p><ol><li>使用分包加载</li><li>压缩图片和资源文件</li><li>删除未使用的组件和文件</li><li>使用CDN加载大文件</li></ol><h3 id="5-2-微信授权问题"><a href="#5-2-微信授权问题" class="headerlink" title="5.2 微信授权问题"></a>5.2 微信授权问题</h3><p><strong>问题描述：</strong><br>获取用户信息时授权弹窗显示不出来。</p><p><strong>解决方案：</strong></p><ol><li><p>使用button触发授权：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">open-type</span>=<span class="string">&quot;getUserInfo&quot;</span> @<span class="attr">getuserinfo</span>=<span class="string">&quot;handleGetUserInfo&quot;</span>&gt;</span></span><br><span class="line">  获取用户信息</span><br><span class="line"><span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li><p>检查是否已授权：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">uni.<span class="title function_">getSetting</span>(&#123;</span><br><span class="line">  <span class="attr">success</span>: <span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (!res.<span class="property">authSetting</span>[<span class="string">&#x27;scope.userInfo&#x27;</span>]) &#123;</span><br><span class="line">      <span class="comment">// 未授权，显示授权按钮</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li></ol><h2 id="6-开发工具问题"><a href="#6-开发工具问题" class="headerlink" title="6. 开发工具问题"></a>6. 开发工具问题</h2><h3 id="6-1-HBuilderX卡顿"><a href="#6-1-HBuilderX卡顿" class="headerlink" title="6.1 HBuilderX卡顿"></a>6.1 HBuilderX卡顿</h3><p><strong>问题描述：</strong><br>HBuilderX运行缓慢，经常卡死。</p><p><strong>解决方案：</strong></p><ol><li>关闭不需要的项目</li><li>定期清理缓存</li><li>更新到最新版本</li><li>增加内存分配</li></ol><h3 id="6-2-真机调试问题"><a href="#6-2-真机调试问题" class="headerlink" title="6.2 真机调试问题"></a>6.2 真机调试问题</h3><p><strong>问题描述：</strong><br>真机调试时连接不上设备。</p><p><strong>解决方案：</strong></p><ol><li>检查USB调试是否开启</li><li>更新手机驱动</li><li>更换数据线</li><li>重启开发工具和手机</li></ol><h2 id="7-总结建议"><a href="#7-总结建议" class="headerlink" title="7. 总结建议"></a>7. 总结建议</h2><ol><li>多看官方文档和更新日志</li><li>保持良好的代码习惯</li><li>做好版本管理</li><li>常见问题记录总结</li><li>定期更新开发工具</li></ol><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">总结uni-app开发中的常见问题和解决方案，帮助开发者避免踩坑，提高开发效率。通俗易懂的语言，适合新手阅读。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="踩坑记录" scheme="https://www.hzv5.cn/tags/%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95/"/>
    
    <category term="问题解决" scheme="https://www.hzv5.cn/tags/%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/"/>
    
  </entry>
  
  <entry>
    <title>uni-app安全防护指南：构建可靠的跨端应用</title>
    <link href="https://www.hzv5.cn/2024/04/15/uniapp-security/"/>
    <id>https://www.hzv5.cn/2024/04/15/uniapp-security/</id>
    <published>2024-04-15T03:35:00.000Z</published>
    <updated>2024-04-15T03:35:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>安全防护是应用开发中不可忽视的环节,本文将详细介绍如何在uni-app中实现全方位的安全防护,助你打造安全可靠的应用。</p></blockquote><span id="more"></span><h2 id="1-数据加密"><a href="#1-数据加密" class="headerlink" title="1. 数据加密"></a>1. 数据加密</h2><h3 id="1-1-加密工具类"><a href="#1-1-加密工具类" class="headerlink" title="1.1 加密工具类"></a>1.1 加密工具类</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/crypto.js</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">CryptoJS</span> <span class="keyword">from</span> <span class="string">&#x27;crypto-js&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Crypto</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">key</span> = options.<span class="property">key</span> || <span class="string">&#x27;default_key&#x27;</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">iv</span> = options.<span class="property">iv</span> || <span class="string">&#x27;default_iv&#x27;</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// AES加密</span></span><br><span class="line">  <span class="title function_">encrypt</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> key = <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span>.<span class="title function_">parse</span>(<span class="variable language_">this</span>.<span class="property">key</span>)</span><br><span class="line">    <span class="keyword">const</span> iv = <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span>.<span class="title function_">parse</span>(<span class="variable language_">this</span>.<span class="property">iv</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">const</span> encrypted = <span class="title class_">CryptoJS</span>.<span class="property">AES</span>.<span class="title function_">encrypt</span>(</span><br><span class="line">      <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(data),</span><br><span class="line">      key,</span><br><span class="line">      &#123;</span><br><span class="line">        iv,</span><br><span class="line">        <span class="attr">mode</span>: <span class="title class_">CryptoJS</span>.<span class="property">mode</span>.<span class="property">CBC</span>,</span><br><span class="line">        <span class="attr">padding</span>: <span class="title class_">CryptoJS</span>.<span class="property">pad</span>.<span class="property">Pkcs7</span></span><br><span class="line">      &#125;</span><br><span class="line">    )</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> encrypted.<span class="title function_">toString</span>()</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// AES解密</span></span><br><span class="line">  <span class="title function_">decrypt</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> key = <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span>.<span class="title function_">parse</span>(<span class="variable language_">this</span>.<span class="property">key</span>)</span><br><span class="line">    <span class="keyword">const</span> iv = <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span>.<span class="title function_">parse</span>(<span class="variable language_">this</span>.<span class="property">iv</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">const</span> decrypted = <span class="title class_">CryptoJS</span>.<span class="property">AES</span>.<span class="title function_">decrypt</span>(</span><br><span class="line">      data,</span><br><span class="line">      key,</span><br><span class="line">      &#123;</span><br><span class="line">        iv,</span><br><span class="line">        <span class="attr">mode</span>: <span class="title class_">CryptoJS</span>.<span class="property">mode</span>.<span class="property">CBC</span>,</span><br><span class="line">        <span class="attr">padding</span>: <span class="title class_">CryptoJS</span>.<span class="property">pad</span>.<span class="property">Pkcs7</span></span><br><span class="line">      &#125;</span><br><span class="line">    )</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">JSON</span>.<span class="title function_">parse</span>(decrypted.<span class="title function_">toString</span>(<span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span>))</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// RSA加密</span></span><br><span class="line">  <span class="title function_">rsaEncrypt</span>(<span class="params">data, publicKey</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> jsencrypt = <span class="keyword">new</span> <span class="title class_">JSEncrypt</span>()</span><br><span class="line">    jsencrypt.<span class="title function_">setPublicKey</span>(publicKey)</span><br><span class="line">    <span class="keyword">return</span> jsencrypt.<span class="title function_">encrypt</span>(data)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// RSA解密</span></span><br><span class="line">  <span class="title function_">rsaDecrypt</span>(<span class="params">data, privateKey</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> jsencrypt = <span class="keyword">new</span> <span class="title class_">JSEncrypt</span>()</span><br><span class="line">    jsencrypt.<span class="title function_">setPrivateKey</span>(privateKey)</span><br><span class="line">    <span class="keyword">return</span> jsencrypt.<span class="title function_">decrypt</span>(data)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// MD5加密</span></span><br><span class="line">  <span class="title function_">md5</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">CryptoJS</span>.<span class="title class_">MD5</span>(data).<span class="title function_">toString</span>()</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// Base64编码</span></span><br><span class="line">  <span class="title function_">base64Encode</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Base64</span>.<span class="title function_">stringify</span>(</span><br><span class="line">      <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span>.<span class="title function_">parse</span>(data)</span><br><span class="line">    )</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// Base64解码</span></span><br><span class="line">  <span class="title function_">base64Decode</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Base64</span>.<span class="title function_">parse</span>(data).<span class="title function_">toString</span>(</span><br><span class="line">      <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span></span><br><span class="line">    )</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">Crypto</span>(&#123;</span><br><span class="line">  <span class="attr">key</span>: process.<span class="property">env</span>.<span class="property">VUE_APP_CRYPTO_KEY</span>,</span><br><span class="line">  <span class="attr">iv</span>: process.<span class="property">env</span>.<span class="property">VUE_APP_CRYPTO_IV</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="1-2-敏感数据存储"><a href="#1-2-敏感数据存储" class="headerlink" title="1.2 敏感数据存储"></a>1.2 敏感数据存储</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/secure-storage.js</span></span><br><span class="line"><span class="keyword">import</span> crypto <span class="keyword">from</span> <span class="string">&#x27;./crypto&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">SecureStorage</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">prefix</span> = options.<span class="property">prefix</span> || <span class="string">&#x27;secure_&#x27;</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">expire</span> = options.<span class="property">expire</span> || <span class="number">0</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 加密存储</span></span><br><span class="line">  <span class="title function_">set</span>(<span class="params">key, value, expire = <span class="number">0</span></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> data = &#123;</span><br><span class="line">      value,</span><br><span class="line">      <span class="attr">time</span>: <span class="title class_">Date</span>.<span class="title function_">now</span>(),</span><br><span class="line">      <span class="attr">expire</span>: expire || <span class="variable language_">this</span>.<span class="property">expire</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">const</span> encrypted = crypto.<span class="title function_">encrypt</span>(data)</span><br><span class="line">    uni.<span class="title function_">setStorageSync</span>(</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">prefix</span> + key,</span><br><span class="line">      encrypted</span><br><span class="line">    )</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 解密读取</span></span><br><span class="line">  <span class="title function_">get</span>(<span class="params">key</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> encrypted = uni.<span class="title function_">getStorageSync</span>(<span class="variable language_">this</span>.<span class="property">prefix</span> + key)</span><br><span class="line">    <span class="keyword">if</span> (!encrypted) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> &#123; value, time, expire &#125; = crypto.<span class="title function_">decrypt</span>(encrypted)</span><br><span class="line">      </span><br><span class="line">      <span class="comment">// 判断是否过期</span></span><br><span class="line">      <span class="keyword">if</span> (expire &amp;&amp; <span class="title class_">Date</span>.<span class="title function_">now</span>() - time &gt; expire * <span class="number">1000</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">remove</span>(key)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">      &#125;</span><br><span class="line">      </span><br><span class="line">      <span class="keyword">return</span> value</span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 移除数据</span></span><br><span class="line">  <span class="title function_">remove</span>(<span class="params">key</span>) &#123;</span><br><span class="line">    uni.<span class="title function_">removeStorageSync</span>(<span class="variable language_">this</span>.<span class="property">prefix</span> + key)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 清空数据</span></span><br><span class="line">  <span class="title function_">clear</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> keys = uni.<span class="title function_">getStorageInfoSync</span>().<span class="property">keys</span></span><br><span class="line">    keys.<span class="title function_">forEach</span>(<span class="function"><span class="params">key</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (key.<span class="title function_">startsWith</span>(<span class="variable language_">this</span>.<span class="property">prefix</span>)) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">remove</span>(key.<span class="title function_">slice</span>(<span class="variable language_">this</span>.<span class="property">prefix</span>.<span class="property">length</span>))</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">SecureStorage</span>()</span><br></pre></td></tr></table></figure><h2 id="2-网络安全"><a href="#2-网络安全" class="headerlink" title="2. 网络安全"></a>2. 网络安全</h2><h3 id="2-1-请求加密"><a href="#2-1-请求加密" class="headerlink" title="2.1 请求加密"></a>2.1 请求加密</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/secure-request.js</span></span><br><span class="line"><span class="keyword">import</span> crypto <span class="keyword">from</span> <span class="string">&#x27;./crypto&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">SecureRequest</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">publicKey</span> = <span class="string">&#x27;&#x27;</span> <span class="comment">// RSA公钥</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 初始化</span></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">init</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="comment">// 获取服务器公钥</span></span><br><span class="line">    <span class="keyword">const</span> &#123; publicKey &#125; = <span class="keyword">await</span> uni.<span class="title function_">request</span>(&#123;</span><br><span class="line">      <span class="attr">url</span>: <span class="string">&#x27;/api/public-key&#x27;</span></span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">publicKey</span> = publicKey</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 加密请求</span></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">request</span>(<span class="params">options</span>) &#123;</span><br><span class="line">    <span class="comment">// 生成随机密钥</span></span><br><span class="line">    <span class="keyword">const</span> randomKey = <span class="title class_">Math</span>.<span class="title function_">random</span>().<span class="title function_">toString</span>(<span class="number">36</span>).<span class="title function_">slice</span>(-<span class="number">8</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 使用RSA加密随机密钥</span></span><br><span class="line">    <span class="keyword">const</span> encryptedKey = crypto.<span class="title function_">rsaEncrypt</span>(</span><br><span class="line">      randomKey,</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">publicKey</span></span><br><span class="line">    )</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 使用随机密钥加密数据</span></span><br><span class="line">    <span class="keyword">const</span> encryptedData = crypto.<span class="title function_">encrypt</span>(</span><br><span class="line">      options.<span class="property">data</span>,</span><br><span class="line">      randomKey</span><br><span class="line">    )</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 发送请求</span></span><br><span class="line">    <span class="keyword">return</span> uni.<span class="title function_">request</span>(&#123;</span><br><span class="line">      ...options,</span><br><span class="line">      <span class="attr">data</span>: &#123;</span><br><span class="line">        <span class="attr">key</span>: encryptedKey,</span><br><span class="line">        <span class="attr">data</span>: encryptedData</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">SecureRequest</span>()</span><br></pre></td></tr></table></figure><h3 id="2-2-防重放攻击"><a href="#2-2-防重放攻击" class="headerlink" title="2.2 防重放攻击"></a>2.2 防重放攻击</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/anti-replay.js</span></span><br><span class="line"><span class="keyword">import</span> crypto <span class="keyword">from</span> <span class="string">&#x27;./crypto&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">AntiReplay</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">cache</span> = <span class="keyword">new</span> <span class="title class_">Map</span>()</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 生成请求签名</span></span><br><span class="line">  <span class="title function_">sign</span>(<span class="params">params</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> timestamp = <span class="title class_">Date</span>.<span class="title function_">now</span>()</span><br><span class="line">    <span class="keyword">const</span> nonce = <span class="title class_">Math</span>.<span class="title function_">random</span>().<span class="title function_">toString</span>(<span class="number">36</span>).<span class="title function_">slice</span>(-<span class="number">8</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">const</span> data = &#123;</span><br><span class="line">      ...params,</span><br><span class="line">      timestamp,</span><br><span class="line">      nonce</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 按键名排序</span></span><br><span class="line">    <span class="keyword">const</span> keys = <span class="title class_">Object</span>.<span class="title function_">keys</span>(data).<span class="title function_">sort</span>()</span><br><span class="line">    <span class="keyword">const</span> signStr = keys.<span class="title function_">map</span>(<span class="function"><span class="params">key</span> =&gt;</span> <span class="string">`<span class="subst">$&#123;key&#125;</span>=<span class="subst">$&#123;data[key]&#125;</span>`</span>).<span class="title function_">join</span>(<span class="string">&#x27;&amp;&#x27;</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      ...data,</span><br><span class="line">      <span class="attr">sign</span>: crypto.<span class="title function_">md5</span>(signStr)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 验证签名</span></span><br><span class="line">  <span class="title function_">verify</span>(<span class="params">params</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; timestamp, nonce, sign, ...rest &#125; = params</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 检查时间戳是否过期</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="title class_">Date</span>.<span class="title function_">now</span>() - timestamp &gt; <span class="number">5</span> * <span class="number">60</span> * <span class="number">1000</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 检查是否重放</span></span><br><span class="line">    <span class="keyword">const</span> cacheKey = <span class="string">`<span class="subst">$&#123;timestamp&#125;</span>:<span class="subst">$&#123;nonce&#125;</span>`</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">has</span>(cacheKey)) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 验证签名</span></span><br><span class="line">    <span class="keyword">const</span> keys = <span class="title class_">Object</span>.<span class="title function_">keys</span>(rest).<span class="title function_">sort</span>()</span><br><span class="line">    <span class="keyword">const</span> signStr = keys.<span class="title function_">map</span>(<span class="function"><span class="params">key</span> =&gt;</span> <span class="string">`<span class="subst">$&#123;key&#125;</span>=<span class="subst">$&#123;rest[key]&#125;</span>`</span>).<span class="title function_">join</span>(<span class="string">&#x27;&amp;&#x27;</span>)</span><br><span class="line">    <span class="keyword">if</span> (crypto.<span class="title function_">md5</span>(signStr) !== sign) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 缓存请求标识</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">set</span>(cacheKey, <span class="literal">true</span>)</span><br><span class="line">    <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">delete</span>(cacheKey)</span><br><span class="line">    &#125;, <span class="number">5</span> * <span class="number">60</span> * <span class="number">1000</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">AntiReplay</span>()</span><br></pre></td></tr></table></figure><h2 id="3-代码保护"><a href="#3-代码保护" class="headerlink" title="3. 代码保护"></a>3. 代码保护</h2><h3 id="3-1-代码混淆"><a href="#3-1-代码混淆" class="headerlink" title="3.1 代码混淆"></a>3.1 代码混淆</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// vue.config.js</span></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">TerserPlugin</span> = <span class="built_in">require</span>(<span class="string">&#x27;terser-webpack-plugin&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = &#123;</span><br><span class="line">  <span class="attr">configureWebpack</span>: &#123;</span><br><span class="line">    <span class="attr">optimization</span>: &#123;</span><br><span class="line">      <span class="attr">minimizer</span>: [</span><br><span class="line">        <span class="keyword">new</span> <span class="title class_">TerserPlugin</span>(&#123;</span><br><span class="line">          <span class="attr">terserOptions</span>: &#123;</span><br><span class="line">            <span class="attr">compress</span>: &#123;</span><br><span class="line">              <span class="attr">drop_console</span>: <span class="literal">true</span>, <span class="comment">// 移除console</span></span><br><span class="line">              <span class="attr">pure_funcs</span>: [<span class="string">&#x27;console.log&#x27;</span>] <span class="comment">// 移除指定函数</span></span><br><span class="line">            &#125;,</span><br><span class="line">            <span class="attr">mangle</span>: &#123;</span><br><span class="line">              <span class="attr">safari10</span>: <span class="literal">true</span> <span class="comment">// 兼容safari10</span></span><br><span class="line">            &#125;,</span><br><span class="line">            <span class="attr">output</span>: &#123;</span><br><span class="line">              <span class="attr">ascii_only</span>: <span class="literal">true</span>, <span class="comment">// 输出ASCII字符</span></span><br><span class="line">              <span class="attr">comments</span>: <span class="literal">false</span> <span class="comment">// 移除注释</span></span><br><span class="line">            &#125;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;)</span><br><span class="line">      ]</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3-2-源码加密"><a href="#3-2-源码加密" class="headerlink" title="3.2 源码加密"></a>3.2 源码加密</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/code-protection.js</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">CodeProtection</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">isDebug</span> = <span class="literal">false</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">init</span>()</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 初始化</span></span><br><span class="line">  <span class="title function_">init</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="comment">// 检测调试模式</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">checkDebugger</span>()</span><br><span class="line">    <span class="comment">// 禁用控制台</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">disableConsole</span>()</span><br><span class="line">    <span class="comment">// 禁用右键菜单</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">disableContextMenu</span>()</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 检测调试模式</span></span><br><span class="line">  <span class="title function_">checkDebugger</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="built_in">setInterval</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> startTime = <span class="title class_">Date</span>.<span class="title function_">now</span>()</span><br><span class="line">      <span class="keyword">debugger</span></span><br><span class="line">      <span class="keyword">const</span> endTime = <span class="title class_">Date</span>.<span class="title function_">now</span>()</span><br><span class="line">      </span><br><span class="line">      <span class="keyword">if</span> (endTime - startTime &gt; <span class="number">100</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">isDebug</span> = <span class="literal">true</span></span><br><span class="line">        <span class="comment">// 检测到调试行为</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">handleDebug</span>()</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;, <span class="number">1000</span>)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 禁用控制台</span></span><br><span class="line">  <span class="title function_">disableConsole</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="comment">// #ifdef H5</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> <span class="title function_">noop</span> = (<span class="params"></span>) =&gt; &#123;&#125;</span><br><span class="line">      <span class="keyword">const</span> methods = [</span><br><span class="line">        <span class="string">&#x27;log&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;debug&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;info&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;warn&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;error&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;assert&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;dir&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;dirxml&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;trace&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;group&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;groupEnd&#x27;</span></span><br><span class="line">      ]</span><br><span class="line">      </span><br><span class="line">      methods.<span class="title function_">forEach</span>(<span class="function"><span class="params">method</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>[method] = noop</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;&#125;</span><br><span class="line">    <span class="comment">// #endif</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 禁用右键菜单</span></span><br><span class="line">  <span class="title function_">disableContextMenu</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="comment">// #ifdef H5</span></span><br><span class="line">    <span class="variable language_">document</span>.<span class="property">oncontextmenu</span> = <span class="function">() =&gt;</span> <span class="literal">false</span></span><br><span class="line">    <span class="comment">// #endif</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 处理调试行为</span></span><br><span class="line">  <span class="title function_">handleDebug</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">isDebug</span>) &#123;</span><br><span class="line">      <span class="comment">// 退出应用</span></span><br><span class="line">      <span class="comment">// #ifdef APP-PLUS</span></span><br><span class="line">      plus.<span class="property">runtime</span>.<span class="title function_">quit</span>()</span><br><span class="line">      <span class="comment">// #endif</span></span><br><span class="line">      </span><br><span class="line">      <span class="comment">// 返回首页</span></span><br><span class="line">      <span class="comment">// #ifdef H5 || MP</span></span><br><span class="line">      uni.<span class="title function_">reLaunch</span>(&#123;</span><br><span class="line">        <span class="attr">url</span>: <span class="string">&#x27;/pages/index/index&#x27;</span></span><br><span class="line">      &#125;)</span><br><span class="line">      <span class="comment">// #endif</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">CodeProtection</span>()</span><br></pre></td></tr></table></figure><h2 id="4-数据防护"><a href="#4-数据防护" class="headerlink" title="4. 数据防护"></a>4. 数据防护</h2><h3 id="4-1-防止SQL注入"><a href="#4-1-防止SQL注入" class="headerlink" title="4.1 防止SQL注入"></a>4.1 防止SQL注入</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/sql-escape.js</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">SqlEscape</span> &#123;</span><br><span class="line">  <span class="comment">// 转义SQL特殊字符</span></span><br><span class="line">  <span class="title function_">escape</span>(<span class="params">str</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> str !== <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> str</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> str.<span class="title function_">replace</span>(<span class="regexp">/[\0\n\r\b\t\\&#x27;&quot;\x1a]/g</span>, <span class="function"><span class="params">s</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">switch</span> (s) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;\0&#x27;</span>:</span><br><span class="line">          <span class="keyword">return</span> <span class="string">&#x27;\\0&#x27;</span></span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;\n&#x27;</span>:</span><br><span class="line">          <span class="keyword">return</span> <span class="string">&#x27;\\n&#x27;</span></span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;\r&#x27;</span>:</span><br><span class="line">          <span class="keyword">return</span> <span class="string">&#x27;\\r&#x27;</span></span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;\b&#x27;</span>:</span><br><span class="line">          <span class="keyword">return</span> <span class="string">&#x27;\\b&#x27;</span></span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;\t&#x27;</span>:</span><br><span class="line">          <span class="keyword">return</span> <span class="string">&#x27;\\t&#x27;</span></span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;\x1a&#x27;</span>:</span><br><span class="line">          <span class="keyword">return</span> <span class="string">&#x27;\\Z&#x27;</span></span><br><span class="line">        <span class="attr">default</span>:</span><br><span class="line">          <span class="keyword">return</span> <span class="string">&#x27;\\&#x27;</span> + s</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 验证SQL注入</span></span><br><span class="line">  <span class="title function_">validate</span>(<span class="params">str</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> pattern = <span class="regexp">/select|update|delete|exec|count|&#x27;|&quot;|=|;|&gt;|&lt;|%/i</span></span><br><span class="line">    <span class="keyword">return</span> !pattern.<span class="title function_">test</span>(str)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">SqlEscape</span>()</span><br></pre></td></tr></table></figure><h3 id="4-2-防止XSS攻击"><a href="#4-2-防止XSS攻击" class="headerlink" title="4.2 防止XSS攻击"></a>4.2 防止XSS攻击</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/xss-filter.js</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">XssFilter</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">rules</span> = &#123;</span><br><span class="line">      <span class="attr">whiteList</span>: &#123;</span><br><span class="line">        <span class="attr">a</span>: [<span class="string">&#x27;href&#x27;</span>, <span class="string">&#x27;title&#x27;</span>, <span class="string">&#x27;target&#x27;</span>],</span><br><span class="line">        <span class="attr">img</span>: [<span class="string">&#x27;src&#x27;</span>, <span class="string">&#x27;alt&#x27;</span>],</span><br><span class="line">        <span class="attr">p</span>: [],</span><br><span class="line">        <span class="attr">div</span>: [],</span><br><span class="line">        <span class="attr">span</span>: [],</span><br><span class="line">        <span class="attr">br</span>: [],</span><br><span class="line">        <span class="attr">strong</span>: [],</span><br><span class="line">        <span class="attr">em</span>: []</span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">stripIgnoreTag</span>: <span class="literal">true</span>,</span><br><span class="line">      <span class="attr">stripIgnoreTagBody</span>: [<span class="string">&#x27;script&#x27;</span>]</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 过滤HTML</span></span><br><span class="line">  <span class="title function_">filter</span>(<span class="params">html</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> html !== <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> html</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> html.<span class="title function_">replace</span>(<span class="regexp">/&lt;\/?[^&gt;]*&gt;/g</span>, <span class="string">&#x27;&#x27;</span>).<span class="title function_">replace</span>(<span class="regexp">/&amp;[^;]+;/g</span>, <span class="string">&#x27;&#x27;</span>)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 转义HTML</span></span><br><span class="line">  <span class="title function_">escape</span>(<span class="params">html</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> html.<span class="title function_">replace</span>(<span class="regexp">/[&amp;&lt;&gt;&quot;&#x27;]/g</span>, <span class="function"><span class="params">match</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> <span class="built_in">escape</span> = &#123;</span><br><span class="line">        <span class="string">&#x27;&amp;&#x27;</span>: <span class="string">&#x27;&amp;amp;&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;&lt;&#x27;</span>: <span class="string">&#x27;&amp;lt;&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;&gt;&#x27;</span>: <span class="string">&#x27;&amp;gt;&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;&quot;&#x27;</span>: <span class="string">&#x27;&amp;quot;&#x27;</span>,</span><br><span class="line">        <span class="string">&quot;&#x27;&quot;</span>: <span class="string">&#x27;&amp;#39;&#x27;</span></span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">escape</span>[match]</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 验证XSS</span></span><br><span class="line">  <span class="title function_">validate</span>(<span class="params">str</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> pattern = <span class="regexp">/&lt;script|javascript:|on\w+\s*=|style\s*=|href\s*=|alert\s*\(|confirm\s*\(|prompt\s*\(/i</span></span><br><span class="line">    <span class="keyword">return</span> !pattern.<span class="title function_">test</span>(str)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">XssFilter</span>()</span><br></pre></td></tr></table></figure><h2 id="5-最佳实践建议"><a href="#5-最佳实践建议" class="headerlink" title="5. 最佳实践建议"></a>5. 最佳实践建议</h2><ol><li>使用HTTPS通信</li><li>实现请求签名</li><li>加密敏感数据</li><li>防止代码泄露</li><li>做好数据校验</li><li>定期安全审计</li><li>及时更新依赖</li><li>记录安全日志</li></ol><h2 id="6-安全监控"><a href="#6-安全监控" class="headerlink" title="6. 安全监控"></a>6. 安全监控</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/security-monitor.js</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">SecurityMonitor</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">logs</span> = []</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">maxLogs</span> = <span class="number">1000</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 记录安全日志</span></span><br><span class="line">  <span class="title function_">log</span>(<span class="params">type, data</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> log = &#123;</span><br><span class="line">      type,</span><br><span class="line">      data,</span><br><span class="line">      <span class="attr">time</span>: <span class="title class_">Date</span>.<span class="title function_">now</span>(),</span><br><span class="line">      <span class="attr">page</span>: <span class="variable language_">this</span>.<span class="title function_">getCurrentPage</span>()</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">logs</span>.<span class="title function_">push</span>(log)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 超出限制清理旧日志</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">logs</span>.<span class="property">length</span> &gt; <span class="variable language_">this</span>.<span class="property">maxLogs</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">logs</span> = <span class="variable language_">this</span>.<span class="property">logs</span>.<span class="title function_">slice</span>(-<span class="variable language_">this</span>.<span class="property">maxLogs</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 上报日志</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">report</span>(log)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 获取当前页面</span></span><br><span class="line">  <span class="title function_">getCurrentPage</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> pages = <span class="title function_">getCurrentPages</span>()</span><br><span class="line">    <span class="keyword">const</span> page = pages[pages.<span class="property">length</span> - <span class="number">1</span>]</span><br><span class="line">    <span class="keyword">return</span> page ? page.<span class="property">route</span> : <span class="string">&#x27;&#x27;</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 上报日志</span></span><br><span class="line">  <span class="title function_">report</span>(<span class="params">log</span>) &#123;</span><br><span class="line">    uni.<span class="title function_">request</span>(&#123;</span><br><span class="line">      <span class="attr">url</span>: <span class="string">&#x27;/api/security/log&#x27;</span>,</span><br><span class="line">      <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">      <span class="attr">data</span>: log</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 获取日志</span></span><br><span class="line">  <span class="title function_">getLogs</span>(<span class="params">type</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (type) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">logs</span>.<span class="title function_">filter</span>(<span class="function"><span class="params">log</span> =&gt;</span> log.<span class="property">type</span> === type)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">logs</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 清理日志</span></span><br><span class="line">  <span class="title function_">clearLogs</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">logs</span> = []</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">SecurityMonitor</span>()</span><br></pre></td></tr></table></figure><h2 id="7-总结"><a href="#7-总结" class="headerlink" title="7. 总结"></a>7. 总结</h2><ol><li>实现数据加密</li><li>保护网络安全</li><li>防护代码泄露</li><li>过滤危险数据</li><li>监控安全风险</li></ol><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">深入探讨uni-app应用的安全防护策略,包括数据加密、防护策略、安全防范等内容,帮助开发者构建安全可靠的跨端应用。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="安全防护" scheme="https://www.hzv5.cn/tags/%E5%AE%89%E5%85%A8%E9%98%B2%E6%8A%A4/"/>
    
    <category term="前端安全" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%AE%89%E5%85%A8/"/>
    
    <category term="数据加密" scheme="https://www.hzv5.cn/tags/%E6%95%B0%E6%8D%AE%E5%8A%A0%E5%AF%86/"/>
    
  </entry>
  
  <entry>
    <title>uni-app性能优化指南：从加载到渲染的全方位提升</title>
    <link href="https://www.hzv5.cn/2024/04/10/uniapp-optimization/"/>
    <id>https://www.hzv5.cn/2024/04/10/uniapp-optimization/</id>
    <published>2024-04-10T06:25:00.000Z</published>
    <updated>2024-04-10T06:25:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>性能优化是提升用户体验的关键因素,本文将从多个维度详细介绍uni-app应用的性能优化策略,帮助你构建流畅的跨端应用。</p></blockquote><span id="more"></span><h2 id="1-首屏加载优化"><a href="#1-首屏加载优化" class="headerlink" title="1. 首屏加载优化"></a>1. 首屏加载优化</h2><h3 id="1-1-分包加载"><a href="#1-1-分包加载" class="headerlink" title="1.1 分包加载"></a>1.1 分包加载</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// pages.json</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;pages&quot;</span>: [&#123;</span><br><span class="line">    <span class="string">&quot;path&quot;</span>: <span class="string">&quot;pages/index/index&quot;</span>,</span><br><span class="line">    <span class="string">&quot;style&quot;</span>: &#123;</span><br><span class="line">      <span class="string">&quot;navigationBarTitleText&quot;</span>: <span class="string">&quot;首页&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;],</span><br><span class="line">  <span class="string">&quot;subPackages&quot;</span>: [&#123;</span><br><span class="line">    <span class="string">&quot;root&quot;</span>: <span class="string">&quot;pagesA&quot;</span>,</span><br><span class="line">    <span class="string">&quot;pages&quot;</span>: [&#123;</span><br><span class="line">      <span class="string">&quot;path&quot;</span>: <span class="string">&quot;list/index&quot;</span>,</span><br><span class="line">      <span class="string">&quot;style&quot;</span>: &#123;</span><br><span class="line">        <span class="string">&quot;navigationBarTitleText&quot;</span>: <span class="string">&quot;列表页&quot;</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;]</span><br><span class="line">  &#125;]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 预加载分包</span></span><br><span class="line"><span class="title function_">onLoad</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="comment">// 进入首页时预加载分包</span></span><br><span class="line">  uni.<span class="title function_">preloadSubPackage</span>(&#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;pagesA&#x27;</span>,</span><br><span class="line">    <span class="attr">success</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;分包预加载成功&#x27;</span>)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">fail</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;分包预加载失败&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="1-2-图片优化"><a href="#1-2-图片优化" class="headerlink" title="1.2 图片优化"></a>1.2 图片优化</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;container&quot;&gt;</span><br><span class="line">    &lt;!-- 使用懒加载 --&gt;</span><br><span class="line">    &lt;image </span><br><span class="line">      v-for=&quot;(item, index) in images&quot; </span><br><span class="line">      :key=&quot;index&quot;</span><br><span class="line">      :src=&quot;item.url&quot;</span><br><span class="line">      :lazy-load=&quot;true&quot;</span><br><span class="line">      mode=&quot;aspectFill&quot;</span><br><span class="line">    /&gt;</span><br><span class="line">    </span><br><span class="line">    &lt;!-- 使用webp格式 --&gt;</span><br><span class="line">    &lt;image </span><br><span class="line">      :src=&quot;getWebpUrl(image.url)&quot;</span><br><span class="line">      mode=&quot;aspectFill&quot;</span><br><span class="line">    /&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  methods: &#123;</span><br><span class="line">    // 判断是否支持webp</span><br><span class="line">    checkWebp() &#123;</span><br><span class="line">      try &#123;</span><br><span class="line">        return document.createElement(&#x27;canvas&#x27;)</span><br><span class="line">          .toDataURL(&#x27;image/webp&#x27;)</span><br><span class="line">          .indexOf(&#x27;data:image/webp&#x27;) === 0</span><br><span class="line">      &#125; catch (e) &#123;</span><br><span class="line">        return false</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    </span><br><span class="line">    // 获取webp图片地址</span><br><span class="line">    getWebpUrl(url) &#123;</span><br><span class="line">      if (this.checkWebp()) &#123;</span><br><span class="line">        return url.replace(/\.(jpg|png)$/, &#x27;.webp&#x27;)</span><br><span class="line">      &#125;</span><br><span class="line">      return url</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="1-3-骨架屏"><a href="#1-3-骨架屏" class="headerlink" title="1.3 骨架屏"></a>1.3 骨架屏</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- components/skeleton.vue --&gt;</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;skeleton&quot; v-if=&quot;loading&quot;&gt;</span><br><span class="line">    &lt;view class=&quot;skeleton-header&quot;&gt;</span><br><span class="line">      &lt;view class=&quot;skeleton-avatar&quot;&gt;&lt;/view&gt;</span><br><span class="line">      &lt;view class=&quot;skeleton-content&quot;&gt;</span><br><span class="line">        &lt;view class=&quot;skeleton-title&quot;&gt;&lt;/view&gt;</span><br><span class="line">        &lt;view class=&quot;skeleton-desc&quot;&gt;&lt;/view&gt;</span><br><span class="line">      &lt;/view&gt;</span><br><span class="line">    &lt;/view&gt;</span><br><span class="line">    &lt;view class=&quot;skeleton-list&quot;&gt;</span><br><span class="line">      &lt;view </span><br><span class="line">        class=&quot;skeleton-item&quot;</span><br><span class="line">        v-for=&quot;i in 5&quot;</span><br><span class="line">        :key=&quot;i&quot;</span><br><span class="line">      &gt;&lt;/view&gt;</span><br><span class="line">    &lt;/view&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang=&quot;scss&quot;&gt;</span><br><span class="line">.skeleton &#123;</span><br><span class="line">  padding: 20rpx;</span><br><span class="line">  </span><br><span class="line">  &amp;-header &#123;</span><br><span class="line">    display: flex;</span><br><span class="line">    margin-bottom: 30rpx;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;-avatar &#123;</span><br><span class="line">    width: 100rpx;</span><br><span class="line">    height: 100rpx;</span><br><span class="line">    border-radius: 50%;</span><br><span class="line">    background: #f0f0f0;</span><br><span class="line">    margin-right: 20rpx;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;-content &#123;</span><br><span class="line">    flex: 1;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;-title &#123;</span><br><span class="line">    width: 60%;</span><br><span class="line">    height: 40rpx;</span><br><span class="line">    background: #f0f0f0;</span><br><span class="line">    margin-bottom: 20rpx;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;-desc &#123;</span><br><span class="line">    width: 80%;</span><br><span class="line">    height: 32rpx;</span><br><span class="line">    background: #f0f0f0;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;-item &#123;</span><br><span class="line">    height: 160rpx;</span><br><span class="line">    background: #f0f0f0;</span><br><span class="line">    margin-bottom: 20rpx;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;-avatar,</span><br><span class="line">  &amp;-title,</span><br><span class="line">  &amp;-desc,</span><br><span class="line">  &amp;-item &#123;</span><br><span class="line">    animation: skeleton-loading 1.4s ease infinite;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">@keyframes skeleton-loading &#123;</span><br><span class="line">  0% &#123;</span><br><span class="line">    opacity: 1;</span><br><span class="line">  &#125;</span><br><span class="line">  50% &#123;</span><br><span class="line">    opacity: 0.5;</span><br><span class="line">  &#125;</span><br><span class="line">  100% &#123;</span><br><span class="line">    opacity: 1;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure><h2 id="2-渲染性能优化"><a href="#2-渲染性能优化" class="headerlink" title="2. 渲染性能优化"></a>2. 渲染性能优化</h2><h3 id="2-1-长列表优化"><a href="#2-1-长列表优化" class="headerlink" title="2.1 长列表优化"></a>2.1 长列表优化</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;list-container&quot;&gt;</span><br><span class="line">    &lt;!-- 虚拟列表 --&gt;</span><br><span class="line">    &lt;recycle-list</span><br><span class="line">      :list=&quot;list&quot;</span><br><span class="line">      :height=&quot;listHeight&quot;</span><br><span class="line">      :item-height=&quot;itemHeight&quot;</span><br><span class="line">      :buffer-scale=&quot;1&quot;</span><br><span class="line">    &gt;</span><br><span class="line">      &lt;template v-slot=&quot;&#123; item &#125;&quot;&gt;</span><br><span class="line">        &lt;view class=&quot;list-item&quot;&gt;</span><br><span class="line">          &#123;&#123; item.title &#125;&#125;</span><br><span class="line">        &lt;/view&gt;</span><br><span class="line">      &lt;/template&gt;</span><br><span class="line">    &lt;/recycle-list&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">import RecycleList from &#x27;@/components/recycle-list&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  components: &#123;</span><br><span class="line">    RecycleList</span><br><span class="line">  &#125;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      list: [],</span><br><span class="line">      listHeight: 600,</span><br><span class="line">      itemHeight: 100</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    // 分页加载数据</span><br><span class="line">    async loadData(page = 1) &#123;</span><br><span class="line">      const &#123; list &#125; = await this.$api.getList(&#123; page &#125;)</span><br><span class="line">      this.list = [...this.list, ...list]</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="2-2-避免频繁更新"><a href="#2-2-避免频繁更新" class="headerlink" title="2.2 避免频繁更新"></a>2.2 避免频繁更新</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      timer: null,</span><br><span class="line">      count: 0</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    // 使用节流</span><br><span class="line">    throttleUpdate() &#123;</span><br><span class="line">      if (this.timer) return</span><br><span class="line">      this.timer = setTimeout(() =&gt; &#123;</span><br><span class="line">        this.count++</span><br><span class="line">        this.timer = null</span><br><span class="line">      &#125;, 16)</span><br><span class="line">    &#125;,</span><br><span class="line">    </span><br><span class="line">    // 使用requestAnimationFrame</span><br><span class="line">    rafUpdate() &#123;</span><br><span class="line">      requestAnimationFrame(() =&gt; &#123;</span><br><span class="line">        this.count++</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  beforeDestroy() &#123;</span><br><span class="line">    // 清理定时器</span><br><span class="line">    if (this.timer) &#123;</span><br><span class="line">      clearTimeout(this.timer)</span><br><span class="line">      this.timer = null</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h2 id="3-内存优化"><a href="#3-内存优化" class="headerlink" title="3. 内存优化"></a>3. 内存优化</h2><h3 id="3-1-及时清理资源"><a href="#3-1-及时清理资源" class="headerlink" title="3.1 及时清理资源"></a>3.1 及时清理资源</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="title function_">data</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">observer</span>: <span class="literal">null</span>,</span><br><span class="line">      <span class="attr">listeners</span>: []</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="title function_">initObserver</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">observer</span> = <span class="keyword">new</span> <span class="title class_">IntersectionObserver</span>(<span class="function"><span class="params">entries</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="comment">// 处理逻辑</span></span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="title function_">addListener</span>(<span class="params">element, event, handler</span>) &#123;</span><br><span class="line">      element.<span class="title function_">addEventListener</span>(event, handler)</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">listeners</span>.<span class="title function_">push</span>(&#123; element, event, handler &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="title function_">beforeDestroy</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="comment">// 清理观察者</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">observer</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">observer</span>.<span class="title function_">disconnect</span>()</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">observer</span> = <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 移除事件监听</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">listeners</span>.<span class="title function_">forEach</span>(<span class="function">(<span class="params">&#123; element, event, handler &#125;</span>) =&gt;</span> &#123;</span><br><span class="line">      element.<span class="title function_">removeEventListener</span>(event, handler)</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">listeners</span> = []</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3-2-缓存管理"><a href="#3-2-缓存管理" class="headerlink" title="3.2 缓存管理"></a>3.2 缓存管理</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/cache.js</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Cache</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">storage</span> = options.<span class="property">storage</span> || uni.<span class="property">getStorageSync</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">prefix</span> = options.<span class="property">prefix</span> || <span class="string">&#x27;cache_&#x27;</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">expire</span> = options.<span class="property">expire</span> || <span class="number">0</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 设置缓存</span></span><br><span class="line">  <span class="title function_">set</span>(<span class="params">key, value, expire = <span class="number">0</span></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> data = &#123;</span><br><span class="line">      value,</span><br><span class="line">      <span class="attr">expire</span>: expire ? <span class="title class_">Date</span>.<span class="title function_">now</span>() + expire * <span class="number">1000</span> : <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">storage</span>(<span class="variable language_">this</span>.<span class="property">prefix</span> + key, <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(data))</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 获取缓存</span></span><br><span class="line">  <span class="title function_">get</span>(<span class="params">key</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> data = <span class="variable language_">this</span>.<span class="title function_">storage</span>(<span class="variable language_">this</span>.<span class="property">prefix</span> + key)</span><br><span class="line">    <span class="keyword">if</span> (!data) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> &#123; value, expire &#125; = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(data)</span><br><span class="line">      <span class="comment">// 判断是否过期</span></span><br><span class="line">      <span class="keyword">if</span> (expire &amp;&amp; expire &lt; <span class="title class_">Date</span>.<span class="title function_">now</span>()) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">remove</span>(key)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> value</span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 移除缓存</span></span><br><span class="line">  <span class="title function_">remove</span>(<span class="params">key</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">storage</span>(<span class="variable language_">this</span>.<span class="property">prefix</span> + key, <span class="string">&#x27;&#x27;</span>)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 清空缓存</span></span><br><span class="line">  <span class="title function_">clear</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> keys = uni.<span class="title function_">getStorageInfoSync</span>().<span class="property">keys</span></span><br><span class="line">    keys.<span class="title function_">forEach</span>(<span class="function"><span class="params">key</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (key.<span class="title function_">startsWith</span>(<span class="variable language_">this</span>.<span class="property">prefix</span>)) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">remove</span>(key.<span class="title function_">slice</span>(<span class="variable language_">this</span>.<span class="property">prefix</span>.<span class="property">length</span>))</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">Cache</span>()</span><br></pre></td></tr></table></figure><h2 id="4-网络优化"><a href="#4-网络优化" class="headerlink" title="4. 网络优化"></a>4. 网络优化</h2><h3 id="4-1-请求优化"><a href="#4-1-请求优化" class="headerlink" title="4.1 请求优化"></a>4.1 请求优化</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/request.js</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Request</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">queue</span> = <span class="keyword">new</span> <span class="title class_">Map</span>() <span class="comment">// 请求队列</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">cache</span> = <span class="keyword">new</span> <span class="title class_">Map</span>() <span class="comment">// 请求缓存</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 发送请求</span></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">request</span>(<span class="params">options</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> key = <span class="variable language_">this</span>.<span class="title function_">getRequestKey</span>(options)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 判断是否有相同请求在队列中</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">queue</span>.<span class="title function_">has</span>(key)) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">queue</span>.<span class="title function_">get</span>(key)</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 判断是否有缓存</span></span><br><span class="line">    <span class="keyword">if</span> (options.<span class="property">useCache</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> cached = <span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">get</span>(key)</span><br><span class="line">      <span class="keyword">if</span> (cached &amp;&amp; cached.<span class="property">expire</span> &gt; <span class="title class_">Date</span>.<span class="title function_">now</span>()) &#123;</span><br><span class="line">        <span class="keyword">return</span> cached.<span class="property">data</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 发送请求</span></span><br><span class="line">    <span class="keyword">const</span> promise = <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      uni.<span class="title function_">request</span>(&#123;</span><br><span class="line">        ...options,</span><br><span class="line">        <span class="attr">success</span>: <span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">          <span class="comment">// 缓存响应</span></span><br><span class="line">          <span class="keyword">if</span> (options.<span class="property">useCache</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">set</span>(key, &#123;</span><br><span class="line">              <span class="attr">data</span>: res.<span class="property">data</span>,</span><br><span class="line">              <span class="attr">expire</span>: <span class="title class_">Date</span>.<span class="title function_">now</span>() + (options.<span class="property">cacheTime</span> || <span class="number">60000</span>)</span><br><span class="line">            &#125;)</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="title function_">resolve</span>(res.<span class="property">data</span>)</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">fail</span>: reject,</span><br><span class="line">        <span class="attr">complete</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">          <span class="comment">// 请求完成后从队列移除</span></span><br><span class="line">          <span class="variable language_">this</span>.<span class="property">queue</span>.<span class="title function_">delete</span>(key)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 添加到队列</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">queue</span>.<span class="title function_">set</span>(key, promise)</span><br><span class="line">    <span class="keyword">return</span> promise</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 生成请求的唯一标识</span></span><br><span class="line">  <span class="title function_">getRequestKey</span>(<span class="params">options</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">`<span class="subst">$&#123;options.url&#125;</span>:<span class="subst">$&#123;<span class="built_in">JSON</span>.stringify(options.data)&#125;</span>`</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">Request</span>()</span><br></pre></td></tr></table></figure><h3 id="4-2-离线缓存"><a href="#4-2-离线缓存" class="headerlink" title="4.2 离线缓存"></a>4.2 离线缓存</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/offline.js</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">OfflineStorage</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">version</span> = <span class="string">&#x27;1.0.0&#x27;</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">table</span> = <span class="string">&#x27;offline_data&#x27;</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 初始化数据库</span></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">init</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      plus.<span class="property">sqlite</span>.<span class="title function_">openDatabase</span>(&#123;</span><br><span class="line">        <span class="attr">name</span>: <span class="string">&#x27;app.db&#x27;</span>,</span><br><span class="line">        <span class="attr">path</span>: <span class="string">&#x27;_doc/app.db&#x27;</span>,</span><br><span class="line">        <span class="attr">success</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">          <span class="variable language_">this</span>.<span class="title function_">createTable</span>()</span><br><span class="line">          <span class="title function_">resolve</span>()</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">fail</span>: reject</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 创建表</span></span><br><span class="line">  <span class="title function_">createTable</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> sql = <span class="string">`</span></span><br><span class="line"><span class="string">      CREATE TABLE IF NOT EXISTS <span class="subst">$&#123;<span class="variable language_">this</span>.table&#125;</span> (</span></span><br><span class="line"><span class="string">        id TEXT PRIMARY KEY,</span></span><br><span class="line"><span class="string">        data TEXT,</span></span><br><span class="line"><span class="string">        expire INTEGER,</span></span><br><span class="line"><span class="string">        version TEXT</span></span><br><span class="line"><span class="string">      )</span></span><br><span class="line"><span class="string">    `</span></span><br><span class="line">    plus.<span class="property">sqlite</span>.<span class="title function_">executeSql</span>(&#123;</span><br><span class="line">      <span class="attr">name</span>: <span class="string">&#x27;app.db&#x27;</span>,</span><br><span class="line">      sql</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 保存数据</span></span><br><span class="line">  <span class="title function_">save</span>(<span class="params">key, data, expire = <span class="number">0</span></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> sql = <span class="string">`</span></span><br><span class="line"><span class="string">      REPLACE INTO <span class="subst">$&#123;<span class="variable language_">this</span>.table&#125;</span> (id, data, expire, version)</span></span><br><span class="line"><span class="string">      VALUES (?, ?, ?, ?)</span></span><br><span class="line"><span class="string">    `</span></span><br><span class="line">    <span class="keyword">const</span> values = [</span><br><span class="line">      key,</span><br><span class="line">      <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(data),</span><br><span class="line">      expire ? <span class="title class_">Date</span>.<span class="title function_">now</span>() + expire * <span class="number">1000</span> : <span class="number">0</span>,</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">version</span></span><br><span class="line">    ]</span><br><span class="line">    </span><br><span class="line">    plus.<span class="property">sqlite</span>.<span class="title function_">executeSql</span>(&#123;</span><br><span class="line">      <span class="attr">name</span>: <span class="string">&#x27;app.db&#x27;</span>,</span><br><span class="line">      sql,</span><br><span class="line">      values</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 获取数据</span></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">get</span>(<span class="params">key</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> sql = <span class="string">`</span></span><br><span class="line"><span class="string">        SELECT * FROM <span class="subst">$&#123;<span class="variable language_">this</span>.table&#125;</span></span></span><br><span class="line"><span class="string">        WHERE id = ? AND version = ?</span></span><br><span class="line"><span class="string">      `</span></span><br><span class="line">      plus.<span class="property">sqlite</span>.<span class="title function_">selectSql</span>(&#123;</span><br><span class="line">        <span class="attr">name</span>: <span class="string">&#x27;app.db&#x27;</span>,</span><br><span class="line">        sql,</span><br><span class="line">        <span class="attr">values</span>: [key, <span class="variable language_">this</span>.<span class="property">version</span>],</span><br><span class="line">        <span class="attr">success</span>: <span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">          <span class="keyword">if</span> (!res.<span class="property">length</span>) &#123;</span><br><span class="line">            <span class="title function_">resolve</span>(<span class="literal">null</span>)</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">          &#125;</span><br><span class="line">          </span><br><span class="line">          <span class="keyword">const</span> &#123; data, expire &#125; = res[<span class="number">0</span>]</span><br><span class="line">          <span class="comment">// 判断是否过期</span></span><br><span class="line">          <span class="keyword">if</span> (expire &amp;&amp; expire &lt; <span class="title class_">Date</span>.<span class="title function_">now</span>()) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">remove</span>(key)</span><br><span class="line">            <span class="title function_">resolve</span>(<span class="literal">null</span>)</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">          &#125;</span><br><span class="line">          </span><br><span class="line">          <span class="title function_">resolve</span>(<span class="title class_">JSON</span>.<span class="title function_">parse</span>(data))</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">fail</span>: reject</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 移除数据</span></span><br><span class="line">  <span class="title function_">remove</span>(<span class="params">key</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> sql = <span class="string">`</span></span><br><span class="line"><span class="string">      DELETE FROM <span class="subst">$&#123;<span class="variable language_">this</span>.table&#125;</span></span></span><br><span class="line"><span class="string">      WHERE id = ?</span></span><br><span class="line"><span class="string">    `</span></span><br><span class="line">    plus.<span class="property">sqlite</span>.<span class="title function_">executeSql</span>(&#123;</span><br><span class="line">      <span class="attr">name</span>: <span class="string">&#x27;app.db&#x27;</span>,</span><br><span class="line">      sql,</span><br><span class="line">      <span class="attr">values</span>: [key]</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 清空数据</span></span><br><span class="line">  <span class="title function_">clear</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> sql = <span class="string">`</span></span><br><span class="line"><span class="string">      DELETE FROM <span class="subst">$&#123;<span class="variable language_">this</span>.table&#125;</span></span></span><br><span class="line"><span class="string">      WHERE version = ?</span></span><br><span class="line"><span class="string">    `</span></span><br><span class="line">    plus.<span class="property">sqlite</span>.<span class="title function_">executeSql</span>(&#123;</span><br><span class="line">      <span class="attr">name</span>: <span class="string">&#x27;app.db&#x27;</span>,</span><br><span class="line">      sql,</span><br><span class="line">      <span class="attr">values</span>: [<span class="variable language_">this</span>.<span class="property">version</span>]</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">OfflineStorage</span>()</span><br></pre></td></tr></table></figure><h2 id="5-最佳实践建议"><a href="#5-最佳实践建议" class="headerlink" title="5. 最佳实践建议"></a>5. 最佳实践建议</h2><ol><li>合理使用分包加载</li><li>优化图片加载策略</li><li>实现虚拟列表</li><li>避免频繁更新</li><li>及时清理资源</li><li>做好缓存管理</li><li>优化网络请求</li><li>实现离线缓存</li></ol><h2 id="6-性能监控"><a href="#6-性能监控" class="headerlink" title="6. 性能监控"></a>6. 性能监控</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/performance.js</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Performance</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">data</span> = &#123;</span><br><span class="line">      <span class="comment">// 页面性能</span></span><br><span class="line">      <span class="attr">page</span>: &#123;</span><br><span class="line">        <span class="attr">ready</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="attr">load</span>: <span class="number">0</span></span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="comment">// 接口性能</span></span><br><span class="line">      <span class="attr">api</span>: <span class="keyword">new</span> <span class="title class_">Map</span>(),</span><br><span class="line">      <span class="comment">// 资源性能</span></span><br><span class="line">      <span class="attr">resource</span>: <span class="keyword">new</span> <span class="title class_">Map</span>()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 记录页面性能</span></span><br><span class="line">  <span class="title function_">recordPage</span>(<span class="params">type, time</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">data</span>.<span class="property">page</span>[type] = time</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 记录接口性能</span></span><br><span class="line">  <span class="title function_">recordApi</span>(<span class="params">url, time</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> api = <span class="variable language_">this</span>.<span class="property">data</span>.<span class="property">api</span>.<span class="title function_">get</span>(url) || &#123;</span><br><span class="line">      <span class="attr">count</span>: <span class="number">0</span>,</span><br><span class="line">      <span class="attr">total</span>: <span class="number">0</span>,</span><br><span class="line">      <span class="attr">max</span>: <span class="number">0</span>,</span><br><span class="line">      <span class="attr">min</span>: <span class="title class_">Infinity</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    api.<span class="property">count</span>++</span><br><span class="line">    api.<span class="property">total</span> += time</span><br><span class="line">    api.<span class="property">max</span> = <span class="title class_">Math</span>.<span class="title function_">max</span>(api.<span class="property">max</span>, time)</span><br><span class="line">    api.<span class="property">min</span> = <span class="title class_">Math</span>.<span class="title function_">min</span>(api.<span class="property">min</span>, time)</span><br><span class="line">    </span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">data</span>.<span class="property">api</span>.<span class="title function_">set</span>(url, api)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 记录资源性能</span></span><br><span class="line">  <span class="title function_">recordResource</span>(<span class="params">url, time</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">data</span>.<span class="property">resource</span>.<span class="title function_">set</span>(url, time)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 获取性能数据</span></span><br><span class="line">  <span class="title function_">getData</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; page, api, resource &#125; = <span class="variable language_">this</span>.<span class="property">data</span></span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      page,</span><br><span class="line">      <span class="attr">api</span>: <span class="title class_">Array</span>.<span class="title function_">from</span>(api.<span class="title function_">entries</span>()).<span class="title function_">map</span>(<span class="function">(<span class="params">[url, data]</span>) =&gt;</span> (&#123;</span><br><span class="line">        url,</span><br><span class="line">        ...data,</span><br><span class="line">        <span class="attr">avg</span>: data.<span class="property">total</span> / data.<span class="property">count</span></span><br><span class="line">      &#125;)),</span><br><span class="line">      <span class="attr">resource</span>: <span class="title class_">Array</span>.<span class="title function_">from</span>(resource.<span class="title function_">entries</span>()).<span class="title function_">map</span>(<span class="function">(<span class="params">[url, time]</span>) =&gt;</span> (&#123;</span><br><span class="line">        url,</span><br><span class="line">        time</span><br><span class="line">      &#125;))</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 上报性能数据</span></span><br><span class="line">  <span class="title function_">report</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> data = <span class="variable language_">this</span>.<span class="title function_">getData</span>()</span><br><span class="line">    <span class="comment">// 上报逻辑</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;性能数据:&#x27;</span>, data)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">Performance</span>()</span><br></pre></td></tr></table></figure><h2 id="7-总结"><a href="#7-总结" class="headerlink" title="7. 总结"></a>7. 总结</h2><ol><li>优化首屏加载</li><li>提升渲染性能</li><li>管理内存资源</li><li>优化网络请求</li><li>实现性能监控</li></ol><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">深入探讨uni-app应用的性能优化策略,包括首屏加载优化、渲染性能优化、内存管理、网络优化等多个维度,助你打造高性能的跨端应用。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="性能优化" scheme="https://www.hzv5.cn/tags/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
    
    <category term="小程序" scheme="https://www.hzv5.cn/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
    
  </entry>
  
  <entry>
    <title>uni-app动画效果实战：从基础到高级的动画实现指南</title>
    <link href="https://www.hzv5.cn/2024/04/05/uniapp-animation/"/>
    <id>https://www.hzv5.cn/2024/04/05/uniapp-animation/</id>
    <published>2024-04-05T01:15:00.000Z</published>
    <updated>2024-04-05T01:15:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>优秀的动画效果可以大大提升应用的用户体验,本文将详细介绍如何在uni-app中实现各种动画效果,助你打造出色的交互体验。</p></blockquote><span id="more"></span><h2 id="1-CSS动画基础"><a href="#1-CSS动画基础" class="headerlink" title="1. CSS动画基础"></a>1. CSS动画基础</h2><h3 id="1-1-过渡动画"><a href="#1-1-过渡动画" class="headerlink" title="1.1 过渡动画"></a>1.1 过渡动画</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;container&quot;&gt;</span><br><span class="line">    &lt;view </span><br><span class="line">      class=&quot;box&quot;</span><br><span class="line">      :class=&quot;&#123; active: isActive &#125;&quot;</span><br><span class="line">      @click=&quot;toggleActive&quot;</span><br><span class="line">    &gt;&lt;/view&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      isActive: false</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    toggleActive() &#123;</span><br><span class="line">      this.isActive = !this.isActive</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang=&quot;scss&quot;&gt;</span><br><span class="line">.box &#123;</span><br><span class="line">  width: 100rpx;</span><br><span class="line">  height: 100rpx;</span><br><span class="line">  background: #409eff;</span><br><span class="line">  transition: all 0.3s ease;</span><br><span class="line">  </span><br><span class="line">  &amp;.active &#123;</span><br><span class="line">    transform: scale(1.5) rotate(45deg);</span><br><span class="line">    background: #67c23a;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure><h3 id="1-2-关键帧动画"><a href="#1-2-关键帧动画" class="headerlink" title="1.2 关键帧动画"></a>1.2 关键帧动画</h3><figure class="highlight scss"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.loading</span> &#123;</span><br><span class="line">  <span class="attribute">width</span>: <span class="number">60</span>rpx;</span><br><span class="line">  <span class="attribute">height</span>: <span class="number">60</span>rpx;</span><br><span class="line">  <span class="attribute">border</span>: <span class="number">4</span>rpx solid <span class="number">#f3f3f3</span>;</span><br><span class="line">  <span class="attribute">border-top</span>: <span class="number">4</span>rpx solid <span class="number">#3498db</span>;</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="number">50%</span>;</span><br><span class="line">  <span class="attribute">animation</span>: spin <span class="number">1s</span> linear infinite;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@keyframes</span> spin &#123;</span><br><span class="line">  <span class="number">0%</span> &#123;</span><br><span class="line">    <span class="attribute">transform</span>: <span class="built_in">rotate</span>(<span class="number">0deg</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="number">100%</span> &#123;</span><br><span class="line">    <span class="attribute">transform</span>: <span class="built_in">rotate</span>(<span class="number">360deg</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.pulse</span> &#123;</span><br><span class="line">  <span class="attribute">width</span>: <span class="number">100</span>rpx;</span><br><span class="line">  <span class="attribute">height</span>: <span class="number">100</span>rpx;</span><br><span class="line">  <span class="attribute">background</span>: <span class="number">#409eff</span>;</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="number">50%</span>;</span><br><span class="line">  <span class="attribute">animation</span>: pulse <span class="number">2s</span> ease-in-out infinite;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@keyframes</span> pulse &#123;</span><br><span class="line">  <span class="number">0%</span> &#123;</span><br><span class="line">    <span class="attribute">transform</span>: <span class="built_in">scale</span>(<span class="number">1</span>);</span><br><span class="line">    <span class="attribute">opacity</span>: <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="number">50%</span> &#123;</span><br><span class="line">    <span class="attribute">transform</span>: <span class="built_in">scale</span>(<span class="number">1.5</span>);</span><br><span class="line">    <span class="attribute">opacity</span>: <span class="number">0.5</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="number">100%</span> &#123;</span><br><span class="line">    <span class="attribute">transform</span>: <span class="built_in">scale</span>(<span class="number">1</span>);</span><br><span class="line">    <span class="attribute">opacity</span>: <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="2-JS动画实现"><a href="#2-JS动画实现" class="headerlink" title="2. JS动画实现"></a>2. JS动画实现</h2><h3 id="2-1-使用animation对象"><a href="#2-1-使用animation对象" class="headerlink" title="2.1 使用animation对象"></a>2.1 使用animation对象</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/animation.js</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">createAnimation</span>(<span class="params">options = &#123;&#125;</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> uni.<span class="title function_">createAnimation</span>(&#123;</span><br><span class="line">    <span class="attr">duration</span>: options.<span class="property">duration</span> || <span class="number">300</span>,</span><br><span class="line">    <span class="attr">timingFunction</span>: options.<span class="property">timingFunction</span> || <span class="string">&#x27;ease&#x27;</span>,</span><br><span class="line">    <span class="attr">delay</span>: options.<span class="property">delay</span> || <span class="number">0</span>,</span><br><span class="line">    <span class="attr">transformOrigin</span>: options.<span class="property">transformOrigin</span> || <span class="string">&#x27;50% 50% 0&#x27;</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用示例</span></span><br><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">view</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">view</span> <span class="attr">:animation</span>=<span class="string">&quot;animationData&quot;</span> <span class="attr">class</span>=<span class="string">&quot;box&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">view</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">button</span> @<span class="attr">click</span>=<span class="string">&quot;startAnimation&quot;</span>&gt;</span>开始动画<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;/<span class="name">view</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> &#123; createAnimation &#125; <span class="keyword">from</span> <span class="string">&#x27;@/utils/animation&#x27;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="title function_">data</span>(<span class="params"></span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">return</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="attr">animation</span>: <span class="literal">null</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="attr">animationData</span>: &#123;&#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="attr">methods</span>: &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="title function_">startAnimation</span>(<span class="params"></span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="comment">// 创建动画实例</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="keyword">const</span> animation = <span class="title function_">createAnimation</span>()</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      </span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="comment">// 定义动画</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      animation</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        .<span class="title function_">scale</span>(<span class="number">1.5</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        .<span class="title function_">rotate</span>(<span class="number">45</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        .<span class="title function_">step</span>()</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        .<span class="title function_">scale</span>(<span class="number">1</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        .<span class="title function_">rotate</span>(<span class="number">0</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        .<span class="title function_">step</span>()</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      </span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="comment">// 导出动画数据</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="variable language_">this</span>.<span class="property">animationData</span> = animation.<span class="title function_">export</span>()</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br></pre></td></tr></table></figure><h3 id="2-2-requestAnimationFrame实现"><a href="#2-2-requestAnimationFrame实现" class="headerlink" title="2.2 requestAnimationFrame实现"></a>2.2 requestAnimationFrame实现</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/raf.js</span></span><br><span class="line"><span class="keyword">let</span> lastTime = <span class="number">0</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">raf</span> = callback =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> currTime = <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getTime</span>()</span><br><span class="line">  <span class="keyword">const</span> timeToCall = <span class="title class_">Math</span>.<span class="title function_">max</span>(<span class="number">0</span>, <span class="number">16</span> - (currTime - lastTime))</span><br><span class="line">  <span class="keyword">const</span> id = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="title function_">callback</span>(currTime + timeToCall)</span><br><span class="line">  &#125;, timeToCall)</span><br><span class="line">  lastTime = currTime + timeToCall</span><br><span class="line">  <span class="keyword">return</span> id</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">caf</span> = id =&gt; &#123;</span><br><span class="line">  <span class="built_in">clearTimeout</span>(id)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> requestAnimationFrame = <span class="keyword">typeof</span> <span class="variable language_">window</span> !== <span class="string">&#x27;undefined&#x27;</span> </span><br><span class="line">  ? <span class="variable language_">window</span>.<span class="property">requestAnimationFrame</span> || raf</span><br><span class="line">  : raf</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> cancelAnimationFrame = <span class="keyword">typeof</span> <span class="variable language_">window</span> !== <span class="string">&#x27;undefined&#x27;</span></span><br><span class="line">  ? <span class="variable language_">window</span>.<span class="property">cancelAnimationFrame</span> || caf</span><br><span class="line">  : caf</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用示例</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">Animator</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">duration</span> = options.<span class="property">duration</span> || <span class="number">300</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">easing</span> = options.<span class="property">easing</span> || (<span class="function"><span class="params">t</span> =&gt;</span> t)</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">running</span> = <span class="literal">false</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="title function_">animate</span>(<span class="params"><span class="keyword">from</span>, to, callback</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> startTime = <span class="title class_">Date</span>.<span class="title function_">now</span>()</span><br><span class="line">    <span class="keyword">const</span> change = to - <span class="keyword">from</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">update</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">      <span class="keyword">const</span> currentTime = <span class="title class_">Date</span>.<span class="title function_">now</span>()</span><br><span class="line">      <span class="keyword">const</span> elapsed = currentTime - startTime</span><br><span class="line">      <span class="keyword">const</span> progress = <span class="title class_">Math</span>.<span class="title function_">min</span>(elapsed / <span class="variable language_">this</span>.<span class="property">duration</span>, <span class="number">1</span>)</span><br><span class="line">      <span class="keyword">const</span> value = <span class="keyword">from</span> + change * <span class="variable language_">this</span>.<span class="title function_">easing</span>(progress)</span><br><span class="line">      </span><br><span class="line">      <span class="title function_">callback</span>(value)</span><br><span class="line">      </span><br><span class="line">      <span class="keyword">if</span> (progress &lt; <span class="number">1</span> &amp;&amp; <span class="variable language_">this</span>.<span class="property">running</span>) &#123;</span><br><span class="line">        <span class="title function_">requestAnimationFrame</span>(update)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">running</span> = <span class="literal">true</span></span><br><span class="line">    <span class="title function_">requestAnimationFrame</span>(update)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="title function_">stop</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">running</span> = <span class="literal">false</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用示例</span></span><br><span class="line"><span class="keyword">const</span> animator = <span class="keyword">new</span> <span class="title class_">Animator</span>(&#123;</span><br><span class="line">  <span class="attr">duration</span>: <span class="number">1000</span>,</span><br><span class="line">  <span class="attr">easing</span>: <span class="function"><span class="params">t</span> =&gt;</span> t * t <span class="comment">// 缓动函数</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">animator.<span class="title function_">animate</span>(<span class="number">0</span>, <span class="number">100</span>, <span class="function"><span class="params">value</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 更新元素位置</span></span><br><span class="line">  element.<span class="property">style</span>.<span class="property">transform</span> = <span class="string">`translateX(<span class="subst">$&#123;value&#125;</span>px)`</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h2 id="3-手势动画"><a href="#3-手势动画" class="headerlink" title="3. 手势动画"></a>3. 手势动画</h2><h3 id="3-1-拖拽动画"><a href="#3-1-拖拽动画" class="headerlink" title="3.1 拖拽动画"></a>3.1 拖拽动画</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;drag-container&quot;&gt;</span><br><span class="line">    &lt;view</span><br><span class="line">      class=&quot;drag-item&quot;</span><br><span class="line">      :style=&quot;itemStyle&quot;</span><br><span class="line">      @touchstart=&quot;handleTouchStart&quot;</span><br><span class="line">      @touchmove=&quot;handleTouchMove&quot;</span><br><span class="line">      @touchend=&quot;handleTouchEnd&quot;</span><br><span class="line">    &gt;</span><br><span class="line">      拖拽我</span><br><span class="line">    &lt;/view&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      startX: 0,</span><br><span class="line">      startY: 0,</span><br><span class="line">      moveX: 0,</span><br><span class="line">      moveY: 0,</span><br><span class="line">      isDragging: false</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  computed: &#123;</span><br><span class="line">    itemStyle() &#123;</span><br><span class="line">      if (!this.isDragging) &#123;</span><br><span class="line">        return &#123;</span><br><span class="line">          transform: `translate3d($&#123;this.moveX&#125;px, $&#123;this.moveY&#125;px, 0)`,</span><br><span class="line">          transition: &#x27;transform 0.3s&#x27;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      return &#123;</span><br><span class="line">        transform: `translate3d($&#123;this.moveX&#125;px, $&#123;this.moveY&#125;px, 0)`</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    handleTouchStart(e) &#123;</span><br><span class="line">      const touch = e.touches[0]</span><br><span class="line">      this.startX = touch.clientX - this.moveX</span><br><span class="line">      this.startY = touch.clientY - this.moveY</span><br><span class="line">      this.isDragging = true</span><br><span class="line">    &#125;,</span><br><span class="line">    handleTouchMove(e) &#123;</span><br><span class="line">      const touch = e.touches[0]</span><br><span class="line">      this.moveX = touch.clientX - this.startX</span><br><span class="line">      this.moveY = touch.clientY - this.startY</span><br><span class="line">      </span><br><span class="line">      // 防止页面滚动</span><br><span class="line">      e.preventDefault()</span><br><span class="line">    &#125;,</span><br><span class="line">    handleTouchEnd() &#123;</span><br><span class="line">      this.isDragging = false</span><br><span class="line">      </span><br><span class="line">      // 判断是否超出边界,如果是则回弹</span><br><span class="line">      const maxX = this.containerWidth - this.itemWidth</span><br><span class="line">      const maxY = this.containerHeight - this.itemHeight</span><br><span class="line">      </span><br><span class="line">      if (this.moveX &lt; 0) this.moveX = 0</span><br><span class="line">      if (this.moveY &lt; 0) this.moveY = 0</span><br><span class="line">      if (this.moveX &gt; maxX) this.moveX = maxX</span><br><span class="line">      if (this.moveY &gt; maxY) this.moveY = maxY</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang=&quot;scss&quot;&gt;</span><br><span class="line">.drag-container &#123;</span><br><span class="line">  position: relative;</span><br><span class="line">  width: 100%;</span><br><span class="line">  height: 500rpx;</span><br><span class="line">  background: #f5f5f5;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.drag-item &#123;</span><br><span class="line">  position: absolute;</span><br><span class="line">  width: 200rpx;</span><br><span class="line">  height: 200rpx;</span><br><span class="line">  background: #409eff;</span><br><span class="line">  color: #fff;</span><br><span class="line">  display: flex;</span><br><span class="line">  align-items: center;</span><br><span class="line">  justify-content: center;</span><br><span class="line">  user-select: none;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure><h3 id="3-2-滑动删除"><a href="#3-2-滑动删除" class="headerlink" title="3.2 滑动删除"></a>3.2 滑动删除</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;swipe-container&quot;&gt;</span><br><span class="line">    &lt;view</span><br><span class="line">      class=&quot;swipe-item&quot;</span><br><span class="line">      :style=&quot;itemStyle&quot;</span><br><span class="line">      @touchstart=&quot;handleTouchStart&quot;</span><br><span class="line">      @touchmove=&quot;handleTouchMove&quot;</span><br><span class="line">      @touchend=&quot;handleTouchEnd&quot;</span><br><span class="line">    &gt;</span><br><span class="line">      &lt;view class=&quot;swipe-content&quot;&gt;</span><br><span class="line">        列表项内容</span><br><span class="line">      &lt;/view&gt;</span><br><span class="line">      &lt;view class=&quot;swipe-actions&quot;&gt;</span><br><span class="line">        &lt;view class=&quot;swipe-btn delete&quot; @click=&quot;handleDelete&quot;&gt;删除&lt;/view&gt;</span><br><span class="line">      &lt;/view&gt;</span><br><span class="line">    &lt;/view&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">const THRESHOLD = 80 // 滑动阈值</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      startX: 0,</span><br><span class="line">      moveX: 0,</span><br><span class="line">      isMoving: false</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  computed: &#123;</span><br><span class="line">    itemStyle() &#123;</span><br><span class="line">      return &#123;</span><br><span class="line">        transform: `translate3d($&#123;this.moveX&#125;px, 0, 0)`,</span><br><span class="line">        transition: this.isMoving ? &#x27;&#x27; : &#x27;transform 0.3s&#x27;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    handleTouchStart(e) &#123;</span><br><span class="line">      this.startX = e.touches[0].clientX - this.moveX</span><br><span class="line">      this.isMoving = true</span><br><span class="line">    &#125;,</span><br><span class="line">    handleTouchMove(e) &#123;</span><br><span class="line">      const moveX = e.touches[0].clientX - this.startX</span><br><span class="line">      // 限制只能向左滑动</span><br><span class="line">      this.moveX = Math.min(0, moveX)</span><br><span class="line">    &#125;,</span><br><span class="line">    handleTouchEnd() &#123;</span><br><span class="line">      this.isMoving = false</span><br><span class="line">      // 判断是否超过阈值</span><br><span class="line">      if (Math.abs(this.moveX) &gt; THRESHOLD) &#123;</span><br><span class="line">        this.moveX = -100 // 展开删除按钮</span><br><span class="line">      &#125; else &#123;</span><br><span class="line">        this.moveX = 0 // 回弹</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    handleDelete() &#123;</span><br><span class="line">      // 删除逻辑</span><br><span class="line">      this.$emit(&#x27;delete&#x27;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang=&quot;scss&quot;&gt;</span><br><span class="line">.swipe-item &#123;</span><br><span class="line">  position: relative;</span><br><span class="line">  width: 100%;</span><br><span class="line">  height: 100rpx;</span><br><span class="line">  background: #fff;</span><br><span class="line">  </span><br><span class="line">  .swipe-content &#123;</span><br><span class="line">    height: 100%;</span><br><span class="line">    padding: 0 30rpx;</span><br><span class="line">    display: flex;</span><br><span class="line">    align-items: center;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  .swipe-actions &#123;</span><br><span class="line">    position: absolute;</span><br><span class="line">    top: 0;</span><br><span class="line">    right: 0;</span><br><span class="line">    height: 100%;</span><br><span class="line">    display: flex;</span><br><span class="line">    transform: translateX(100%);</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  .swipe-btn &#123;</span><br><span class="line">    width: 100rpx;</span><br><span class="line">    height: 100%;</span><br><span class="line">    display: flex;</span><br><span class="line">    align-items: center;</span><br><span class="line">    justify-content: center;</span><br><span class="line">    color: #fff;</span><br><span class="line">    </span><br><span class="line">    &amp;.delete &#123;</span><br><span class="line">      background: #f56c6c;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure><h2 id="4-高级动画技巧"><a href="#4-高级动画技巧" class="headerlink" title="4. 高级动画技巧"></a>4. 高级动画技巧</h2><h3 id="4-1-路由转场动画"><a href="#4-1-路由转场动画" class="headerlink" title="4.1 路由转场动画"></a>4.1 路由转场动画</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;page-container&quot;&gt;</span><br><span class="line">    &lt;view </span><br><span class="line">      class=&quot;page-wrapper&quot;</span><br><span class="line">      :class=&quot;transitionClass&quot;</span><br><span class="line">      :style=&quot;&#123; &#x27;z-index&#x27;: zIndex &#125;&quot;</span><br><span class="line">    &gt;</span><br><span class="line">      &lt;slot&gt;&lt;/slot&gt;</span><br><span class="line">    &lt;/view&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  props: &#123;</span><br><span class="line">    name: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;fade&#x27;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      transitionClass: &#x27;&#x27;,</span><br><span class="line">      zIndex: 1</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    enter() &#123;</span><br><span class="line">      this.zIndex = 2</span><br><span class="line">      this.transitionClass = `$&#123;this.name&#125;-enter`</span><br><span class="line">      requestAnimationFrame(() =&gt; &#123;</span><br><span class="line">        this.transitionClass = `$&#123;this.name&#125;-enter $&#123;this.name&#125;-enter-active`</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;,</span><br><span class="line">    leave() &#123;</span><br><span class="line">      this.zIndex = 1</span><br><span class="line">      this.transitionClass = `$&#123;this.name&#125;-leave`</span><br><span class="line">      requestAnimationFrame(() =&gt; &#123;</span><br><span class="line">        this.transitionClass = `$&#123;this.name&#125;-leave $&#123;this.name&#125;-leave-active`</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang=&quot;scss&quot;&gt;</span><br><span class="line">.page-container &#123;</span><br><span class="line">  position: relative;</span><br><span class="line">  width: 100%;</span><br><span class="line">  height: 100%;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.page-wrapper &#123;</span><br><span class="line">  position: absolute;</span><br><span class="line">  width: 100%;</span><br><span class="line">  height: 100%;</span><br><span class="line">  transition: all 0.3s;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 淡入淡出</span><br><span class="line">.fade-enter &#123;</span><br><span class="line">  opacity: 0;</span><br><span class="line">&#125;</span><br><span class="line">.fade-enter-active &#123;</span><br><span class="line">  opacity: 1;</span><br><span class="line">&#125;</span><br><span class="line">.fade-leave &#123;</span><br><span class="line">  opacity: 1;</span><br><span class="line">&#125;</span><br><span class="line">.fade-leave-active &#123;</span><br><span class="line">  opacity: 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 滑动</span><br><span class="line">.slide-enter &#123;</span><br><span class="line">  transform: translateX(100%);</span><br><span class="line">&#125;</span><br><span class="line">.slide-enter-active &#123;</span><br><span class="line">  transform: translateX(0);</span><br><span class="line">&#125;</span><br><span class="line">.slide-leave &#123;</span><br><span class="line">  transform: translateX(0);</span><br><span class="line">&#125;</span><br><span class="line">.slide-leave-active &#123;</span><br><span class="line">  transform: translateX(-100%);</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure><h3 id="4-2-列表动画"><a href="#4-2-列表动画" class="headerlink" title="4.2 列表动画"></a>4.2 列表动画</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;list-container&quot;&gt;</span><br><span class="line">    &lt;view</span><br><span class="line">      v-for=&quot;(item, index) in list&quot;</span><br><span class="line">      :key=&quot;item.id&quot;</span><br><span class="line">      class=&quot;list-item&quot;</span><br><span class="line">      :style=&quot;getItemStyle(index)&quot;</span><br><span class="line">    &gt;</span><br><span class="line">      &#123;&#123; item.text &#125;&#125;</span><br><span class="line">    &lt;/view&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      list: []</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    getItemStyle(index) &#123;</span><br><span class="line">      return &#123;</span><br><span class="line">        animation: `slideIn 0.3s ease-out $&#123;index * 0.1&#125;s both`</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    addItem() &#123;</span><br><span class="line">      this.list.push(&#123;</span><br><span class="line">        id: Date.now(),</span><br><span class="line">        text: &#x27;新项目&#x27;</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;,</span><br><span class="line">    removeItem(index) &#123;</span><br><span class="line">      this.list.splice(index, 1)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang=&quot;scss&quot;&gt;</span><br><span class="line">.list-item &#123;</span><br><span class="line">  height: 100rpx;</span><br><span class="line">  margin: 20rpx;</span><br><span class="line">  background: #fff;</span><br><span class="line">  border-radius: 8rpx;</span><br><span class="line">  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">@keyframes slideIn &#123;</span><br><span class="line">  from &#123;</span><br><span class="line">    opacity: 0;</span><br><span class="line">    transform: translateY(60rpx);</span><br><span class="line">  &#125;</span><br><span class="line">  to &#123;</span><br><span class="line">    opacity: 1;</span><br><span class="line">    transform: translateY(0);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure><h2 id="5-性能优化"><a href="#5-性能优化" class="headerlink" title="5. 性能优化"></a>5. 性能优化</h2><ol><li>使用transform代替位置属性</li><li>使用will-change提示浏览器</li><li>避免同时动画过多元素</li><li>适当使用硬件加速</li><li>合理设置动画帧率</li></ol><h2 id="6-最佳实践建议"><a href="#6-最佳实践建议" class="headerlink" title="6. 最佳实践建议"></a>6. 最佳实践建议</h2><ol><li>动画要有目的性</li><li>遵循物理运动规律</li><li>注意动画时长控制</li><li>提供动画开关选项</li><li>做好性能优化</li></ol><h2 id="7-总结"><a href="#7-总结" class="headerlink" title="7. 总结"></a>7. 总结</h2><ol><li>掌握动画基础知识</li><li>灵活运用多种实现方式</li><li>注意性能优化</li><li>提升用户体验</li><li>保持代码可维护性</li></ol><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">深入探讨uni-app中的动画效果实现方案,包括CSS动画、JS动画、手势动画等内容,帮助开发者打造流畅的动画交互体验。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="动画效果" scheme="https://www.hzv5.cn/tags/%E5%8A%A8%E7%94%BB%E6%95%88%E6%9E%9C/"/>
    
    <category term="CSS动画" scheme="https://www.hzv5.cn/tags/CSS%E5%8A%A8%E7%94%BB/"/>
    
    <category term="JS动画" scheme="https://www.hzv5.cn/tags/JS%E5%8A%A8%E7%94%BB/"/>
    
  </entry>
  
  <entry>
    <title>uni-app组件开发实战：从基础到进阶的最佳实践</title>
    <link href="https://www.hzv5.cn/2024/03/30/uniapp-component/"/>
    <id>https://www.hzv5.cn/2024/03/30/uniapp-component/</id>
    <published>2024-03-30T02:40:00.000Z</published>
    <updated>2024-03-30T02:40:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>组件化开发是现代前端的重要特征,本文将详细介绍如何在uni-app中开发高质量的UI组件,助你打造自己的组件库。</p></blockquote><span id="more"></span><h2 id="1-组件基础开发"><a href="#1-组件基础开发" class="headerlink" title="1. 组件基础开发"></a>1. 组件基础开发</h2><h3 id="1-1-组件目录结构"><a href="#1-1-组件目录结构" class="headerlink" title="1.1 组件目录结构"></a>1.1 组件目录结构</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">components</span><br><span class="line">├── base              <span class="comment"># 基础组件</span></span><br><span class="line">│   ├── button</span><br><span class="line">│   ├── input</span><br><span class="line">│   └── icon</span><br><span class="line">├── business          <span class="comment"># 业务组件</span></span><br><span class="line">│   ├── product-card</span><br><span class="line">│   ├── order-item</span><br><span class="line">│   └── user-info</span><br><span class="line">└── common           <span class="comment"># 公共组件</span></span><br><span class="line">    ├── loading</span><br><span class="line">    ├── empty</span><br><span class="line">    └── error</span><br></pre></td></tr></table></figure><h3 id="1-2-基础组件示例"><a href="#1-2-基础组件示例" class="headerlink" title="1.2 基础组件示例"></a>1.2 基础组件示例</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- components/base/button/index.vue --&gt;</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view </span><br><span class="line">    class=&quot;custom-button&quot;</span><br><span class="line">    :class=&quot;[</span><br><span class="line">      `custom-button--$&#123;type&#125;`,</span><br><span class="line">      `custom-button--$&#123;size&#125;`,</span><br><span class="line">      &#123;</span><br><span class="line">        &#x27;custom-button--plain&#x27;: plain,</span><br><span class="line">        &#x27;custom-button--disabled&#x27;: disabled,</span><br><span class="line">        &#x27;custom-button--loading&#x27;: loading</span><br><span class="line">      &#125;</span><br><span class="line">    ]&quot;</span><br><span class="line">    :hover-class=&quot;disabled ? &#x27;&#x27; : &#x27;custom-button--hover&#x27;&quot;</span><br><span class="line">    @click=&quot;handleClick&quot;</span><br><span class="line">  &gt;</span><br><span class="line">    &lt;view class=&quot;custom-button__content&quot;&gt;</span><br><span class="line">      &lt;text v-if=&quot;loading&quot; class=&quot;custom-button__loading&quot;&gt;&lt;/text&gt;</span><br><span class="line">      &lt;text v-if=&quot;icon&quot; class=&quot;custom-button__icon&quot; :class=&quot;icon&quot;&gt;&lt;/text&gt;</span><br><span class="line">      &lt;text class=&quot;custom-button__text&quot;&gt;&lt;slot&gt;&lt;/slot&gt;&lt;/text&gt;</span><br><span class="line">    &lt;/view&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;CustomButton&#x27;,</span><br><span class="line">  props: &#123;</span><br><span class="line">    // 按钮类型</span><br><span class="line">    type: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;default&#x27;,</span><br><span class="line">      validator: value =&gt; &#123;</span><br><span class="line">        return [&#x27;default&#x27;, &#x27;primary&#x27;, &#x27;success&#x27;, &#x27;warning&#x27;, &#x27;danger&#x27;].includes(value)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    // 按钮尺寸</span><br><span class="line">    size: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;normal&#x27;,</span><br><span class="line">      validator: value =&gt; &#123;</span><br><span class="line">        return [&#x27;small&#x27;, &#x27;normal&#x27;, &#x27;large&#x27;].includes(value)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    // 是否朴素按钮</span><br><span class="line">    plain: &#123;</span><br><span class="line">      type: Boolean,</span><br><span class="line">      default: false</span><br><span class="line">    &#125;,</span><br><span class="line">    // 是否禁用</span><br><span class="line">    disabled: &#123;</span><br><span class="line">      type: Boolean,</span><br><span class="line">      default: false</span><br><span class="line">    &#125;,</span><br><span class="line">    // 是否加载中</span><br><span class="line">    loading: &#123;</span><br><span class="line">      type: Boolean,</span><br><span class="line">      default: false</span><br><span class="line">    &#125;,</span><br><span class="line">    // 图标类名</span><br><span class="line">    icon: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;&#x27;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    handleClick(event) &#123;</span><br><span class="line">      if (this.disabled || this.loading) return</span><br><span class="line">      this.$emit(&#x27;click&#x27;, event)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang=&quot;scss&quot;&gt;</span><br><span class="line">.custom-button &#123;</span><br><span class="line">  position: relative;</span><br><span class="line">  display: inline-flex;</span><br><span class="line">  align-items: center;</span><br><span class="line">  justify-content: center;</span><br><span class="line">  padding: 0 30rpx;</span><br><span class="line">  font-size: 28rpx;</span><br><span class="line">  height: 80rpx;</span><br><span class="line">  line-height: 1;</span><br><span class="line">  text-align: center;</span><br><span class="line">  border-radius: 8rpx;</span><br><span class="line">  background: #fff;</span><br><span class="line">  border: 2rpx solid #dcdfe6;</span><br><span class="line">  box-sizing: border-box;</span><br><span class="line">  transition: all 0.3s;</span><br><span class="line">  </span><br><span class="line">  &amp;--hover &#123;</span><br><span class="line">    opacity: 0.8;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;--primary &#123;</span><br><span class="line">    color: #fff;</span><br><span class="line">    background: #409eff;</span><br><span class="line">    border-color: #409eff;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;--success &#123;</span><br><span class="line">    color: #fff;</span><br><span class="line">    background: #67c23a;</span><br><span class="line">    border-color: #67c23a;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;--warning &#123;</span><br><span class="line">    color: #fff;</span><br><span class="line">    background: #e6a23c;</span><br><span class="line">    border-color: #e6a23c;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;--danger &#123;</span><br><span class="line">    color: #fff;</span><br><span class="line">    background: #f56c6c;</span><br><span class="line">    border-color: #f56c6c;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;--plain &#123;</span><br><span class="line">    background: transparent;</span><br><span class="line">    </span><br><span class="line">    &amp;.custom-button--primary &#123;</span><br><span class="line">      color: #409eff;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    &amp;.custom-button--success &#123;</span><br><span class="line">      color: #67c23a;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    &amp;.custom-button--warning &#123;</span><br><span class="line">      color: #e6a23c;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    &amp;.custom-button--danger &#123;</span><br><span class="line">      color: #f56c6c;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;--disabled &#123;</span><br><span class="line">    opacity: 0.5;</span><br><span class="line">    cursor: not-allowed;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;--small &#123;</span><br><span class="line">    height: 60rpx;</span><br><span class="line">    padding: 0 20rpx;</span><br><span class="line">    font-size: 24rpx;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;--large &#123;</span><br><span class="line">    height: 100rpx;</span><br><span class="line">    padding: 0 40rpx;</span><br><span class="line">    font-size: 32rpx;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;__content &#123;</span><br><span class="line">    display: flex;</span><br><span class="line">    align-items: center;</span><br><span class="line">    justify-content: center;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;__loading &#123;</span><br><span class="line">    width: 28rpx;</span><br><span class="line">    height: 28rpx;</span><br><span class="line">    margin-right: 10rpx;</span><br><span class="line">    border: 2rpx solid currentColor;</span><br><span class="line">    border-radius: 50%;</span><br><span class="line">    border-right-color: transparent;</span><br><span class="line">    animation: button-loading 0.8s linear infinite;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &amp;__icon &#123;</span><br><span class="line">    margin-right: 10rpx;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">@keyframes button-loading &#123;</span><br><span class="line">  from &#123;</span><br><span class="line">    transform: rotate(0);</span><br><span class="line">  &#125;</span><br><span class="line">  to &#123;</span><br><span class="line">    transform: rotate(360deg);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure><h2 id="2-组件通信方式"><a href="#2-组件通信方式" class="headerlink" title="2. 组件通信方式"></a>2. 组件通信方式</h2><h3 id="2-1-Props-Events"><a href="#2-1-Props-Events" class="headerlink" title="2.1 Props/Events"></a>2.1 Props/Events</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 父组件 --&gt;</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;custom-form</span><br><span class="line">    :model=&quot;formData&quot;</span><br><span class="line">    :rules=&quot;formRules&quot;</span><br><span class="line">    @submit=&quot;handleSubmit&quot;</span><br><span class="line">  &gt;</span><br><span class="line">    &lt;custom-form-item label=&quot;用户名&quot; prop=&quot;username&quot;&gt;</span><br><span class="line">      &lt;custom-input v-model=&quot;formData.username&quot; /&gt;</span><br><span class="line">    &lt;/custom-form-item&gt;</span><br><span class="line">  &lt;/custom-form&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      formData: &#123;</span><br><span class="line">        username: &#x27;&#x27;</span><br><span class="line">      &#125;,</span><br><span class="line">      formRules: &#123;</span><br><span class="line">        username: [</span><br><span class="line">          &#123; required: true, message: &#x27;请输入用户名&#x27; &#125;</span><br><span class="line">        ]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    handleSubmit(values) &#123;</span><br><span class="line">      console.log(&#x27;表单提交:&#x27;, values)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="2-2-Provide-Inject"><a href="#2-2-Provide-Inject" class="headerlink" title="2.2 Provide/Inject"></a>2.2 Provide/Inject</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- components/form/index.vue --&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;CustomForm&#x27;,</span><br><span class="line">  provide() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      form: this</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  props: &#123;</span><br><span class="line">    model: &#123;</span><br><span class="line">      type: Object,</span><br><span class="line">      required: true</span><br><span class="line">    &#125;,</span><br><span class="line">    rules: &#123;</span><br><span class="line">      type: Object,</span><br><span class="line">      default: () =&gt; (&#123;&#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    validate(callback) &#123;</span><br><span class="line">      // 表单验证逻辑</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;!-- components/form-item/index.vue --&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;CustomFormItem&#x27;,</span><br><span class="line">  inject: [&#x27;form&#x27;],</span><br><span class="line">  props: &#123;</span><br><span class="line">    label: String,</span><br><span class="line">    prop: String</span><br><span class="line">  &#125;,</span><br><span class="line">  mounted() &#123;</span><br><span class="line">    if (this.prop) &#123;</span><br><span class="line">      this.form.fields.push(this)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h2 id="3-跨端适配"><a href="#3-跨端适配" class="headerlink" title="3. 跨端适配"></a>3. 跨端适配</h2><h3 id="3-1-条件编译"><a href="#3-1-条件编译" class="headerlink" title="3.1 条件编译"></a>3.1 条件编译</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;custom-input&quot;&gt;</span><br><span class="line">    &lt;!-- #ifdef MP --&gt;</span><br><span class="line">    &lt;input </span><br><span class="line">      :value=&quot;value&quot;</span><br><span class="line">      :type=&quot;type&quot;</span><br><span class="line">      :password=&quot;password&quot;</span><br><span class="line">      :placeholder=&quot;placeholder&quot;</span><br><span class="line">      :disabled=&quot;disabled&quot;</span><br><span class="line">      :maxlength=&quot;maxlength&quot;</span><br><span class="line">      @input=&quot;handleInput&quot;</span><br><span class="line">      @focus=&quot;handleFocus&quot;</span><br><span class="line">      @blur=&quot;handleBlur&quot;</span><br><span class="line">    /&gt;</span><br><span class="line">    &lt;!-- #endif --&gt;</span><br><span class="line">    </span><br><span class="line">    &lt;!-- #ifdef H5 --&gt;</span><br><span class="line">    &lt;input </span><br><span class="line">      v-model=&quot;inputValue&quot;</span><br><span class="line">      :type=&quot;type&quot;</span><br><span class="line">      :placeholder=&quot;placeholder&quot;</span><br><span class="line">      :disabled=&quot;disabled&quot;</span><br><span class="line">      :maxlength=&quot;maxlength&quot;</span><br><span class="line">      @focus=&quot;handleFocus&quot;</span><br><span class="line">      @blur=&quot;handleBlur&quot;</span><br><span class="line">    /&gt;</span><br><span class="line">    &lt;!-- #endif --&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;CustomInput&#x27;,</span><br><span class="line">  props: &#123;</span><br><span class="line">    value: String,</span><br><span class="line">    type: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;text&#x27;</span><br><span class="line">    &#125;,</span><br><span class="line">    password: Boolean,</span><br><span class="line">    placeholder: String,</span><br><span class="line">    disabled: Boolean,</span><br><span class="line">    maxlength: &#123;</span><br><span class="line">      type: Number,</span><br><span class="line">      default: -1</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      inputValue: this.value</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  watch: &#123;</span><br><span class="line">    value(val) &#123;</span><br><span class="line">      this.inputValue = val</span><br><span class="line">    &#125;,</span><br><span class="line">    inputValue(val) &#123;</span><br><span class="line">      this.$emit(&#x27;input&#x27;, val)</span><br><span class="line">      this.$emit(&#x27;change&#x27;, val)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    handleInput(e) &#123;</span><br><span class="line">      // #ifdef MP</span><br><span class="line">      const value = e.detail.value</span><br><span class="line">      // #endif</span><br><span class="line">      </span><br><span class="line">      // #ifdef H5</span><br><span class="line">      const value = e.target.value</span><br><span class="line">      // #endif</span><br><span class="line">      </span><br><span class="line">      this.inputValue = value</span><br><span class="line">    &#125;,</span><br><span class="line">    handleFocus(e) &#123;</span><br><span class="line">      this.$emit(&#x27;focus&#x27;, e)</span><br><span class="line">    &#125;,</span><br><span class="line">    handleBlur(e) &#123;</span><br><span class="line">      this.$emit(&#x27;blur&#x27;, e)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="3-2-样式适配"><a href="#3-2-样式适配" class="headerlink" title="3.2 样式适配"></a>3.2 样式适配</h3><figure class="highlight scss"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* styles/mixins.scss */</span></span><br><span class="line"><span class="comment">// 1px边框</span></span><br><span class="line"><span class="keyword">@mixin</span> hairline(<span class="variable">$position</span>: bottom, <span class="variable">$color</span>: <span class="number">#dcdfe6</span>) &#123;</span><br><span class="line">  <span class="attribute">position</span>: relative;</span><br><span class="line">  </span><br><span class="line">  &amp;<span class="selector-pseudo">::after</span> &#123;</span><br><span class="line">    <span class="attribute">content</span>: <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    <span class="attribute">position</span>: absolute;</span><br><span class="line">    #&#123;<span class="variable">$position</span>&#125;: <span class="number">0</span>;</span><br><span class="line">    <span class="attribute">left</span>: <span class="number">0</span>;</span><br><span class="line">    <span class="attribute">width</span>: <span class="number">100%</span>;</span><br><span class="line">    <span class="attribute">height</span>: <span class="number">1px</span>;</span><br><span class="line">    <span class="attribute">background</span>: <span class="variable">$color</span>;</span><br><span class="line">    <span class="attribute">transform</span>: <span class="built_in">scaleY</span>(<span class="number">0.5</span>);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// #ifdef H5</span></span><br><span class="line">    <span class="keyword">@media</span> (<span class="attribute">-webkit-min-device-pixel-ratio</span>: <span class="number">2</span>) &#123;</span><br><span class="line">      <span class="attribute">transform</span>: <span class="built_in">scaleY</span>(<span class="number">0.5</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// #endif</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 安全区域</span></span><br><span class="line"><span class="keyword">@mixin</span> safe-area(<span class="variable">$position</span>: bottom) &#123;</span><br><span class="line">  <span class="comment">// #ifdef H5</span></span><br><span class="line">  <span class="attribute">padding</span>-#&#123;<span class="variable">$position</span>&#125;: <span class="built_in">constant</span>(safe-area-inset-#&#123;<span class="variable">$position</span>&#125;);</span><br><span class="line">  <span class="attribute">padding</span>-#&#123;<span class="variable">$position</span>&#125;: <span class="built_in">env</span>(safe-area-inset-#&#123;<span class="variable">$position</span>&#125;);</span><br><span class="line">  <span class="comment">// #endif</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment">// #ifdef MP</span></span><br><span class="line">  <span class="attribute">padding</span>-#&#123;<span class="variable">$position</span>&#125;: <span class="number">0</span>;</span><br><span class="line">  <span class="comment">// #endif</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="4-组件优化"><a href="#4-组件优化" class="headerlink" title="4. 组件优化"></a>4. 组件优化</h2><h3 id="4-1-性能优化"><a href="#4-1-性能优化" class="headerlink" title="4.1 性能优化"></a>4.1 性能优化</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;CustomList&#x27;,</span><br><span class="line">  props: &#123;</span><br><span class="line">    list: Array</span><br><span class="line">  &#125;,</span><br><span class="line">  // 避免不必要的更新</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      renderList: this.list.map(item =&gt; (&#123;</span><br><span class="line">        ...item,</span><br><span class="line">        _id: item.id</span><br><span class="line">      &#125;))</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  watch: &#123;</span><br><span class="line">    list: &#123;</span><br><span class="line">      handler(val) &#123;</span><br><span class="line">        this.renderList = val.map(item =&gt; (&#123;</span><br><span class="line">          ...item,</span><br><span class="line">          _id: item.id</span><br><span class="line">        &#125;))</span><br><span class="line">      &#125;,</span><br><span class="line">      deep: true</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="4-2-体验优化"><a href="#4-2-体验优化" class="headerlink" title="4.2 体验优化"></a>4.2 体验优化</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;custom-image&quot; :style=&quot;imageStyle&quot;&gt;</span><br><span class="line">    &lt;image</span><br><span class="line">      :src=&quot;src&quot;</span><br><span class="line">      :mode=&quot;mode&quot;</span><br><span class="line">      :lazy-load=&quot;lazyLoad&quot;</span><br><span class="line">      @load=&quot;handleLoad&quot;</span><br><span class="line">      @error=&quot;handleError&quot;</span><br><span class="line">    /&gt;</span><br><span class="line">    &lt;view v-if=&quot;loading&quot; class=&quot;custom-image__loading&quot;&gt;</span><br><span class="line">      &lt;text class=&quot;custom-image__loading-text&quot;&gt;加载中...&lt;/text&gt;</span><br><span class="line">    &lt;/view&gt;</span><br><span class="line">    &lt;view v-if=&quot;error&quot; class=&quot;custom-image__error&quot;&gt;</span><br><span class="line">      &lt;text class=&quot;custom-image__error-text&quot;&gt;加载失败&lt;/text&gt;</span><br><span class="line">    &lt;/view&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;CustomImage&#x27;,</span><br><span class="line">  props: &#123;</span><br><span class="line">    src: String,</span><br><span class="line">    mode: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;aspectFill&#x27;</span><br><span class="line">    &#125;,</span><br><span class="line">    width: &#123;</span><br><span class="line">      type: [String, Number],</span><br><span class="line">      default: &#x27;100%&#x27;</span><br><span class="line">    &#125;,</span><br><span class="line">    height: &#123;</span><br><span class="line">      type: [String, Number],</span><br><span class="line">      default: &#x27;100%&#x27;</span><br><span class="line">    &#125;,</span><br><span class="line">    lazyLoad: &#123;</span><br><span class="line">      type: Boolean,</span><br><span class="line">      default: true</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      loading: true,</span><br><span class="line">      error: false</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  computed: &#123;</span><br><span class="line">    imageStyle() &#123;</span><br><span class="line">      return &#123;</span><br><span class="line">        width: typeof this.width === &#x27;number&#x27; ? `$&#123;this.width&#125;rpx` : this.width,</span><br><span class="line">        height: typeof this.height === &#x27;number&#x27; ? `$&#123;this.height&#125;rpx` : this.height</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    handleLoad(e) &#123;</span><br><span class="line">      this.loading = false</span><br><span class="line">      this.$emit(&#x27;load&#x27;, e)</span><br><span class="line">    &#125;,</span><br><span class="line">    handleError(e) &#123;</span><br><span class="line">      this.loading = false</span><br><span class="line">      this.error = true</span><br><span class="line">      this.$emit(&#x27;error&#x27;, e)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h2 id="5-最佳实践建议"><a href="#5-最佳实践建议" class="headerlink" title="5. 最佳实践建议"></a>5. 最佳实践建议</h2><ol><li>组件命名规范</li><li>合理的目录结构</li><li>完善的文档说明</li><li>统一的样式规范</li><li>做好跨端适配</li></ol><h2 id="6-总结"><a href="#6-总结" class="headerlink" title="6. 总结"></a>6. 总结</h2><ol><li>掌握组件开发基础</li><li>实现组件通信</li><li>处理跨端适配</li><li>优化组件性能</li><li>提升用户体验</li></ol><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">深入探讨uni-app组件开发的最佳实践,包括基础组件封装、组件通信、跨端适配等内容,帮助开发者构建高质量的UI组件库。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="组件开发" scheme="https://www.hzv5.cn/tags/%E7%BB%84%E4%BB%B6%E5%BC%80%E5%8F%91/"/>
    
    <category term="UI组件" scheme="https://www.hzv5.cn/tags/UI%E7%BB%84%E4%BB%B6/"/>
    
  </entry>
  
  <entry>
    <title>uni-app网络请求与缓存策略：构建高效的数据层</title>
    <link href="https://www.hzv5.cn/2024/03/25/uniapp-network/"/>
    <id>https://www.hzv5.cn/2024/03/25/uniapp-network/</id>
    <published>2024-03-25T07:20:00.000Z</published>
    <updated>2024-03-25T07:20:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>网络请求和数据缓存是应用开发中的关键环节,本文将详细介绍如何在uni-app中构建高效可靠的数据层。</p></blockquote><span id="more"></span><h2 id="1-网络请求封装"><a href="#1-网络请求封装" class="headerlink" title="1. 网络请求封装"></a>1. 网络请求封装</h2><h3 id="1-1-基础请求类"><a href="#1-1-基础请求类" class="headerlink" title="1.1 基础请求类"></a>1.1 基础请求类</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/request.js</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Request</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">baseURL</span> = options.<span class="property">baseURL</span> || <span class="string">&#x27;&#x27;</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">timeout</span> = options.<span class="property">timeout</span> || <span class="number">60000</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">header</span> = options.<span class="property">header</span> || &#123;&#125;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">beforeRequest</span> = options.<span class="property">beforeRequest</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">afterRequest</span> = options.<span class="property">afterRequest</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 请求拦截</span></span><br><span class="line">  <span class="title function_">beforeRequest</span>(<span class="params">config</span>) &#123;</span><br><span class="line">    <span class="comment">// 添加token</span></span><br><span class="line">    <span class="keyword">const</span> token = uni.<span class="title function_">getStorageSync</span>(<span class="string">&#x27;token&#x27;</span>)</span><br><span class="line">    <span class="keyword">if</span> (token) &#123;</span><br><span class="line">      config.<span class="property">header</span>.<span class="property">Authorization</span> = <span class="string">`Bearer <span class="subst">$&#123;token&#125;</span>`</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> config</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 响应拦截</span></span><br><span class="line">  <span class="title function_">afterRequest</span>(<span class="params">response</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; statusCode, data &#125; = response</span><br><span class="line">    <span class="keyword">if</span> (statusCode &gt;= <span class="number">200</span> &amp;&amp; statusCode &lt; <span class="number">300</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> data</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">reject</span>(response)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 请求方法</span></span><br><span class="line">  <span class="title function_">request</span>(<span class="params">options = &#123;&#125;</span>) &#123;</span><br><span class="line">    options.<span class="property">baseURL</span> = options.<span class="property">baseURL</span> || <span class="variable language_">this</span>.<span class="property">baseURL</span></span><br><span class="line">    options.<span class="property">timeout</span> = options.<span class="property">timeout</span> || <span class="variable language_">this</span>.<span class="property">timeout</span></span><br><span class="line">    options.<span class="property">header</span> = &#123; ...<span class="variable language_">this</span>.<span class="property">header</span>, ...options.<span class="property">header</span> &#125;</span><br><span class="line">    options.<span class="property">method</span> = options.<span class="property">method</span> || <span class="string">&#x27;GET&#x27;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 请求拦截</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">beforeRequest</span>) &#123;</span><br><span class="line">      options = <span class="variable language_">this</span>.<span class="title function_">beforeRequest</span>(options)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      uni.<span class="title function_">request</span>(&#123;</span><br><span class="line">        ...options,</span><br><span class="line">        <span class="attr">url</span>: options.<span class="property">baseURL</span> + options.<span class="property">url</span>,</span><br><span class="line">        <span class="attr">success</span>: <span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">          <span class="comment">// 响应拦截</span></span><br><span class="line">          <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">afterRequest</span>) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">              <span class="keyword">const</span> data = <span class="variable language_">this</span>.<span class="title function_">afterRequest</span>(res)</span><br><span class="line">              <span class="title function_">resolve</span>(data)</span><br><span class="line">            &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">              <span class="title function_">reject</span>(error)</span><br><span class="line">            &#125;</span><br><span class="line">          &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="title function_">resolve</span>(res.<span class="property">data</span>)</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">fail</span>: <span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">          <span class="title function_">reject</span>(err)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 封装常用请求方法</span></span><br><span class="line">  <span class="title function_">get</span>(<span class="params">url, data = &#123;&#125;, options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">request</span>(&#123;</span><br><span class="line">      url,</span><br><span class="line">      data,</span><br><span class="line">      <span class="attr">method</span>: <span class="string">&#x27;GET&#x27;</span>,</span><br><span class="line">      ...options</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">post</span>(<span class="params">url, data = &#123;&#125;, options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">request</span>(&#123;</span><br><span class="line">      url,</span><br><span class="line">      data,</span><br><span class="line">      <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">      ...options</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">put</span>(<span class="params">url, data = &#123;&#125;, options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">request</span>(&#123;</span><br><span class="line">      url,</span><br><span class="line">      data,</span><br><span class="line">      <span class="attr">method</span>: <span class="string">&#x27;PUT&#x27;</span>,</span><br><span class="line">      ...options</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">delete</span>(<span class="params">url, data = &#123;&#125;, options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">request</span>(&#123;</span><br><span class="line">      url,</span><br><span class="line">      data,</span><br><span class="line">      <span class="attr">method</span>: <span class="string">&#x27;DELETE&#x27;</span>,</span><br><span class="line">      ...options</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">Request</span>(&#123;</span><br><span class="line">  <span class="attr">baseURL</span>: process.<span class="property">env</span>.<span class="property">VUE_APP_BASE_API</span>,</span><br><span class="line">  <span class="attr">timeout</span>: <span class="number">10000</span>,</span><br><span class="line">  <span class="attr">header</span>: &#123;</span><br><span class="line">    <span class="string">&#x27;Content-Type&#x27;</span>: <span class="string">&#x27;application/json&#x27;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="1-2-请求拦截器"><a href="#1-2-请求拦截器" class="headerlink" title="1.2 请求拦截器"></a>1.2 请求拦截器</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/interceptors.js</span></span><br><span class="line"><span class="keyword">import</span> store <span class="keyword">from</span> <span class="string">&#x27;@/store&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 请求队列</span></span><br><span class="line"><span class="keyword">let</span> requestQueue = []</span><br><span class="line"><span class="comment">// 是否正在刷新token</span></span><br><span class="line"><span class="keyword">let</span> isRefreshing = <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">requestInterceptor</span> = (<span class="params">config</span>) =&gt; &#123;</span><br><span class="line">  <span class="comment">// 添加token</span></span><br><span class="line">  <span class="keyword">const</span> token = uni.<span class="title function_">getStorageSync</span>(<span class="string">&#x27;token&#x27;</span>)</span><br><span class="line">  <span class="keyword">if</span> (token) &#123;</span><br><span class="line">    config.<span class="property">header</span>.<span class="property">Authorization</span> = <span class="string">`Bearer <span class="subst">$&#123;token&#125;</span>`</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> config</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">responseInterceptor</span> = <span class="keyword">async</span> (<span class="params">response</span>) =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> &#123; statusCode, data &#125; = response</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// token过期处理</span></span><br><span class="line">  <span class="keyword">if</span> (statusCode === <span class="number">401</span>) &#123;</span><br><span class="line">    <span class="comment">// 将请求添加到队列</span></span><br><span class="line">    <span class="keyword">const</span> retryRequest = <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve</span>) =&gt;</span> &#123;</span><br><span class="line">      requestQueue.<span class="title function_">push</span>(<span class="function">(<span class="params">token</span>) =&gt;</span> &#123;</span><br><span class="line">        config.<span class="property">header</span>.<span class="property">Authorization</span> = <span class="string">`Bearer <span class="subst">$&#123;token&#125;</span>`</span></span><br><span class="line">        <span class="title function_">resolve</span>(request.<span class="title function_">request</span>(config))</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 是否正在刷新token</span></span><br><span class="line">    <span class="keyword">if</span> (!isRefreshing) &#123;</span><br><span class="line">      isRefreshing = <span class="literal">true</span></span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 刷新token</span></span><br><span class="line">        <span class="keyword">const</span> &#123; token &#125; = <span class="keyword">await</span> store.<span class="title function_">dispatch</span>(<span class="string">&#x27;user/refreshToken&#x27;</span>)</span><br><span class="line">        <span class="comment">// 重试队列中的请求</span></span><br><span class="line">        requestQueue.<span class="title function_">forEach</span>(<span class="function"><span class="params">callback</span> =&gt;</span> <span class="title function_">callback</span>(token))</span><br><span class="line">        requestQueue = []</span><br><span class="line">        <span class="keyword">return</span> request.<span class="title function_">request</span>(config)</span><br><span class="line">      &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">        <span class="comment">// 刷新token失败,跳转登录页</span></span><br><span class="line">        store.<span class="title function_">dispatch</span>(<span class="string">&#x27;user/logout&#x27;</span>)</span><br><span class="line">        uni.<span class="title function_">navigateTo</span>(&#123;</span><br><span class="line">          <span class="attr">url</span>: <span class="string">&#x27;/pages/login/index&#x27;</span></span><br><span class="line">        &#125;)</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">reject</span>(error)</span><br><span class="line">      &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        isRefreshing = <span class="literal">false</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> retryRequest</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> data</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="2-数据缓存策略"><a href="#2-数据缓存策略" class="headerlink" title="2. 数据缓存策略"></a>2. 数据缓存策略</h2><h3 id="2-1-缓存管理类"><a href="#2-1-缓存管理类" class="headerlink" title="2.1 缓存管理类"></a>2.1 缓存管理类</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/cache.js</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Cache</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">prefix</span> = options.<span class="property">prefix</span> || <span class="string">&#x27;app_&#x27;</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">expire</span> = options.<span class="property">expire</span> || <span class="number">0</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">isEncrypt</span> = options.<span class="property">isEncrypt</span> || <span class="literal">false</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 设置缓存</span></span><br><span class="line">  <span class="title function_">setItem</span>(<span class="params">key, value, expire = <span class="number">0</span></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> data = &#123;</span><br><span class="line">      value,</span><br><span class="line">      <span class="attr">time</span>: <span class="title class_">Date</span>.<span class="title function_">now</span>(),</span><br><span class="line">      <span class="attr">expire</span>: expire || <span class="variable language_">this</span>.<span class="property">expire</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 加密处理</span></span><br><span class="line">    <span class="keyword">const</span> stringData = <span class="variable language_">this</span>.<span class="property">isEncrypt</span> </span><br><span class="line">      ? <span class="variable language_">this</span>.<span class="title function_">encrypt</span>(<span class="title class_">JSON</span>.<span class="title function_">stringify</span>(data))</span><br><span class="line">      : <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(data)</span><br><span class="line">      </span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      uni.<span class="title function_">setStorageSync</span>(<span class="variable language_">this</span>.<span class="property">prefix</span> + key, stringData)</span><br><span class="line">    &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;缓存设置失败:&#x27;</span>, error)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 获取缓存</span></span><br><span class="line">  <span class="title function_">getItem</span>(<span class="params">key</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> data = uni.<span class="title function_">getStorageSync</span>(<span class="variable language_">this</span>.<span class="property">prefix</span> + key)</span><br><span class="line">      <span class="keyword">if</span> (!data) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">      </span><br><span class="line">      <span class="comment">// 解密处理</span></span><br><span class="line">      <span class="keyword">const</span> storage = <span class="variable language_">this</span>.<span class="property">isEncrypt</span> </span><br><span class="line">        ? <span class="title class_">JSON</span>.<span class="title function_">parse</span>(<span class="variable language_">this</span>.<span class="title function_">decrypt</span>(data))</span><br><span class="line">        : <span class="title class_">JSON</span>.<span class="title function_">parse</span>(data)</span><br><span class="line">        </span><br><span class="line">      <span class="comment">// 过期判断</span></span><br><span class="line">      <span class="keyword">if</span> (storage.<span class="property">expire</span> &amp;&amp; <span class="title class_">Date</span>.<span class="title function_">now</span>() - storage.<span class="property">time</span> &gt; storage.<span class="property">expire</span> * <span class="number">1000</span>) &#123;</span><br><span class="line">        uni.<span class="title function_">removeStorageSync</span>(<span class="variable language_">this</span>.<span class="property">prefix</span> + key)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">      &#125;</span><br><span class="line">      </span><br><span class="line">      <span class="keyword">return</span> storage.<span class="property">value</span></span><br><span class="line">    &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;缓存获取失败:&#x27;</span>, error)</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 移除缓存</span></span><br><span class="line">  <span class="title function_">removeItem</span>(<span class="params">key</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      uni.<span class="title function_">removeStorageSync</span>(<span class="variable language_">this</span>.<span class="property">prefix</span> + key)</span><br><span class="line">    &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;缓存移除失败:&#x27;</span>, error)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 清空缓存</span></span><br><span class="line">  <span class="title function_">clear</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      uni.<span class="title function_">clearStorageSync</span>()</span><br><span class="line">    &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;缓存清空失败:&#x27;</span>, error)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 加密方法</span></span><br><span class="line">  <span class="title function_">encrypt</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="comment">// 实现加密逻辑</span></span><br><span class="line">    <span class="keyword">return</span> data</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 解密方法</span></span><br><span class="line">  <span class="title function_">decrypt</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="comment">// 实现解密逻辑</span></span><br><span class="line">    <span class="keyword">return</span> data</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">Cache</span>(&#123;</span><br><span class="line">  <span class="attr">prefix</span>: <span class="string">&#x27;app_&#x27;</span>,</span><br><span class="line">  <span class="attr">expire</span>: <span class="number">7</span> * <span class="number">24</span> * <span class="number">60</span> * <span class="number">60</span>, <span class="comment">// 默认7天过期</span></span><br><span class="line">  <span class="attr">isEncrypt</span>: process.<span class="property">env</span>.<span class="property">NODE_ENV</span> === <span class="string">&#x27;production&#x27;</span> <span class="comment">// 生产环境开启加密</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="2-2-数据预加载"><a href="#2-2-数据预加载" class="headerlink" title="2.2 数据预加载"></a>2.2 数据预加载</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/preload.js</span></span><br><span class="line"><span class="keyword">import</span> cache <span class="keyword">from</span> <span class="string">&#x27;./cache&#x27;</span></span><br><span class="line"><span class="keyword">import</span> request <span class="keyword">from</span> <span class="string">&#x27;./request&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Preload</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">tasks</span> = <span class="keyword">new</span> <span class="title class_">Map</span>()</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 添加预加载任务</span></span><br><span class="line">  <span class="title function_">add</span>(<span class="params">key, promiseCreator</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">tasks</span>.<span class="title function_">has</span>(key)) &#123;</span><br><span class="line">      <span class="keyword">const</span> task = <span class="title function_">promiseCreator</span>().<span class="title function_">then</span>(<span class="function"><span class="params">data</span> =&gt;</span> &#123;</span><br><span class="line">        cache.<span class="title function_">setItem</span>(key, data)</span><br><span class="line">        <span class="keyword">return</span> data</span><br><span class="line">      &#125;)</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">tasks</span>.<span class="title function_">set</span>(key, task)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">tasks</span>.<span class="title function_">get</span>(key)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 获取预加载数据</span></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">get</span>(<span class="params">key, promiseCreator</span>) &#123;</span><br><span class="line">    <span class="comment">// 优先从缓存获取</span></span><br><span class="line">    <span class="keyword">const</span> cached = cache.<span class="title function_">getItem</span>(key)</span><br><span class="line">    <span class="keyword">if</span> (cached) <span class="keyword">return</span> cached</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 其次从预加载任务获取</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">tasks</span>.<span class="title function_">has</span>(key)) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">tasks</span>.<span class="title function_">get</span>(key)</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 最后实时加载</span></span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">add</span>(key, promiseCreator)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 清除预加载任务</span></span><br><span class="line">  <span class="title function_">clear</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">tasks</span>.<span class="title function_">clear</span>()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> <span class="title class_">Preload</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用示例</span></span><br><span class="line"><span class="keyword">const</span> preload = <span class="keyword">new</span> <span class="title class_">Preload</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">// 预加载数据</span></span><br><span class="line">preload.<span class="title function_">add</span>(<span class="string">&#x27;userInfo&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> request.<span class="title function_">get</span>(<span class="string">&#x27;/api/user/info&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取数据</span></span><br><span class="line"><span class="keyword">const</span> userInfo = <span class="keyword">await</span> preload.<span class="title function_">get</span>(<span class="string">&#x27;userInfo&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> request.<span class="title function_">get</span>(<span class="string">&#x27;/api/user/info&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h2 id="3-实际应用示例"><a href="#3-实际应用示例" class="headerlink" title="3. 实际应用示例"></a>3. 实际应用示例</h2><h3 id="3-1-API封装"><a href="#3-1-API封装" class="headerlink" title="3.1 API封装"></a>3.1 API封装</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// api/user.js</span></span><br><span class="line"><span class="keyword">import</span> request <span class="keyword">from</span> <span class="string">&#x27;@/utils/request&#x27;</span></span><br><span class="line"><span class="keyword">import</span> cache <span class="keyword">from</span> <span class="string">&#x27;@/utils/cache&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">login</span>(<span class="params">data</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> request.<span class="title function_">post</span>(<span class="string">&#x27;/api/login&#x27;</span>, data)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">getUserInfo</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> cache.<span class="title function_">remember</span>(<span class="string">&#x27;user_info&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> request.<span class="title function_">get</span>(<span class="string">&#x27;/api/user/info&#x27;</span>)</span><br><span class="line">  &#125;, <span class="number">30</span> * <span class="number">60</span>) <span class="comment">// 缓存30分钟</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">updateUserInfo</span>(<span class="params">data</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> request.<span class="title function_">put</span>(<span class="string">&#x27;/api/user/info&#x27;</span>, data).<span class="title function_">then</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 更新后清除缓存</span></span><br><span class="line">    cache.<span class="title function_">removeItem</span>(<span class="string">&#x27;user_info&#x27;</span>)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3-2-数据预加载"><a href="#3-2-数据预加载" class="headerlink" title="3.2 数据预加载"></a>3.2 数据预加载</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// pages/index/index.vue</span></span><br><span class="line"><span class="keyword">import</span> preload <span class="keyword">from</span> <span class="string">&#x27;@/utils/preload&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="title function_">onLoad</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="comment">// 预加载下一页数据</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">preloadNextPage</span>()</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="title function_">preloadNextPage</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> nextPage = <span class="variable language_">this</span>.<span class="property">currentPage</span> + <span class="number">1</span></span><br><span class="line">      preload.<span class="title function_">add</span>(<span class="string">`list_page_<span class="subst">$&#123;nextPage&#125;</span>`</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> request.<span class="title function_">get</span>(<span class="string">&#x27;/api/list&#x27;</span>, &#123;</span><br><span class="line">          <span class="attr">page</span>: nextPage,</span><br><span class="line">          <span class="attr">size</span>: <span class="number">10</span></span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="keyword">async</span> <span class="title function_">loadNextPage</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> nextPage = <span class="variable language_">this</span>.<span class="property">currentPage</span> + <span class="number">1</span></span><br><span class="line">      <span class="keyword">const</span> data = <span class="keyword">await</span> preload.<span class="title function_">get</span>(<span class="string">`list_page_<span class="subst">$&#123;nextPage&#125;</span>`</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> request.<span class="title function_">get</span>(<span class="string">&#x27;/api/list&#x27;</span>, &#123;</span><br><span class="line">          <span class="attr">page</span>: nextPage,</span><br><span class="line">          <span class="attr">size</span>: <span class="number">10</span></span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;)</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">list</span>.<span class="title function_">push</span>(...data.<span class="property">list</span>)</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">currentPage</span> = nextPage</span><br><span class="line">      <span class="comment">// 继续预加载下一页</span></span><br><span class="line">      <span class="variable language_">this</span>.<span class="title function_">preloadNextPage</span>()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="4-最佳实践建议"><a href="#4-最佳实践建议" class="headerlink" title="4. 最佳实践建议"></a>4. 最佳实践建议</h2><ol><li>统一封装请求方法</li><li>实现请求拦截和响应拦截</li><li>合理使用数据缓存</li><li>实现数据预加载</li><li>注意安全性处理</li></ol><h2 id="5-总结"><a href="#5-总结" class="headerlink" title="5. 总结"></a>5. 总结</h2><ol><li>掌握请求封装技巧</li><li>实现数据缓存策略</li><li>优化数据加载体验</li><li>处理异常情况</li><li>保证数据安全性</li></ol><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">深入探讨uni-app中的网络请求与数据缓存方案,包括请求封装、拦截器配置、数据缓存策略等内容,帮助开发者构建可靠的数据层。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="网络请求" scheme="https://www.hzv5.cn/tags/%E7%BD%91%E7%BB%9C%E8%AF%B7%E6%B1%82/"/>
    
    <category term="数据缓存" scheme="https://www.hzv5.cn/tags/%E6%95%B0%E6%8D%AE%E7%BC%93%E5%AD%98/"/>
    
  </entry>
  
  <entry>
    <title>uni-app状态管理进阶：Vuex最佳实践与性能优化</title>
    <link href="https://www.hzv5.cn/2024/03/20/uniapp-state-management/"/>
    <id>https://www.hzv5.cn/2024/03/20/uniapp-state-management/</id>
    <published>2024-03-20T08:45:00.000Z</published>
    <updated>2024-03-20T08:45:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>状态管理是uni-app应用开发中的重要环节,本文将深入介绍Vuex在uni-app中的应用,以及如何构建高效的数据流方案。</p></blockquote><span id="more"></span><h2 id="1-Vuex基础配置"><a href="#1-Vuex基础配置" class="headerlink" title="1. Vuex基础配置"></a>1. Vuex基础配置</h2><h3 id="1-1-目录结构"><a href="#1-1-目录结构" class="headerlink" title="1.1 目录结构"></a>1.1 目录结构</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">store</span><br><span class="line">├── index.js          <span class="comment"># 入口文件</span></span><br><span class="line">├── state.js          <span class="comment"># 根级别的state</span></span><br><span class="line">├── mutations.js      <span class="comment"># 根级别的mutations</span></span><br><span class="line">├── actions.js        <span class="comment"># 根级别的actions</span></span><br><span class="line">├── getters.js        <span class="comment"># 根级别的getters</span></span><br><span class="line">└── modules          <span class="comment"># 模块目录</span></span><br><span class="line">    ├── user.js      <span class="comment"># 用户模块</span></span><br><span class="line">    ├── cart.js      <span class="comment"># 购物车模块</span></span><br><span class="line">    └── order.js     <span class="comment"># 订单模块</span></span><br></pre></td></tr></table></figure><h3 id="1-2-基础配置"><a href="#1-2-基础配置" class="headerlink" title="1.2 基础配置"></a>1.2 基础配置</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// store/index.js</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Vue</span> <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Vuex</span> <span class="keyword">from</span> <span class="string">&#x27;vuex&#x27;</span></span><br><span class="line"><span class="keyword">import</span> state <span class="keyword">from</span> <span class="string">&#x27;./state&#x27;</span></span><br><span class="line"><span class="keyword">import</span> mutations <span class="keyword">from</span> <span class="string">&#x27;./mutations&#x27;</span></span><br><span class="line"><span class="keyword">import</span> actions <span class="keyword">from</span> <span class="string">&#x27;./actions&#x27;</span></span><br><span class="line"><span class="keyword">import</span> getters <span class="keyword">from</span> <span class="string">&#x27;./getters&#x27;</span></span><br><span class="line"><span class="keyword">import</span> user <span class="keyword">from</span> <span class="string">&#x27;./modules/user&#x27;</span></span><br><span class="line"><span class="keyword">import</span> cart <span class="keyword">from</span> <span class="string">&#x27;./modules/cart&#x27;</span></span><br><span class="line"><span class="keyword">import</span> order <span class="keyword">from</span> <span class="string">&#x27;./modules/order&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="title class_">Vue</span>.<span class="title function_">use</span>(<span class="title class_">Vuex</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> store = <span class="keyword">new</span> <span class="title class_">Vuex</span>.<span class="title class_">Store</span>(&#123;</span><br><span class="line">  state,</span><br><span class="line">  mutations,</span><br><span class="line">  actions,</span><br><span class="line">  getters,</span><br><span class="line">  <span class="attr">modules</span>: &#123;</span><br><span class="line">    user,</span><br><span class="line">    cart,</span><br><span class="line">    order</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">strict</span>: process.<span class="property">env</span>.<span class="property">NODE_ENV</span> !== <span class="string">&#x27;production&#x27;</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> store</span><br></pre></td></tr></table></figure><h2 id="2-模块化设计"><a href="#2-模块化设计" class="headerlink" title="2. 模块化设计"></a>2. 模块化设计</h2><h3 id="2-1-用户模块"><a href="#2-1-用户模块" class="headerlink" title="2.1 用户模块"></a>2.1 用户模块</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// store/modules/user.js</span></span><br><span class="line"><span class="keyword">import</span> &#123; login, getUserInfo, updateUserInfo &#125; <span class="keyword">from</span> <span class="string">&#x27;@/api/user&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> state = &#123;</span><br><span class="line">  <span class="attr">token</span>: uni.<span class="title function_">getStorageSync</span>(<span class="string">&#x27;token&#x27;</span>) || <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">  <span class="attr">userInfo</span>: <span class="literal">null</span>,</span><br><span class="line">  <span class="attr">permissions</span>: []</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> mutations = &#123;</span><br><span class="line">  <span class="title function_">SET_TOKEN</span>(<span class="params">state, token</span>) &#123;</span><br><span class="line">    state.<span class="property">token</span> = token</span><br><span class="line">    uni.<span class="title function_">setStorageSync</span>(<span class="string">&#x27;token&#x27;</span>, token)</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="title function_">SET_USER_INFO</span>(<span class="params">state, info</span>) &#123;</span><br><span class="line">    state.<span class="property">userInfo</span> = info</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="title function_">SET_PERMISSIONS</span>(<span class="params">state, permissions</span>) &#123;</span><br><span class="line">    state.<span class="property">permissions</span> = permissions</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="title function_">CLEAR_USER_DATA</span>(<span class="params">state</span>) &#123;</span><br><span class="line">    state.<span class="property">token</span> = <span class="string">&#x27;&#x27;</span></span><br><span class="line">    state.<span class="property">userInfo</span> = <span class="literal">null</span></span><br><span class="line">    state.<span class="property">permissions</span> = []</span><br><span class="line">    uni.<span class="title function_">removeStorageSync</span>(<span class="string">&#x27;token&#x27;</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> actions = &#123;</span><br><span class="line">  <span class="comment">// 登录</span></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">login</span>(<span class="params">&#123; commit &#125;, params</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> &#123; token &#125; = <span class="keyword">await</span> <span class="title function_">login</span>(params)</span><br><span class="line">      <span class="title function_">commit</span>(<span class="string">&#x27;SET_TOKEN&#x27;</span>, token)</span><br><span class="line">      <span class="keyword">return</span> token</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;登录失败&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 获取用户信息</span></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">getUserInfo</span>(<span class="params">&#123; commit &#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> &#123; userInfo, permissions &#125; = <span class="keyword">await</span> <span class="title function_">getUserInfo</span>()</span><br><span class="line">      <span class="title function_">commit</span>(<span class="string">&#x27;SET_USER_INFO&#x27;</span>, userInfo)</span><br><span class="line">      <span class="title function_">commit</span>(<span class="string">&#x27;SET_PERMISSIONS&#x27;</span>, permissions)</span><br><span class="line">      <span class="keyword">return</span> userInfo</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;获取用户信息失败&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 更新用户信息</span></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">updateUserInfo</span>(<span class="params">&#123; commit &#125;, params</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> info = <span class="keyword">await</span> <span class="title function_">updateUserInfo</span>(params)</span><br><span class="line">      <span class="title function_">commit</span>(<span class="string">&#x27;SET_USER_INFO&#x27;</span>, info)</span><br><span class="line">      <span class="keyword">return</span> info</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;更新用户信息失败&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 退出登录</span></span><br><span class="line">  <span class="title function_">logout</span>(<span class="params">&#123; commit &#125;</span>) &#123;</span><br><span class="line">    <span class="title function_">commit</span>(<span class="string">&#x27;CLEAR_USER_DATA&#x27;</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> getters = &#123;</span><br><span class="line">  <span class="attr">isLogin</span>: <span class="function"><span class="params">state</span> =&gt;</span> !!state.<span class="property">token</span>,</span><br><span class="line">  <span class="attr">userInfo</span>: <span class="function"><span class="params">state</span> =&gt;</span> state.<span class="property">userInfo</span> || &#123;&#125;,</span><br><span class="line">  <span class="attr">permissions</span>: <span class="function"><span class="params">state</span> =&gt;</span> state.<span class="property">permissions</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">namespaced</span>: <span class="literal">true</span>,</span><br><span class="line">  state,</span><br><span class="line">  mutations,</span><br><span class="line">  actions,</span><br><span class="line">  getters</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="2-2-购物车模块"><a href="#2-2-购物车模块" class="headerlink" title="2.2 购物车模块"></a>2.2 购物车模块</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// store/modules/cart.js</span></span><br><span class="line"><span class="keyword">import</span> &#123; getCartList, updateCart, removeFromCart &#125; <span class="keyword">from</span> <span class="string">&#x27;@/api/cart&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> state = &#123;</span><br><span class="line">  <span class="attr">cartList</span>: [],</span><br><span class="line">  <span class="attr">selectedIds</span>: []</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> mutations = &#123;</span><br><span class="line">  <span class="title function_">SET_CART_LIST</span>(<span class="params">state, list</span>) &#123;</span><br><span class="line">    state.<span class="property">cartList</span> = list</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="title function_">UPDATE_CART_ITEM</span>(<span class="params">state, &#123; id, data &#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> index = state.<span class="property">cartList</span>.<span class="title function_">findIndex</span>(<span class="function"><span class="params">item</span> =&gt;</span> item.<span class="property">id</span> === id)</span><br><span class="line">    <span class="keyword">if</span> (index &gt; -<span class="number">1</span>) &#123;</span><br><span class="line">      state.<span class="property">cartList</span>[index] = &#123; ...state.<span class="property">cartList</span>[index], ...data &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="title function_">REMOVE_CART_ITEM</span>(<span class="params">state, id</span>) &#123;</span><br><span class="line">    state.<span class="property">cartList</span> = state.<span class="property">cartList</span>.<span class="title function_">filter</span>(<span class="function"><span class="params">item</span> =&gt;</span> item.<span class="property">id</span> !== id)</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="title function_">SET_SELECTED_IDS</span>(<span class="params">state, ids</span>) &#123;</span><br><span class="line">    state.<span class="property">selectedIds</span> = ids</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> actions = &#123;</span><br><span class="line">  <span class="comment">// 获取购物车列表</span></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">getCartList</span>(<span class="params">&#123; commit &#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> list = <span class="keyword">await</span> <span class="title function_">getCartList</span>()</span><br><span class="line">      <span class="title function_">commit</span>(<span class="string">&#x27;SET_CART_LIST&#x27;</span>, list)</span><br><span class="line">      <span class="keyword">return</span> list</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;获取购物车列表失败&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 更新购物车商品</span></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">updateCartItem</span>(<span class="params">&#123; commit &#125;, &#123; id, data &#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">await</span> <span class="title function_">updateCart</span>(id, data)</span><br><span class="line">      <span class="title function_">commit</span>(<span class="string">&#x27;UPDATE_CART_ITEM&#x27;</span>, &#123; id, data &#125;)</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;更新购物车商品失败&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 删除购物车商品</span></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">removeCartItem</span>(<span class="params">&#123; commit &#125;, id</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">await</span> <span class="title function_">removeFromCart</span>(id)</span><br><span class="line">      <span class="title function_">commit</span>(<span class="string">&#x27;REMOVE_CART_ITEM&#x27;</span>, id)</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;删除购物车商品失败&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> getters = &#123;</span><br><span class="line">  <span class="attr">cartCount</span>: <span class="function"><span class="params">state</span> =&gt;</span> state.<span class="property">cartList</span>.<span class="property">length</span>,</span><br><span class="line">  <span class="attr">selectedCount</span>: <span class="function"><span class="params">state</span> =&gt;</span> state.<span class="property">selectedIds</span>.<span class="property">length</span>,</span><br><span class="line">  <span class="attr">totalPrice</span>: <span class="function"><span class="params">state</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> state.<span class="property">cartList</span></span><br><span class="line">      .<span class="title function_">filter</span>(<span class="function"><span class="params">item</span> =&gt;</span> state.<span class="property">selectedIds</span>.<span class="title function_">includes</span>(item.<span class="property">id</span>))</span><br><span class="line">      .<span class="title function_">reduce</span>(<span class="function">(<span class="params">total, item</span>) =&gt;</span> total + item.<span class="property">price</span> * item.<span class="property">quantity</span>, <span class="number">0</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">namespaced</span>: <span class="literal">true</span>,</span><br><span class="line">  state,</span><br><span class="line">  mutations,</span><br><span class="line">  actions,</span><br><span class="line">  getters</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="3-数据持久化"><a href="#3-数据持久化" class="headerlink" title="3. 数据持久化"></a>3. 数据持久化</h2><h3 id="3-1-插件封装"><a href="#3-1-插件封装" class="headerlink" title="3.1 插件封装"></a>3.1 插件封装</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// store/plugins/persist.js</span></span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">STORAGE_KEY</span> = <span class="string">&#x27;vuex_storage&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">function</span> <span class="title function_">createPersistPlugin</span>(<span class="params">options = &#123;&#125;</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> &#123;</span><br><span class="line">    key = <span class="variable constant_">STORAGE_KEY</span>,</span><br><span class="line">    paths = [],</span><br><span class="line">    storage = uni.<span class="property">getStorageSync</span></span><br><span class="line">  &#125; = options</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 获取持久化数据</span></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">getState</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> data = <span class="title function_">storage</span>(key)</span><br><span class="line">      <span class="keyword">return</span> data ? <span class="title class_">JSON</span>.<span class="title function_">parse</span>(data) : &#123;&#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;获取持久化数据失败:&#x27;</span>, err)</span><br><span class="line">      <span class="keyword">return</span> &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 设置持久化数据</span></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">setState</span> = (<span class="params">state, paths</span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> data = paths.<span class="property">length</span></span><br><span class="line">        ? paths.<span class="title function_">reduce</span>(<span class="function">(<span class="params">obj, path</span>) =&gt;</span> &#123;</span><br><span class="line">            obj[path] = state[path]</span><br><span class="line">            <span class="keyword">return</span> obj</span><br><span class="line">          &#125;, &#123;&#125;)</span><br><span class="line">        : state</span><br><span class="line">      <span class="title function_">storage</span>(key, <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(data))</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;设置持久化数据失败:&#x27;</span>, err)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> <span class="function"><span class="params">store</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 初始化时获取持久化数据</span></span><br><span class="line">    <span class="keyword">const</span> data = <span class="title function_">getState</span>()</span><br><span class="line">    <span class="keyword">if</span> (<span class="title class_">Object</span>.<span class="title function_">keys</span>(data).<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">      store.<span class="title function_">replaceState</span>(&#123;</span><br><span class="line">        ...store.<span class="property">state</span>,</span><br><span class="line">        ...data</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 监听数据变化</span></span><br><span class="line">    store.<span class="title function_">subscribe</span>(<span class="function">(<span class="params">mutation, state</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="title function_">setState</span>(state, paths)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3-2-使用插件"><a href="#3-2-使用插件" class="headerlink" title="3.2 使用插件"></a>3.2 使用插件</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// store/index.js</span></span><br><span class="line"><span class="keyword">import</span> createPersistPlugin <span class="keyword">from</span> <span class="string">&#x27;./plugins/persist&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> persistPlugin = <span class="title function_">createPersistPlugin</span>(&#123;</span><br><span class="line">  <span class="attr">paths</span>: [<span class="string">&#x27;user.token&#x27;</span>, <span class="string">&#x27;user.userInfo&#x27;</span>, <span class="string">&#x27;cart.cartList&#x27;</span>],</span><br><span class="line">  <span class="attr">storage</span>: uni.<span class="property">setStorageSync</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> store = <span class="keyword">new</span> <span class="title class_">Vuex</span>.<span class="title class_">Store</span>(&#123;</span><br><span class="line">  <span class="comment">// ...其他配置</span></span><br><span class="line">  <span class="attr">plugins</span>: [persistPlugin]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h2 id="4-性能优化"><a href="#4-性能优化" class="headerlink" title="4. 性能优化"></a>4. 性能优化</h2><h3 id="4-1-避免频繁更新"><a href="#4-1-避免频繁更新" class="headerlink" title="4.1 避免频繁更新"></a>4.1 避免频繁更新</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// store/modules/cart.js</span></span><br><span class="line"><span class="keyword">import</span> &#123; debounce &#125; <span class="keyword">from</span> <span class="string">&#x27;@/utils/tools&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> actions = &#123;</span><br><span class="line">  <span class="comment">// 使用防抖优化更新</span></span><br><span class="line">  <span class="attr">updateCartItem</span>: <span class="title function_">debounce</span>(<span class="keyword">async</span> <span class="keyword">function</span>(<span class="params">&#123; commit &#125;, &#123; id, data &#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">await</span> <span class="title function_">updateCart</span>(id, data)</span><br><span class="line">      <span class="title function_">commit</span>(<span class="string">&#x27;UPDATE_CART_ITEM&#x27;</span>, &#123; id, data &#125;)</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;更新购物车商品失败&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;, <span class="number">300</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="4-2-批量更新"><a href="#4-2-批量更新" class="headerlink" title="4.2 批量更新"></a>4.2 批量更新</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// store/modules/cart.js</span></span><br><span class="line"><span class="keyword">const</span> actions = &#123;</span><br><span class="line">  <span class="comment">// 批量更新购物车</span></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">batchUpdateCart</span>(<span class="params">&#123; commit &#125;, items</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">await</span> <span class="title class_">Promise</span>.<span class="title function_">all</span>(items.<span class="title function_">map</span>(<span class="function"><span class="params">item</span> =&gt;</span> <span class="title function_">updateCart</span>(item.<span class="property">id</span>, item.<span class="property">data</span>)))</span><br><span class="line">      items.<span class="title function_">forEach</span>(<span class="function"><span class="params">item</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">commit</span>(<span class="string">&#x27;UPDATE_CART_ITEM&#x27;</span>, item)</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;批量更新购物车失败&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="5-辅助函数使用"><a href="#5-辅助函数使用" class="headerlink" title="5. 辅助函数使用"></a>5. 辅助函数使用</h2><h3 id="5-1-组件中使用"><a href="#5-1-组件中使用" class="headerlink" title="5.1 组件中使用"></a>5.1 组件中使用</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;cart&quot;&gt;</span><br><span class="line">    &lt;view class=&quot;total&quot;&gt;总价: ￥&#123;&#123; totalPrice &#125;&#125;&lt;/view&gt;</span><br><span class="line">    &lt;view </span><br><span class="line">      v-for=&quot;item in cartList&quot;</span><br><span class="line">      :key=&quot;item.id&quot;</span><br><span class="line">      class=&quot;cart-item&quot;</span><br><span class="line">    &gt;</span><br><span class="line">      &lt;text&gt;&#123;&#123; item.name &#125;&#125;&lt;/text&gt;</span><br><span class="line">      &lt;text&gt;￥&#123;&#123; item.price &#125;&#125;&lt;/text&gt;</span><br><span class="line">      &lt;button @click=&quot;updateQuantity(item.id, item.quantity + 1)&quot;&gt;+&lt;/button&gt;</span><br><span class="line">      &lt;text&gt;&#123;&#123; item.quantity &#125;&#125;&lt;/text&gt;</span><br><span class="line">      &lt;button @click=&quot;updateQuantity(item.id, item.quantity - 1)&quot;&gt;-&lt;/button&gt;</span><br><span class="line">      &lt;button @click=&quot;removeItem(item.id)&quot;&gt;删除&lt;/button&gt;</span><br><span class="line">    &lt;/view&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">import &#123; mapState, mapGetters, mapActions &#125; from &#x27;vuex&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  computed: &#123;</span><br><span class="line">    ...mapState(&#x27;cart&#x27;, [&#x27;cartList&#x27;]),</span><br><span class="line">    ...mapGetters(&#x27;cart&#x27;, [&#x27;totalPrice&#x27;])</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    ...mapActions(&#x27;cart&#x27;, [&#x27;updateCartItem&#x27;, &#x27;removeCartItem&#x27;]),</span><br><span class="line">    async updateQuantity(id, quantity) &#123;</span><br><span class="line">      if (quantity &lt; 1) return</span><br><span class="line">      try &#123;</span><br><span class="line">        await this.updateCartItem(&#123; id, data: &#123; quantity &#125; &#125;)</span><br><span class="line">        uni.showToast(&#123; title: &#x27;更新成功&#x27; &#125;)</span><br><span class="line">      &#125; catch (err) &#123;</span><br><span class="line">        uni.showToast(&#123; title: err.message, icon: &#x27;none&#x27; &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    async removeItem(id) &#123;</span><br><span class="line">      try &#123;</span><br><span class="line">        await this.removeCartItem(id)</span><br><span class="line">        uni.showToast(&#123; title: &#x27;删除成功&#x27; &#125;)</span><br><span class="line">      &#125; catch (err) &#123;</span><br><span class="line">        uni.showToast(&#123; title: err.message, icon: &#x27;none&#x27; &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="5-2-自定义辅助函数"><a href="#5-2-自定义辅助函数" class="headerlink" title="5.2 自定义辅助函数"></a>5.2 自定义辅助函数</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// store/helpers.js</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">mapCache</span>(<span class="params">namespace, maps</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> res = &#123;&#125;</span><br><span class="line">  </span><br><span class="line">  <span class="title function_">normalizeMap</span>(maps).<span class="title function_">forEach</span>(<span class="function">(<span class="params">&#123; key, val &#125;</span>) =&gt;</span> &#123;</span><br><span class="line">    res[key] = <span class="keyword">function</span> <span class="title function_">mappedCache</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> store = <span class="variable language_">this</span>.<span class="property">$store</span></span><br><span class="line">      <span class="keyword">const</span> cache = store.<span class="property">_cache</span> || (store.<span class="property">_cache</span> = &#123;&#125;)</span><br><span class="line">      <span class="keyword">const</span> cacheKey = namespace + <span class="string">&#x27;:&#x27;</span> + key</span><br><span class="line">      </span><br><span class="line">      <span class="keyword">if</span> (cache[cacheKey]) &#123;</span><br><span class="line">        <span class="keyword">return</span> cache[cacheKey]</span><br><span class="line">      &#125;</span><br><span class="line">      </span><br><span class="line">      <span class="keyword">const</span> value = <span class="keyword">typeof</span> val === <span class="string">&#x27;function&#x27;</span></span><br><span class="line">        ? val.<span class="title function_">call</span>(<span class="variable language_">this</span>, store.<span class="property">state</span>[namespace], store.<span class="property">getters</span>)</span><br><span class="line">        : store.<span class="property">state</span>[namespace][val]</span><br><span class="line">        </span><br><span class="line">      cache[cacheKey] = value</span><br><span class="line">      <span class="keyword">return</span> value</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> res</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">normalizeMap</span>(<span class="params">map</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="title class_">Array</span>.<span class="title function_">isArray</span>(map)</span><br><span class="line">    ? map.<span class="title function_">map</span>(<span class="function"><span class="params">key</span> =&gt;</span> (&#123; key, <span class="attr">val</span>: key &#125;))</span><br><span class="line">    : <span class="title class_">Object</span>.<span class="title function_">keys</span>(map).<span class="title function_">map</span>(<span class="function"><span class="params">key</span> =&gt;</span> (&#123; key, <span class="attr">val</span>: map[key] &#125;))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="6-最佳实践建议"><a href="#6-最佳实践建议" class="headerlink" title="6. 最佳实践建议"></a>6. 最佳实践建议</h2><ol><li>合理划分模块</li><li>实现数据持久化</li><li>注意性能优化</li><li>使用辅助函数</li><li>做好错误处理</li></ol><h2 id="7-总结"><a href="#7-总结" class="headerlink" title="7. 总结"></a>7. 总结</h2><ol><li>掌握Vuex基础配置</li><li>实现模块化设计</li><li>处理数据持久化</li><li>优化更新性能</li><li>灵活使用辅助函数</li></ol><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">深入探讨uni-app中的状态管理方案,包括Vuex的最佳实践、数据持久化、性能优化等内容,帮助开发者构建可维护的数据流方案。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="Vuex" scheme="https://www.hzv5.cn/tags/Vuex/"/>
    
    <category term="状态管理" scheme="https://www.hzv5.cn/tags/%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86/"/>
    
  </entry>
  
  <entry>
    <title>uni-app路由与页面跳转：最佳实践与踩坑指南</title>
    <link href="https://www.hzv5.cn/2024/03/15/uniapp-router/"/>
    <id>https://www.hzv5.cn/2024/03/15/uniapp-router/</id>
    <published>2024-03-15T06:30:00.000Z</published>
    <updated>2024-03-15T06:30:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>路由与页面跳转是uni-app应用的核心功能之一,本文将详细介绍各种跳转方式及其最佳实践,帮助你构建流畅的页面导航体验。</p></blockquote><span id="more"></span><h2 id="1-基础路由方法"><a href="#1-基础路由方法" class="headerlink" title="1. 基础路由方法"></a>1. 基础路由方法</h2><h3 id="1-1-页面跳转方式"><a href="#1-1-页面跳转方式" class="headerlink" title="1.1 页面跳转方式"></a>1.1 页面跳转方式</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 保留当前页面，跳转到应用内的某个页面</span></span><br><span class="line">uni.<span class="title function_">navigateTo</span>(&#123;</span><br><span class="line">  <span class="attr">url</span>: <span class="string">&#x27;/pages/detail/detail?id=1&#x27;</span>,</span><br><span class="line">  <span class="attr">success</span>: <span class="keyword">function</span>(<span class="params">res</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;跳转成功&#x27;</span>)</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">fail</span>: <span class="keyword">function</span>(<span class="params">err</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;跳转失败:&#x27;</span>, err)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 关闭当前页面，跳转到应用内的某个页面</span></span><br><span class="line">uni.<span class="title function_">redirectTo</span>(&#123;</span><br><span class="line">  <span class="attr">url</span>: <span class="string">&#x27;/pages/index/index&#x27;</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 关闭所有页面，打开到应用内的某个页面</span></span><br><span class="line">uni.<span class="title function_">reLaunch</span>(&#123;</span><br><span class="line">  <span class="attr">url</span>: <span class="string">&#x27;/pages/home/home&#x27;</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 关闭当前页面，返回上一页面或多级页面</span></span><br><span class="line">uni.<span class="title function_">navigateBack</span>(&#123;</span><br><span class="line">  <span class="attr">delta</span>: <span class="number">1</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 跳转到 tabBar 页面</span></span><br><span class="line">uni.<span class="title function_">switchTab</span>(&#123;</span><br><span class="line">  <span class="attr">url</span>: <span class="string">&#x27;/pages/user/user&#x27;</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="1-2-参数传递"><a href="#1-2-参数传递" class="headerlink" title="1.2 参数传递"></a>1.2 参数传递</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 页面A：传递参数</span></span><br><span class="line">uni.<span class="title function_">navigateTo</span>(&#123;</span><br><span class="line">  <span class="attr">url</span>: <span class="string">&#x27;/pages/detail/detail?id=1&amp;type=product&amp;data=&#x27;</span> + <span class="built_in">encodeURIComponent</span>(<span class="title class_">JSON</span>.<span class="title function_">stringify</span>(data))</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 页面B：接收参数</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="title function_">onLoad</span>(<span class="params">options</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> id = options.<span class="property">id</span></span><br><span class="line">    <span class="keyword">const</span> type = options.<span class="property">type</span></span><br><span class="line">    <span class="keyword">const</span> data = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(<span class="built_in">decodeURIComponent</span>(options.<span class="property">data</span>))</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;接收到的参数:&#x27;</span>, id, type, data)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="2-路由拦截与权限控制"><a href="#2-路由拦截与权限控制" class="headerlink" title="2. 路由拦截与权限控制"></a>2. 路由拦截与权限控制</h2><h3 id="2-1-全局路由拦截"><a href="#2-1-全局路由拦截" class="headerlink" title="2.1 全局路由拦截"></a>2.1 全局路由拦截</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// main.js</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Vue</span> <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> store <span class="keyword">from</span> <span class="string">&#x27;./store&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 注册全局路由拦截器</span></span><br><span class="line"><span class="keyword">const</span> whiteList = [<span class="string">&#x27;/pages/login/login&#x27;</span>, <span class="string">&#x27;/pages/register/register&#x27;</span>]</span><br><span class="line"></span><br><span class="line"><span class="title class_">Vue</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">$beforeRouter</span> = <span class="keyword">function</span>(<span class="params">to</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 检查是否需要登录</span></span><br><span class="line">    <span class="keyword">if</span> (whiteList.<span class="title function_">includes</span>(to)) &#123;</span><br><span class="line">      <span class="title function_">resolve</span>()</span><br><span class="line">      <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 检查登录状态</span></span><br><span class="line">    <span class="keyword">const</span> token = uni.<span class="title function_">getStorageSync</span>(<span class="string">&#x27;token&#x27;</span>)</span><br><span class="line">    <span class="keyword">if</span> (!token) &#123;</span><br><span class="line">      uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">        <span class="attr">title</span>: <span class="string">&#x27;请先登录&#x27;</span>,</span><br><span class="line">        <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span></span><br><span class="line">      &#125;)</span><br><span class="line">      uni.<span class="title function_">navigateTo</span>(&#123;</span><br><span class="line">        <span class="attr">url</span>: <span class="string">&#x27;/pages/login/login&#x27;</span></span><br><span class="line">      &#125;)</span><br><span class="line">      <span class="title function_">reject</span>(<span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;未登录&#x27;</span>))</span><br><span class="line">      <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 检查权限</span></span><br><span class="line">    <span class="keyword">const</span> userInfo = store.<span class="property">state</span>.<span class="property">user</span>.<span class="property">userInfo</span></span><br><span class="line">    <span class="keyword">if</span> (to.<span class="property">requiresAuth</span> &amp;&amp; !userInfo.<span class="property">permissions</span>.<span class="title function_">includes</span>(to.<span class="property">permission</span>)) &#123;</span><br><span class="line">      uni.<span class="title function_">showToast</span>(&#123;</span><br><span class="line">        <span class="attr">title</span>: <span class="string">&#x27;暂无权限访问&#x27;</span>,</span><br><span class="line">        <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span></span><br><span class="line">      &#125;)</span><br><span class="line">      <span class="title function_">reject</span>(<span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;无权限&#x27;</span>))</span><br><span class="line">      <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="title function_">resolve</span>()</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 页面中使用</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">onLoad</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">await</span> <span class="variable language_">this</span>.$beforeRouter(<span class="string">&#x27;/pages/user/user&#x27;</span>)</span><br><span class="line">      <span class="comment">// 继续执行页面逻辑</span></span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;路由拦截:&#x27;</span>, err)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="2-2-页面级权限控制"><a href="#2-2-页面级权限控制" class="headerlink" title="2.2 页面级权限控制"></a>2.2 页面级权限控制</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// mixins/auth.js</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="title function_">data</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">hasPermission</span>: <span class="literal">false</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="title function_">onLoad</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">checkPermission</span>()</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="title function_">checkPermission</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> userPermissions = <span class="variable language_">this</span>.<span class="property">$store</span>.<span class="property">state</span>.<span class="property">user</span>.<span class="property">permissions</span></span><br><span class="line">      <span class="keyword">const</span> pagePermission = <span class="variable language_">this</span>.<span class="property">$options</span>.<span class="property">permission</span></span><br><span class="line">      </span><br><span class="line">      <span class="keyword">if</span> (!pagePermission) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">hasPermission</span> = <span class="literal">true</span></span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">      &#125;</span><br><span class="line">      </span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">hasPermission</span> = userPermissions.<span class="title function_">includes</span>(pagePermission)</span><br><span class="line">      </span><br><span class="line">      <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">hasPermission</span>) &#123;</span><br><span class="line">        uni.<span class="title function_">showModal</span>(&#123;</span><br><span class="line">          <span class="attr">title</span>: <span class="string">&#x27;提示&#x27;</span>,</span><br><span class="line">          <span class="attr">content</span>: <span class="string">&#x27;暂无访问权限&#x27;</span>,</span><br><span class="line">          <span class="attr">showCancel</span>: <span class="literal">false</span>,</span><br><span class="line">          <span class="attr">success</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            uni.<span class="title function_">navigateBack</span>()</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 页面中使用</span></span><br><span class="line"><span class="keyword">import</span> authMixin <span class="keyword">from</span> <span class="string">&#x27;@/mixins/auth&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">mixins</span>: [authMixin],</span><br><span class="line">  <span class="attr">permission</span>: <span class="string">&#x27;user:edit&#x27;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="3-页面通信方案"><a href="#3-页面通信方案" class="headerlink" title="3. 页面通信方案"></a>3. 页面通信方案</h2><h3 id="3-1-页面间事件通信"><a href="#3-1-页面间事件通信" class="headerlink" title="3.1 页面间事件通信"></a>3.1 页面间事件通信</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 页面A：发送事件</span></span><br><span class="line"><span class="title function_">onLoad</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="comment">// 注册事件监听</span></span><br><span class="line">  uni.$on(<span class="string">&#x27;updateList&#x27;</span>, <span class="variable language_">this</span>.<span class="property">handleUpdateList</span>)</span><br><span class="line">&#125;,</span><br><span class="line"><span class="title function_">onUnload</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="comment">// 注销事件监听</span></span><br><span class="line">  uni.$off(<span class="string">&#x27;updateList&#x27;</span>, <span class="variable language_">this</span>.<span class="property">handleUpdateList</span>)</span><br><span class="line">&#125;,</span><br><span class="line"><span class="attr">methods</span>: &#123;</span><br><span class="line">  <span class="title function_">handleUpdateList</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;收到更新数据:&#x27;</span>, data)</span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">refreshList</span>()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 页面B：触发事件</span></span><br><span class="line"><span class="attr">methods</span>: &#123;</span><br><span class="line">  <span class="title function_">submitSuccess</span>(<span class="params"></span>) &#123;</span><br><span class="line">    uni.$emit(<span class="string">&#x27;updateList&#x27;</span>, &#123; <span class="attr">type</span>: <span class="string">&#x27;add&#x27;</span>, <span class="attr">data</span>: <span class="variable language_">this</span>.<span class="property">formData</span> &#125;)</span><br><span class="line">    uni.<span class="title function_">navigateBack</span>()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3-2-页面栈管理"><a href="#3-2-页面栈管理" class="headerlink" title="3.2 页面栈管理"></a>3.2 页面栈管理</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utils/page.js</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">PageManager</span> &#123;</span><br><span class="line">  <span class="comment">// 获取当前页面栈</span></span><br><span class="line">  <span class="keyword">static</span> <span class="title function_">getCurrentPages</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> pages = <span class="title function_">getCurrentPages</span>()</span><br><span class="line">    <span class="keyword">return</span> pages</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 获取上一个页面实例</span></span><br><span class="line">  <span class="keyword">static</span> <span class="title function_">getPrevPage</span>(<span class="params">delta = <span class="number">1</span></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> pages = <span class="variable language_">this</span>.<span class="title function_">getCurrentPages</span>()</span><br><span class="line">    <span class="keyword">const</span> prevPage = pages[pages.<span class="property">length</span> - <span class="number">1</span> - delta]</span><br><span class="line">    <span class="keyword">return</span> prevPage</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 调用上一个页面的方法</span></span><br><span class="line">  <span class="keyword">static</span> <span class="title function_">callPrevPageMethod</span>(<span class="params">methodName, args, delta = <span class="number">1</span></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> prevPage = <span class="variable language_">this</span>.<span class="title function_">getPrevPage</span>(delta)</span><br><span class="line">    <span class="keyword">if</span> (prevPage &amp;&amp; <span class="keyword">typeof</span> prevPage[methodName] === <span class="string">&#x27;function&#x27;</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> prevPage[methodName](args)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 检查是否可以返回</span></span><br><span class="line">  <span class="keyword">static</span> <span class="title function_">canBack</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> pages = <span class="variable language_">this</span>.<span class="title function_">getCurrentPages</span>()</span><br><span class="line">    <span class="keyword">return</span> pages.<span class="property">length</span> &gt; <span class="number">1</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">PageManager</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用示例</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">PageManager</span> <span class="keyword">from</span> <span class="string">&#x27;@/utils/page&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 调用上一页面方法</span></span><br><span class="line"><span class="title class_">PageManager</span>.<span class="title function_">callPrevPageMethod</span>(<span class="string">&#x27;refreshData&#x27;</span>, &#123; <span class="attr">type</span>: <span class="string">&#x27;update&#x27;</span> &#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 检查是否可以返回</span></span><br><span class="line"><span class="keyword">if</span> (<span class="title class_">PageManager</span>.<span class="title function_">canBack</span>()) &#123;</span><br><span class="line">  uni.<span class="title function_">navigateBack</span>()</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">  uni.<span class="title function_">reLaunch</span>(&#123; <span class="attr">url</span>: <span class="string">&#x27;/pages/index/index&#x27;</span> &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="4-路由动画与转场效果"><a href="#4-路由动画与转场效果" class="headerlink" title="4. 路由动画与转场效果"></a>4. 路由动画与转场效果</h2><h3 id="4-1-基础动画配置"><a href="#4-1-基础动画配置" class="headerlink" title="4.1 基础动画配置"></a>4.1 基础动画配置</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// pages.json</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;pages&quot;</span>: [&#123;</span><br><span class="line">    <span class="string">&quot;path&quot;</span>: <span class="string">&quot;pages/index/index&quot;</span>,</span><br><span class="line">    <span class="string">&quot;style&quot;</span>: &#123;</span><br><span class="line">      <span class="string">&quot;navigationBarTitleText&quot;</span>: <span class="string">&quot;首页&quot;</span>,</span><br><span class="line">      <span class="string">&quot;app-plus&quot;</span>: &#123;</span><br><span class="line">        <span class="string">&quot;animationType&quot;</span>: <span class="string">&quot;slide-in-right&quot;</span>,</span><br><span class="line">        <span class="string">&quot;animationDuration&quot;</span>: <span class="number">300</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 页面跳转时指定动画</span></span><br><span class="line">uni.<span class="title function_">navigateTo</span>(&#123;</span><br><span class="line">  <span class="attr">url</span>: <span class="string">&#x27;/pages/detail/detail&#x27;</span>,</span><br><span class="line">  <span class="attr">animationType</span>: <span class="string">&#x27;slide-in-bottom&#x27;</span>,</span><br><span class="line">  <span class="attr">animationDuration</span>: <span class="number">300</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="4-2-自定义转场动画"><a href="#4-2-自定义转场动画" class="headerlink" title="4.2 自定义转场动画"></a>4.2 自定义转场动画</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- components/page-transition.vue --&gt;</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;page-transition&quot; :class=&quot;[transitionClass]&quot;&gt;</span><br><span class="line">    &lt;slot&gt;&lt;/slot&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      transitionClass: &#x27;&#x27;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    enter() &#123;</span><br><span class="line">      this.transitionClass = &#x27;slide-enter&#x27;</span><br><span class="line">      setTimeout(() =&gt; &#123;</span><br><span class="line">        this.transitionClass = &#x27;slide-enter-active&#x27;</span><br><span class="line">      &#125;, 50)</span><br><span class="line">    &#125;,</span><br><span class="line">    leave() &#123;</span><br><span class="line">      this.transitionClass = &#x27;slide-leave&#x27;</span><br><span class="line">      setTimeout(() =&gt; &#123;</span><br><span class="line">        this.transitionClass = &#x27;slide-leave-active&#x27;</span><br><span class="line">      &#125;, 50)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style&gt;</span><br><span class="line">.page-transition &#123;</span><br><span class="line">  position: absolute;</span><br><span class="line">  width: 100%;</span><br><span class="line">  height: 100%;</span><br><span class="line">  transition: all 0.3s ease;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.slide-enter &#123;</span><br><span class="line">  transform: translateX(100%);</span><br><span class="line">&#125;</span><br><span class="line">.slide-enter-active &#123;</span><br><span class="line">  transform: translateX(0);</span><br><span class="line">&#125;</span><br><span class="line">.slide-leave &#123;</span><br><span class="line">  transform: translateX(0);</span><br><span class="line">&#125;</span><br><span class="line">.slide-leave-active &#123;</span><br><span class="line">  transform: translateX(-100%);</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure><h2 id="5-常见问题与解决方案"><a href="#5-常见问题与解决方案" class="headerlink" title="5. 常见问题与解决方案"></a>5. 常见问题与解决方案</h2><h3 id="5-1-页面栈溢出"><a href="#5-1-页面栈溢出" class="headerlink" title="5.1 页面栈溢出"></a>5.1 页面栈溢出</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 检查页面栈深度</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">checkPageStack</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> pages = <span class="title function_">getCurrentPages</span>()</span><br><span class="line">  <span class="keyword">const</span> maxStack = <span class="number">10</span> <span class="comment">// 最大页面栈深度</span></span><br><span class="line">  </span><br><span class="line">  <span class="keyword">if</span> (pages.<span class="property">length</span> &gt;= maxStack) &#123;</span><br><span class="line">    uni.<span class="title function_">showModal</span>(&#123;</span><br><span class="line">      <span class="attr">title</span>: <span class="string">&#x27;提示&#x27;</span>,</span><br><span class="line">      <span class="attr">content</span>: <span class="string">&#x27;页面层级过深，是否返回首页？&#x27;</span>,</span><br><span class="line">      <span class="attr">success</span>: <span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (res.<span class="property">confirm</span>) &#123;</span><br><span class="line">          uni.<span class="title function_">reLaunch</span>(&#123;</span><br><span class="line">            <span class="attr">url</span>: <span class="string">&#x27;/pages/index/index&#x27;</span></span><br><span class="line">          &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用示例</span></span><br><span class="line"><span class="attr">methods</span>: &#123;</span><br><span class="line">  <span class="title function_">navigateToDetail</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="title function_">checkPageStack</span>()) <span class="keyword">return</span></span><br><span class="line">    uni.<span class="title function_">navigateTo</span>(&#123;</span><br><span class="line">      <span class="attr">url</span>: <span class="string">&#x27;/pages/detail/detail&#x27;</span></span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="5-2-参数长度限制"><a href="#5-2-参数长度限制" class="headerlink" title="5.2 参数长度限制"></a>5.2 参数长度限制</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 处理长参数传递</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">handleLongParams</span>(<span class="params">params</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> params !== <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">    params = <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(params)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 检查参数长度</span></span><br><span class="line">  <span class="keyword">if</span> (params.<span class="property">length</span> &gt; <span class="number">2048</span>) &#123;</span><br><span class="line">    <span class="comment">// 存储到本地</span></span><br><span class="line">    <span class="keyword">const</span> key = <span class="string">&#x27;temp_params_&#x27;</span> + <span class="title class_">Date</span>.<span class="title function_">now</span>()</span><br><span class="line">    uni.<span class="title function_">setStorageSync</span>(key, params)</span><br><span class="line">    <span class="keyword">return</span> key</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> params</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 页面A：传递参数</span></span><br><span class="line"><span class="keyword">const</span> params = <span class="title function_">handleLongParams</span>(<span class="variable language_">this</span>.<span class="property">longData</span>)</span><br><span class="line">uni.<span class="title function_">navigateTo</span>(&#123;</span><br><span class="line">  <span class="attr">url</span>: <span class="string">`/pages/detail/detail?key=<span class="subst">$&#123;params&#125;</span>`</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 页面B：接收参数</span></span><br><span class="line"><span class="title function_">onLoad</span>(<span class="params">options</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> data = options.<span class="property">key</span></span><br><span class="line">  <span class="keyword">if</span> (data.<span class="title function_">startsWith</span>(<span class="string">&#x27;temp_params_&#x27;</span>)) &#123;</span><br><span class="line">    <span class="comment">// 从本地存储获取</span></span><br><span class="line">    data = uni.<span class="title function_">getStorageSync</span>(data)</span><br><span class="line">    <span class="comment">// 清理存储</span></span><br><span class="line">    uni.<span class="title function_">removeStorageSync</span>(data)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="title function_">handleData</span>(<span class="title class_">JSON</span>.<span class="title function_">parse</span>(data))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="6-最佳实践建议"><a href="#6-最佳实践建议" class="headerlink" title="6. 最佳实践建议"></a>6. 最佳实践建议</h2><ol><li>合理使用页面跳转方式</li><li>实现统一的路由拦截</li><li>注意页面栈管理</li><li>优化转场动画</li><li>处理异常情况</li></ol><h2 id="7-总结"><a href="#7-总结" class="headerlink" title="7. 总结"></a>7. 总结</h2><ol><li>掌握基础路由方法</li><li>实现权限控制</li><li>处理页面通信</li><li>优化用户体验</li><li>解决常见问题</li></ol><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">详细介绍uni-app中的路由与页面跳转机制,包括各种跳转方式、参数传递、路由拦截、页面通信等内容,帮助开发者构建完善的页面导航体系。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="路由跳转" scheme="https://www.hzv5.cn/tags/%E8%B7%AF%E7%94%B1%E8%B7%B3%E8%BD%AC/"/>
    
    <category term="页面通信" scheme="https://www.hzv5.cn/tags/%E9%A1%B5%E9%9D%A2%E9%80%9A%E4%BF%A1/"/>
    
  </entry>
  
  <entry>
    <title>uni-app性能优化实战：从加载到渲染的全方位提升</title>
    <link href="https://www.hzv5.cn/2024/03/10/uniapp-performance/"/>
    <id>https://www.hzv5.cn/2024/03/10/uniapp-performance/</id>
    <published>2024-03-10T03:30:00.000Z</published>
    <updated>2024-03-10T03:30:00.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>性能优化是提升用户体验的关键因素,本文将从多个维度详细介绍uni-app应用的性能优化策略,帮助你构建流畅的跨端应用。</p></blockquote><span id="more"></span><h2 id="1-首屏加载优化"><a href="#1-首屏加载优化" class="headerlink" title="1. 首屏加载优化"></a>1. 首屏加载优化</h2><h3 id="1-1-分包加载"><a href="#1-1-分包加载" class="headerlink" title="1.1 分包加载"></a>1.1 分包加载</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// pages.json</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;pages&quot;</span>: [&#123;</span><br><span class="line">    <span class="string">&quot;path&quot;</span>: <span class="string">&quot;pages/index/index&quot;</span>,</span><br><span class="line">    <span class="string">&quot;style&quot;</span>: &#123; ... &#125;</span><br><span class="line">  &#125;],</span><br><span class="line">  <span class="string">&quot;subPackages&quot;</span>: [&#123;</span><br><span class="line">    <span class="string">&quot;root&quot;</span>: <span class="string">&quot;pagesA&quot;</span>,</span><br><span class="line">    <span class="string">&quot;pages&quot;</span>: [&#123;</span><br><span class="line">      <span class="string">&quot;path&quot;</span>: <span class="string">&quot;list/index&quot;</span>,</span><br><span class="line">      <span class="string">&quot;style&quot;</span>: &#123; ... &#125;</span><br><span class="line">    &#125;]</span><br><span class="line">  &#125;]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="1-2-预加载策略"><a href="#1-2-预加载策略" class="headerlink" title="1.2 预加载策略"></a>1.2 预加载策略</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 预加载分包</span></span><br><span class="line">uni.<span class="title function_">preloadSubPackage</span>(&#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;pagesA&#x27;</span>,</span><br><span class="line">  <span class="attr">success</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;分包预加载成功&#x27;</span>)</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">fail</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;分包预加载失败&#x27;</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 预加载页面</span></span><br><span class="line"><span class="title function_">onLoad</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="comment">// 在首页预加载其他页面</span></span><br><span class="line">  uni.<span class="title function_">preloadPage</span>(&#123;</span><br><span class="line">    <span class="attr">url</span>: <span class="string">&#x27;/pagesA/list/index&#x27;</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="1-3-骨架屏实现"><a href="#1-3-骨架屏实现" class="headerlink" title="1.3 骨架屏实现"></a>1.3 骨架屏实现</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- components/skeleton.vue --&gt;</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;skeleton&quot; v-if=&quot;loading&quot;&gt;</span><br><span class="line">    &lt;view class=&quot;skeleton-header&quot;&gt;&lt;/view&gt;</span><br><span class="line">    &lt;view class=&quot;skeleton-content&quot;&gt;</span><br><span class="line">      &lt;view class=&quot;skeleton-item&quot; v-for=&quot;i in 5&quot; :key=&quot;i&quot;&gt;&lt;/view&gt;</span><br><span class="line">    &lt;/view&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;style&gt;</span><br><span class="line">.skeleton &#123;</span><br><span class="line">  padding: 20rpx;</span><br><span class="line">&#125;</span><br><span class="line">.skeleton-header &#123;</span><br><span class="line">  height: 40rpx;</span><br><span class="line">  background: #f0f0f0;</span><br><span class="line">  margin-bottom: 20rpx;</span><br><span class="line">  animation: skeleton-loading 1s infinite;</span><br><span class="line">&#125;</span><br><span class="line">.skeleton-item &#123;</span><br><span class="line">  height: 100rpx;</span><br><span class="line">  background: #f0f0f0;</span><br><span class="line">  margin-bottom: 20rpx;</span><br><span class="line">  animation: skeleton-loading 1s infinite;</span><br><span class="line">&#125;</span><br><span class="line">@keyframes skeleton-loading &#123;</span><br><span class="line">  0% &#123; opacity: 1; &#125;</span><br><span class="line">  50% &#123; opacity: 0.5; &#125;</span><br><span class="line">  100% &#123; opacity: 1; &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure><h2 id="2-渲染性能优化"><a href="#2-渲染性能优化" class="headerlink" title="2. 渲染性能优化"></a>2. 渲染性能优化</h2><h3 id="2-1-长列表优化"><a href="#2-1-长列表优化" class="headerlink" title="2.1 长列表优化"></a>2.1 长列表优化</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 虚拟列表实现 --&gt;</span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;view class=&quot;list-container&quot;&gt;</span><br><span class="line">    &lt;view </span><br><span class="line">      class=&quot;list-phantom&quot;</span><br><span class="line">      :style=&quot;&#123; height: listHeight + &#x27;px&#x27; &#125;&quot;</span><br><span class="line">    &gt;&lt;/view&gt;</span><br><span class="line">    &lt;view </span><br><span class="line">      class=&quot;list-content&quot;</span><br><span class="line">      :style=&quot;&#123; transform: getTransform &#125;&quot;</span><br><span class="line">    &gt;</span><br><span class="line">      &lt;view </span><br><span class="line">        class=&quot;list-item&quot;</span><br><span class="line">        v-for=&quot;item in visibleData&quot;</span><br><span class="line">        :key=&quot;item.id&quot;</span><br><span class="line">      &gt;</span><br><span class="line">        &#123;&#123; item.content &#125;&#125;</span><br><span class="line">      &lt;/view&gt;</span><br><span class="line">    &lt;/view&gt;</span><br><span class="line">  &lt;/view&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      listData: [], // 完整列表数据</span><br><span class="line">      itemHeight: 50, // 每项高度</span><br><span class="line">      visibleCount: 10, // 可视区域显示的数量</span><br><span class="line">      startIndex: 0, // 起始索引</span><br><span class="line">      endIndex: 0 // 结束索引</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  computed: &#123;</span><br><span class="line">    listHeight() &#123;</span><br><span class="line">      return this.listData.length * this.itemHeight</span><br><span class="line">    &#125;,</span><br><span class="line">    visibleData() &#123;</span><br><span class="line">      return this.listData.slice(this.startIndex, this.endIndex)</span><br><span class="line">    &#125;,</span><br><span class="line">    getTransform() &#123;</span><br><span class="line">      return `translate3d(0, $&#123;this.startIndex * this.itemHeight&#125;px, 0)`</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    handleScroll(e) &#123;</span><br><span class="line">      const scrollTop = e.detail.scrollTop</span><br><span class="line">      this.startIndex = Math.floor(scrollTop / this.itemHeight)</span><br><span class="line">      this.endIndex = this.startIndex + this.visibleCount</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="2-2-避免频繁更新"><a href="#2-2-避免频繁更新" class="headerlink" title="2.2 避免频繁更新"></a>2.2 避免频繁更新</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用防抖</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">debounce</span>(<span class="params">fn, delay</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> timer = <span class="literal">null</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">function</span>(<span class="params">...args</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (timer) <span class="built_in">clearTimeout</span>(timer)</span><br><span class="line">    timer = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">      fn.<span class="title function_">apply</span>(<span class="variable language_">this</span>, args)</span><br><span class="line">    &#125;, delay)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用节流</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">throttle</span>(<span class="params">fn, delay</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> timer = <span class="literal">null</span></span><br><span class="line">  <span class="keyword">let</span> start = <span class="title class_">Date</span>.<span class="title function_">now</span>()</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">function</span>(<span class="params">...args</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> current = <span class="title class_">Date</span>.<span class="title function_">now</span>()</span><br><span class="line">    <span class="keyword">const</span> remaining = delay - (current - start)</span><br><span class="line">    <span class="keyword">if</span> (timer) <span class="built_in">clearTimeout</span>(timer)</span><br><span class="line">    <span class="keyword">if</span> (remaining &lt;= <span class="number">0</span>) &#123;</span><br><span class="line">      fn.<span class="title function_">apply</span>(<span class="variable language_">this</span>, args)</span><br><span class="line">      start = <span class="title class_">Date</span>.<span class="title function_">now</span>()</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      timer = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        fn.<span class="title function_">apply</span>(<span class="variable language_">this</span>, args)</span><br><span class="line">        start = <span class="title class_">Date</span>.<span class="title function_">now</span>()</span><br><span class="line">      &#125;, remaining)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 在组件中使用</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="attr">updateData</span>: <span class="title function_">debounce</span>(<span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="comment">// 更新数据的操作</span></span><br><span class="line">    &#125;, <span class="number">300</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="3-内存优化"><a href="#3-内存优化" class="headerlink" title="3. 内存优化"></a>3. 内存优化</h2><h3 id="3-1-及时销毁"><a href="#3-1-及时销毁" class="headerlink" title="3.1 及时销毁"></a>3.1 及时销毁</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="title function_">data</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">timer</span>: <span class="literal">null</span>,</span><br><span class="line">      <span class="attr">observer</span>: <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="title function_">beforeDestroy</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="comment">// 清除定时器</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">timer</span>) &#123;</span><br><span class="line">      <span class="built_in">clearTimeout</span>(<span class="variable language_">this</span>.<span class="property">timer</span>)</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">timer</span> = <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 清除监听器</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">observer</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">observer</span>.<span class="title function_">disconnect</span>()</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">observer</span> = <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3-2-避免内存泄漏"><a href="#3-2-避免内存泄漏" class="headerlink" title="3.2 避免内存泄漏"></a>3.2 避免内存泄漏</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 图片预加载</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">preloadImages</span> = (<span class="params">urls</span>) =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> promises = urls.<span class="title function_">map</span>(<span class="function"><span class="params">url</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> image = <span class="keyword">new</span> <span class="title class_">Image</span>()</span><br><span class="line">      image.<span class="property">onload</span> = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        image.<span class="property">onload</span> = <span class="literal">null</span> <span class="comment">// 清除事件监听</span></span><br><span class="line">        <span class="title function_">resolve</span>(url)</span><br><span class="line">      &#125;</span><br><span class="line">      image.<span class="property">onerror</span> = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        image.<span class="property">onerror</span> = <span class="literal">null</span> <span class="comment">// 清除事件监听</span></span><br><span class="line">        <span class="title function_">reject</span>(url)</span><br><span class="line">      &#125;</span><br><span class="line">      image.<span class="property">src</span> = url</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">all</span>(promises)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="4-网络优化"><a href="#4-网络优化" class="headerlink" title="4. 网络优化"></a>4. 网络优化</h2><h3 id="4-1-请求合并"><a href="#4-1-请求合并" class="headerlink" title="4.1 请求合并"></a>4.1 请求合并</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 请求队列管理</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">RequestQueue</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">queue</span> = <span class="keyword">new</span> <span class="title class_">Map</span>()</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">request</span>(<span class="params">key, promiseCreator</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">queue</span>.<span class="title function_">has</span>(key)) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">queue</span>.<span class="title function_">get</span>(key)</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">const</span> promise = <span class="title function_">promiseCreator</span>()</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">queue</span>.<span class="title function_">set</span>(key, promise)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> result = <span class="keyword">await</span> promise</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">queue</span>.<span class="title function_">delete</span>(key)</span><br><span class="line">      <span class="keyword">return</span> result</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">queue</span>.<span class="title function_">delete</span>(key)</span><br><span class="line">      <span class="keyword">throw</span> err</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用示例</span></span><br><span class="line"><span class="keyword">const</span> requestQueue = <span class="keyword">new</span> <span class="title class_">RequestQueue</span>()</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fetchData</span>(<span class="params">id</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> requestQueue.<span class="title function_">request</span>(<span class="string">`data_<span class="subst">$&#123;id&#125;</span>`</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function"><span class="params">resolve</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">resolve</span>(&#123; id, <span class="attr">data</span>: <span class="string">&#x27;some data&#x27;</span> &#125;)</span><br><span class="line">      &#125;, <span class="number">1000</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="4-2-数据缓存"><a href="#4-2-数据缓存" class="headerlink" title="4.2 数据缓存"></a>4.2 数据缓存</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">CacheManager</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">expire = <span class="number">5</span> * <span class="number">60</span> * <span class="number">1000</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">cache</span> = <span class="keyword">new</span> <span class="title class_">Map</span>()</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">expire</span> = expire</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="title function_">set</span>(<span class="params">key, value</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">set</span>(key, &#123;</span><br><span class="line">      value,</span><br><span class="line">      <span class="attr">timestamp</span>: <span class="title class_">Date</span>.<span class="title function_">now</span>()</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="title function_">get</span>(<span class="params">key</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> data = <span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">get</span>(key)</span><br><span class="line">    <span class="keyword">if</span> (!data) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (<span class="title class_">Date</span>.<span class="title function_">now</span>() - data.<span class="property">timestamp</span> &gt; <span class="variable language_">this</span>.<span class="property">expire</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">delete</span>(key)</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> data.<span class="property">value</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="title function_">clear</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">clear</span>()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用示例</span></span><br><span class="line"><span class="keyword">const</span> cache = <span class="keyword">new</span> <span class="title class_">CacheManager</span>()</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">getData</span>(<span class="params">key</span>) &#123;</span><br><span class="line">  <span class="comment">// 先从缓存获取</span></span><br><span class="line">  <span class="keyword">const</span> cached = cache.<span class="title function_">get</span>(key)</span><br><span class="line">  <span class="keyword">if</span> (cached) <span class="keyword">return</span> cached</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 缓存不存在则请求</span></span><br><span class="line">  <span class="keyword">const</span> data = <span class="keyword">await</span> <span class="title function_">fetchData</span>(key)</span><br><span class="line">  cache.<span class="title function_">set</span>(key, data)</span><br><span class="line">  <span class="keyword">return</span> data</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="5-其他优化技巧"><a href="#5-其他优化技巧" class="headerlink" title="5. 其他优化技巧"></a>5. 其他优化技巧</h2><h3 id="5-1-图片优化"><a href="#5-1-图片优化" class="headerlink" title="5.1 图片优化"></a>5.1 图片优化</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 图片懒加载指令</span></span><br><span class="line"><span class="title class_">Vue</span>.<span class="title function_">directive</span>(<span class="string">&#x27;lazy&#x27;</span>, &#123;</span><br><span class="line">  <span class="title function_">bind</span>(<span class="params">el, binding</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> observer = <span class="keyword">new</span> <span class="title class_">IntersectionObserver</span>(<span class="function"><span class="params">entries</span> =&gt;</span> &#123;</span><br><span class="line">      entries.<span class="title function_">forEach</span>(<span class="function"><span class="params">entry</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (entry.<span class="property">isIntersecting</span>) &#123;</span><br><span class="line">          el.<span class="property">src</span> = binding.<span class="property">value</span></span><br><span class="line">          observer.<span class="title function_">unobserve</span>(el)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">    observer.<span class="title function_">observe</span>(el)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用示例</span></span><br><span class="line">&lt;image v-lazy=<span class="string">&quot;imageUrl&quot;</span> /&gt;</span><br></pre></td></tr></table></figure><h3 id="5-2-组件优化"><a href="#5-2-组件优化" class="headerlink" title="5.2 组件优化"></a>5.2 组件优化</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用keep-alive缓存组件</span></span><br><span class="line">&lt;keep-alive&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">component</span> <span class="attr">:is</span>=<span class="string">&quot;currentComponent&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">component</span>&gt;</span></span></span><br><span class="line">&lt;/keep-alive&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 异步组件</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">AsyncComponent</span> = (<span class="params"></span>) =&gt; (&#123;</span><br><span class="line">  <span class="attr">component</span>: <span class="keyword">import</span>(<span class="string">&#x27;./heavy-component.vue&#x27;</span>),</span><br><span class="line">  <span class="attr">loading</span>: <span class="title class_">LoadingComponent</span>,</span><br><span class="line">  <span class="attr">error</span>: <span class="title class_">ErrorComponent</span>,</span><br><span class="line">  <span class="attr">delay</span>: <span class="number">200</span>,</span><br><span class="line">  <span class="attr">timeout</span>: <span class="number">3000</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h2 id="6-性能监控"><a href="#6-性能监控" class="headerlink" title="6. 性能监控"></a>6. 性能监控</h2><h3 id="6-1-页面性能监控"><a href="#6-1-页面性能监控" class="headerlink" title="6.1 页面性能监控"></a>6.1 页面性能监控</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> performance = &#123;</span><br><span class="line">  <span class="comment">// 记录时间点</span></span><br><span class="line">  <span class="title function_">mark</span>(<span class="params">name</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> performance !== <span class="string">&#x27;undefined&#x27;</span>) &#123;</span><br><span class="line">      performance.<span class="title function_">mark</span>(name)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 测量两个时间点之间的时间</span></span><br><span class="line">  <span class="title function_">measure</span>(<span class="params">name, startMark, endMark</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> performance !== <span class="string">&#x27;undefined&#x27;</span>) &#123;</span><br><span class="line">      performance.<span class="title function_">measure</span>(name, startMark, endMark)</span><br><span class="line">      <span class="keyword">const</span> measures = performance.<span class="title function_">getEntriesByName</span>(name)</span><br><span class="line">      <span class="keyword">return</span> measures[<span class="number">0</span>].<span class="property">duration</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 上报性能数据</span></span><br><span class="line">  <span class="title function_">report</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="comment">// 上报逻辑</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;性能数据:&#x27;</span>, data)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="7-总结"><a href="#7-总结" class="headerlink" title="7. 总结"></a>7. 总结</h2><ol><li>合理使用分包加载</li><li>实现虚拟列表</li><li>优化更新机制</li><li>注意内存管理</li><li>做好网络优化</li><li>监控性能指标</li></ol><hr><blockquote><p>如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力！ </p></blockquote>]]></content>
    
    
    <summary type="html">深入探讨uni-app应用的性能优化策略,包括首屏加载优化、渲染性能优化、内存管理、网络优化等多个维度,助你打造高性能的跨端应用。</summary>
    
    
    
    <category term="前端开发" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="uni-app" scheme="https://www.hzv5.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/uni-app/"/>
    
    
    <category term="uni-app" scheme="https://www.hzv5.cn/tags/uni-app/"/>
    
    <category term="前端开发" scheme="https://www.hzv5.cn/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="性能优化" scheme="https://www.hzv5.cn/tags/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
    
    <category term="小程序" scheme="https://www.hzv5.cn/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
    
  </entry>
  
</feed>
