<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>大前端开发 on 码上生长 - 探索个人成长的无限可能</title>
    <link>https://dstweihao.cn/categories/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/</link>
    <description>Recent content in 大前端开发 on 码上生长 - 探索个人成长的无限可能</description>
    <generator>Hugo -- 0.144.2</generator>
    <language>zh</language>
    <lastBuildDate>Sat, 26 Apr 2025 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://dstweihao.cn/categories/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>前端业务组件封装与管理的解决方案</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/%E5%89%8D%E7%AB%AF%E4%B8%9A%E5%8A%A1%E7%BB%84%E4%BB%B6%E5%B0%81%E8%A3%85%E4%B8%8E%E7%AE%A1%E7%90%86%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/</link>
      <pubDate>Sat, 26 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/%E5%89%8D%E7%AB%AF%E4%B8%9A%E5%8A%A1%E7%BB%84%E4%BB%B6%E5%B0%81%E8%A3%85%E4%B8%8E%E7%AE%A1%E7%90%86%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/</guid>
      <description>&lt;h1 id=&#34;1-前言&#34;&gt;1. 前言&lt;/h1&gt;
&lt;p&gt;在前端开发中，业务组件的封装与管理是一个常见的难题。当多个项目共用同一个业务组件时，如何平衡不同项目的需求差异，同时保持组件的可维护性和可扩展性，成为了一个亟待解决的问题。&lt;/p&gt;
&lt;h1 id=&#34;2-如何应对多项目需求差异&#34;&gt;2 如何应对多项目需求差异&lt;/h1&gt;
&lt;p&gt;在业务组件封装过程中，我们常常会遇到这样的问题：项目 &lt;code&gt;A&lt;/code&gt; 和项目 &lt;code&gt;B&lt;/code&gt; 都使用了某个业务组件，但项目 &lt;code&gt;A&lt;/code&gt; 迭代了需求，而这个需求在项目 &lt;code&gt;B&lt;/code&gt; 中却用不到。如果这次为了满足项目 &lt;code&gt;A&lt;/code&gt; 的需求而修改组件，那么未来项目 &lt;code&gt;B&lt;/code&gt; 也可能出现类似但不完全相同的需求，难道每次都要通过特判来解决吗？&lt;/p&gt;
&lt;p&gt;实际上，业务组件的问题并非孤立存在，而是整个前端项目开发流程中的一个环节。我们需要从更高的层次、更宏观的角度去看待，梳理整个前端项目的开发流程，预见可能面临的问题，并逐一讨论解决方案、进行应用和验证，而不仅仅是解决业务组件自身的问题。&lt;/p&gt;
&lt;h1 id=&#34;3-期望的应用场景&#34;&gt;3. 期望的应用场景&lt;/h1&gt;
&lt;p&gt;我们期望构建一个高效、灵活的前端开发流程，具体场景如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;提供一个基础的项目模板，其中包含常用的业务组件，如登录注册、首页、个人中心、用户管理等。这样，新的项目可以直接基于模板启动，减少重复工作。&lt;/li&gt;
&lt;li&gt;通过动态配置主题色等功能，满足客户项目的定制化需求。例如，不同客户可能对界面风格有不同偏好，通过风格配置平台可以快速实现定制。&lt;/li&gt;
&lt;li&gt;在菜单管理中配置好路由，从业务组件库中引入所需的业务组件。如果现有组件不满足需求，则可以迭代现有组件或新增组件。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;4-通用性与灵活性&#34;&gt;4. 通用性与灵活性&lt;/h1&gt;
&lt;p&gt;业务组件应具备通用功能，能够满足大部分项目的需求，从而减少重复开发，提高开发效率。当遇到特殊需求时，可以采用组合式函数的方式，将逻辑单独抽离出来复用。同时，提供样式自定义功能，通过增加一个 &lt;code&gt;.vue&lt;/code&gt; 文件来实现样式定制，从而复用组合式函数。这种做法既保持了组件的通用性，又提供了足够的灵活性来应对不同项目的需求。&lt;/p&gt;
&lt;h1 id=&#34;5-确保质量和稳定性&#34;&gt;5. 确保质量和稳定性&lt;/h1&gt;
&lt;p&gt;为了保证业务组件的质量和稳定性，单元测试是必不可少的环节。主要包括以下两个方面：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;对组件的逻辑代码进行测试，确保其功能正确无误。&lt;/li&gt;
&lt;li&gt;测试组件之间的交互是否符合预期，例如父子组件之间的数据传递、事件触发等。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;6-满足多样化需求&#34;&gt;6. 满足多样化需求&lt;/h1&gt;
&lt;p&gt;业务组件的风格动态设置是一个关键问题。以当前常见的&lt;code&gt;明亮&lt;/code&gt;和&lt;code&gt;暗黑&lt;/code&gt;风格为例，问题的根本原因并不在于组件自身，而在于项目。因此，需要设置的不是业务组件的主题，而是项目的主题。而项目是基于我们提供的项目模板开发的，所以项目模板需要提供风格动态设置功能。&lt;/p&gt;
&lt;p&gt;最佳的实现方式是通过可视化页面进行配置，然后生成 &lt;code&gt;CSS&lt;/code&gt; 文件，将其引入到项目中进行配置。这就需要开发一个可视化主题配置平台，比如 &lt;code&gt;Arco Design Lab&lt;/code&gt; 平台（&lt;a href=&#34;https://arco.design/docs/designlab/guideline&#34;&gt;平台使用指南&lt;/a&gt;），能够很好地满足这一需求。&lt;/p&gt;
&lt;h1 id=&#34;7-总结&#34;&gt;7. 总结&lt;/h1&gt;
&lt;p&gt;通过建立一套完整的开发规范、提供风格动态设置功能，我们可以有效地解决多项目需求差异的问题，提高开发效率和质量。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="1-前言">1. 前言</h1>
<p>在前端开发中，业务组件的封装与管理是一个常见的难题。当多个项目共用同一个业务组件时，如何平衡不同项目的需求差异，同时保持组件的可维护性和可扩展性，成为了一个亟待解决的问题。</p>
<h1 id="2-如何应对多项目需求差异">2 如何应对多项目需求差异</h1>
<p>在业务组件封装过程中，我们常常会遇到这样的问题：项目 <code>A</code> 和项目 <code>B</code> 都使用了某个业务组件，但项目 <code>A</code> 迭代了需求，而这个需求在项目 <code>B</code> 中却用不到。如果这次为了满足项目 <code>A</code> 的需求而修改组件，那么未来项目 <code>B</code> 也可能出现类似但不完全相同的需求，难道每次都要通过特判来解决吗？</p>
<p>实际上，业务组件的问题并非孤立存在，而是整个前端项目开发流程中的一个环节。我们需要从更高的层次、更宏观的角度去看待，梳理整个前端项目的开发流程，预见可能面临的问题，并逐一讨论解决方案、进行应用和验证，而不仅仅是解决业务组件自身的问题。</p>
<h1 id="3-期望的应用场景">3. 期望的应用场景</h1>
<p>我们期望构建一个高效、灵活的前端开发流程，具体场景如下：</p>
<ol>
<li>提供一个基础的项目模板，其中包含常用的业务组件，如登录注册、首页、个人中心、用户管理等。这样，新的项目可以直接基于模板启动，减少重复工作。</li>
<li>通过动态配置主题色等功能，满足客户项目的定制化需求。例如，不同客户可能对界面风格有不同偏好，通过风格配置平台可以快速实现定制。</li>
<li>在菜单管理中配置好路由，从业务组件库中引入所需的业务组件。如果现有组件不满足需求，则可以迭代现有组件或新增组件。</li>
</ol>
<h1 id="4-通用性与灵活性">4. 通用性与灵活性</h1>
<p>业务组件应具备通用功能，能够满足大部分项目的需求，从而减少重复开发，提高开发效率。当遇到特殊需求时，可以采用组合式函数的方式，将逻辑单独抽离出来复用。同时，提供样式自定义功能，通过增加一个 <code>.vue</code> 文件来实现样式定制，从而复用组合式函数。这种做法既保持了组件的通用性，又提供了足够的灵活性来应对不同项目的需求。</p>
<h1 id="5-确保质量和稳定性">5. 确保质量和稳定性</h1>
<p>为了保证业务组件的质量和稳定性，单元测试是必不可少的环节。主要包括以下两个方面：</p>
<ol>
<li>对组件的逻辑代码进行测试，确保其功能正确无误。</li>
<li>测试组件之间的交互是否符合预期，例如父子组件之间的数据传递、事件触发等。</li>
</ol>
<h1 id="6-满足多样化需求">6. 满足多样化需求</h1>
<p>业务组件的风格动态设置是一个关键问题。以当前常见的<code>明亮</code>和<code>暗黑</code>风格为例，问题的根本原因并不在于组件自身，而在于项目。因此，需要设置的不是业务组件的主题，而是项目的主题。而项目是基于我们提供的项目模板开发的，所以项目模板需要提供风格动态设置功能。</p>
<p>最佳的实现方式是通过可视化页面进行配置，然后生成 <code>CSS</code> 文件，将其引入到项目中进行配置。这就需要开发一个可视化主题配置平台，比如 <code>Arco Design Lab</code> 平台（<a href="https://arco.design/docs/designlab/guideline">平台使用指南</a>），能够很好地满足这一需求。</p>
<h1 id="7-总结">7. 总结</h1>
<p>通过建立一套完整的开发规范、提供风格动态设置功能，我们可以有效地解决多项目需求差异的问题，提高开发效率和质量。</p>
]]></content:encoded>
    </item>
    <item>
      <title>展厅3D项目实现方案</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/%E5%B1%95%E5%8E%853d%E9%A1%B9%E7%9B%AE%E5%AE%9E%E7%8E%B0%E6%96%B9%E6%A1%88/</link>
      <pubDate>Thu, 24 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/%E5%B1%95%E5%8E%853d%E9%A1%B9%E7%9B%AE%E5%AE%9E%E7%8E%B0%E6%96%B9%E6%A1%88/</guid>
      <description>&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;
&lt;p&gt;本项目旨在开发一个展厅&lt;code&gt;3D&lt;/code&gt;展示系统，主要功能为监控大屏与&lt;code&gt;3D&lt;/code&gt;城市沙盘显示。项目涉及两台电脑屏幕，分别标记为&lt;code&gt;A&lt;/code&gt;和&lt;code&gt;B&lt;/code&gt;。&lt;code&gt;A&lt;/code&gt;屏幕用于展示&lt;code&gt;3D&lt;/code&gt;城市沙盘，用户点击沙盘中的特定区域时，&lt;code&gt;B&lt;/code&gt;屏幕将显示与该区域相关的效果视频。因此，项目的核心在于如何构建&lt;code&gt;3D&lt;/code&gt;城市沙盘以及实现两台电脑之间的通信功能。&lt;/p&gt;
&lt;h1 id=&#34;解决方案&#34;&gt;解决方案&lt;/h1&gt;
&lt;p&gt;最初计划使用&lt;code&gt;Three.js&lt;/code&gt;来开发&lt;code&gt;3D&lt;/code&gt;城市沙盘，并通过&lt;code&gt;Electron&lt;/code&gt;开发两个独立的应用程序，分别部署在&lt;code&gt;A&lt;/code&gt;和&lt;code&gt;B&lt;/code&gt;电脑上以实现通信功能。然而，在项目推进过程中，我们发现&lt;code&gt;3D&lt;/code&gt;城市沙盘可以通过视频形式实现，仅需由&lt;code&gt;UI&lt;/code&gt;设计团队制作一个&lt;code&gt;3D&lt;/code&gt;城市沙盘视频即可。对于沙盘大屏的左右旋转功能，可以通过捕获手势事件来控制视频播放器的快进和后退操作，从而避免了使用&lt;code&gt;Three.js&lt;/code&gt;开发&lt;code&gt;3D&lt;/code&gt;沙盘的复杂工作。&lt;/p&gt;
&lt;h1 id=&#34;电脑间通信验证&#34;&gt;电脑间通信验证&lt;/h1&gt;
&lt;p&gt;基于&lt;code&gt;electron-vite-vue&lt;/code&gt;和&lt;code&gt;ws&lt;/code&gt;框架，我们开发了两个应用程序：客户端和服务端。客户端部署在主屏（&lt;code&gt;A&lt;/code&gt;电脑），服务端部署在副屏（&lt;code&gt;B&lt;/code&gt;电脑）。当系统启动时，服务端将在本地创建一个&lt;code&gt;WebSocket&lt;/code&gt;服务器，监听&lt;code&gt;8080&lt;/code&gt;端口。客户端则创建一个&lt;code&gt;WebSocket&lt;/code&gt;客户端实例，连接至该服务器，从而实现两台电脑之间的通信功能。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/electron-vite/electron-vite-vue&#34;&gt;electron-vite-vue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/websockets/ws&#34;&gt;ws&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;假设&lt;code&gt;B&lt;/code&gt;电脑的&lt;code&gt;IP&lt;/code&gt;地址为&lt;code&gt;192.168.28.112&lt;/code&gt;，我们首先在&lt;code&gt;B&lt;/code&gt;电脑上创建一个&lt;code&gt;WebSocket&lt;/code&gt;服务器，监听&lt;code&gt;8080&lt;/code&gt;端口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;WebSocket&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ws&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;wss&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;WebSocket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8080&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;wss&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;connection&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ws&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;ws&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;message&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;incoming&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;received: %s&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;ws&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;something&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;ws&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;close&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;clear&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;client disconnected&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接下来，在&lt;code&gt;A&lt;/code&gt;电脑上创建一个新的&lt;code&gt;WebSocket&lt;/code&gt;客户端实例，连接到&lt;code&gt;B&lt;/code&gt;电脑的&lt;code&gt;WebSocket&lt;/code&gt;服务器，用于发送消息：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;WebSocket&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ws&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 本地调试
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// const ws = new WebSocket(&amp;#39;ws://localhost:8080&amp;#39;);  
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 连接`B`电脑的 `WebSocket` 服务器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ws&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;WebSocket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ws://192.168.28.112:8080&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;ws&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;open&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;connected&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;setInterval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;ws&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Hello Server!&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;Math&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;random&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;ws&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;message&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;incoming&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;ws&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;close&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;clear&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;disconnected&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;ws&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;error&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;WebSocket Error: &amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过上述实现，&lt;code&gt;A&lt;/code&gt;和&lt;code&gt;B&lt;/code&gt;电脑之间的通信效果如下：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202504231100832.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202504231101378.png&#34;&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="前言">前言</h1>
<p>本项目旨在开发一个展厅<code>3D</code>展示系统，主要功能为监控大屏与<code>3D</code>城市沙盘显示。项目涉及两台电脑屏幕，分别标记为<code>A</code>和<code>B</code>。<code>A</code>屏幕用于展示<code>3D</code>城市沙盘，用户点击沙盘中的特定区域时，<code>B</code>屏幕将显示与该区域相关的效果视频。因此，项目的核心在于如何构建<code>3D</code>城市沙盘以及实现两台电脑之间的通信功能。</p>
<h1 id="解决方案">解决方案</h1>
<p>最初计划使用<code>Three.js</code>来开发<code>3D</code>城市沙盘，并通过<code>Electron</code>开发两个独立的应用程序，分别部署在<code>A</code>和<code>B</code>电脑上以实现通信功能。然而，在项目推进过程中，我们发现<code>3D</code>城市沙盘可以通过视频形式实现，仅需由<code>UI</code>设计团队制作一个<code>3D</code>城市沙盘视频即可。对于沙盘大屏的左右旋转功能，可以通过捕获手势事件来控制视频播放器的快进和后退操作，从而避免了使用<code>Three.js</code>开发<code>3D</code>沙盘的复杂工作。</p>
<h1 id="电脑间通信验证">电脑间通信验证</h1>
<p>基于<code>electron-vite-vue</code>和<code>ws</code>框架，我们开发了两个应用程序：客户端和服务端。客户端部署在主屏（<code>A</code>电脑），服务端部署在副屏（<code>B</code>电脑）。当系统启动时，服务端将在本地创建一个<code>WebSocket</code>服务器，监听<code>8080</code>端口。客户端则创建一个<code>WebSocket</code>客户端实例，连接至该服务器，从而实现两台电脑之间的通信功能。</p>
<ol>
<li><a href="https://github.com/electron-vite/electron-vite-vue">electron-vite-vue</a></li>
<li><a href="https://github.com/websockets/ws">ws</a></li>
</ol>
<p>假设<code>B</code>电脑的<code>IP</code>地址为<code>192.168.28.112</code>，我们首先在<code>B</code>电脑上创建一个<code>WebSocket</code>服务器，监听<code>8080</code>端口：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">WebSocket</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;ws&#39;</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">wss</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebSocket</span><span class="p">.</span><span class="nx">Server</span><span class="p">({</span> <span class="nx">port</span><span class="o">:</span> <span class="mi">8080</span> <span class="p">});</span>  
</span></span><span class="line"><span class="cl"><span class="nx">wss</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;connection&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="nx">connection</span><span class="p">(</span><span class="nx">ws</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">  <span class="nx">ws</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;message&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="nx">incoming</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;received: %s&#39;</span><span class="p">,</span> <span class="nx">message</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl">  <span class="p">});</span>  
</span></span><span class="line"><span class="cl">  <span class="nx">ws</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s1">&#39;something&#39;</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl">  <span class="nx">ws</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;close&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="nx">clear</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;client disconnected&#39;</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl">  <span class="p">});</span>  
</span></span><span class="line"><span class="cl"><span class="p">});</span>  
</span></span></code></pre></div><p>接下来，在<code>A</code>电脑上创建一个新的<code>WebSocket</code>客户端实例，连接到<code>B</code>电脑的<code>WebSocket</code>服务器，用于发送消息：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">WebSocket</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;ws&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 本地调试
</span></span></span><span class="line"><span class="cl"><span class="c1">// const ws = new WebSocket(&#39;ws://localhost:8080&#39;);  
</span></span></span><span class="line"><span class="cl"><span class="c1">// 连接`B`电脑的 `WebSocket` 服务器
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="nx">ws</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebSocket</span><span class="p">(</span><span class="s1">&#39;ws://192.168.28.112:8080&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">ws</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;open&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="nx">open</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;connected&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">setInterval</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">ws</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s1">&#39;Hello Server!&#39;</span> <span class="o">+</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span> <span class="mi">3000</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="nx">ws</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;message&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="nx">incoming</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="nx">ws</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;close&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="nx">clear</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;disconnected&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="nx">ws</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="nx">error</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s1">&#39;WebSocket Error: &#39;</span><span class="p">,</span> <span class="nx">err</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>通过上述实现，<code>A</code>和<code>B</code>电脑之间的通信效果如下：</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202504231100832.png"></p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202504231101378.png"></p>
]]></content:encoded>
    </item>
    <item>
      <title>Pinia持久化插件 pinia-plugin-persistedstate 的基本使用</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/pinia%E6%8C%81%E4%B9%85%E5%8C%96%E6%8F%92%E4%BB%B6-pinia-plugin-persistedstate-%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/</link>
      <pubDate>Mon, 14 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/pinia%E6%8C%81%E4%B9%85%E5%8C%96%E6%8F%92%E4%BB%B6-pinia-plugin-persistedstate-%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/</guid>
      <description>&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;
&lt;p&gt;在&lt;code&gt;Vue&lt;/code&gt;项目开发过程中，状态管理是至关重要的环节。随着&lt;code&gt;Pinia&lt;/code&gt;的推出，它凭借更简洁直观的&lt;code&gt;API&lt;/code&gt;，逐渐成为&lt;code&gt;Vuex&lt;/code&gt;的有力替代品。为了进一步简化本地存储的管理，&lt;a href=&#34;https://www.npmjs.com/package/pinia-plugin-persistedstate&#34;&gt;pinia-plugin-persistedstate&lt;/a&gt; 插件应运而生，它能够帮助开发者轻松实现状态的持久化。&lt;/p&gt;
&lt;p&gt;本文将详细介绍如何使用该插件，并解决在跨项目登录时由于数据格式不一致导致的问题。&lt;/p&gt;
&lt;h1 id=&#34;安装插件&#34;&gt;安装插件&lt;/h1&gt;
&lt;p&gt;在项目的根目录下运行以下命令以安装插件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;npm&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;pinia&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;plugin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;persistedstate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;随后，在&lt;code&gt;main.ts&lt;/code&gt;文件中引入并配置插件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createPinia&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;pinia&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;piniaPluginPersistedstate&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;pinia-plugin-persistedstate&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;pinia&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createPinia&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;pinia&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;use&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;piniaPluginPersistedstate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;完成以上步骤后，&lt;code&gt;Pinia&lt;/code&gt;便具备了持久化功能。&lt;/p&gt;
&lt;h1 id=&#34;基本使用&#34;&gt;基本使用&lt;/h1&gt;
&lt;p&gt;假设我们需要管理用户信息&lt;code&gt;userInfo&lt;/code&gt;，并将其持久化到本地存储中，那么就可以这样实现：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;defineStore&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;pinia&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;useUserInfoStore&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;defineStore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;userInfo&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;userInfo&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;null&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;persist&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;actions&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;setUserInfo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;info&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;any&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;userInfo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;按照上述配置，用户信息将自动持久化到本地存储中。&lt;/p&gt;
&lt;h1 id=&#34;仅持久化对象中的特定字段&#34;&gt;仅持久化对象中的特定字段&lt;/h1&gt;
&lt;p&gt;在实际应用中，开发者可能会面临跨项目登录时出现的兼容性问题。具体场景为：用户在项目&lt;code&gt;A&lt;/code&gt;完成登录操作后，随即打开项目&lt;code&gt;B&lt;/code&gt;。由于&lt;code&gt;Token&lt;/code&gt;的复用机制，项目&lt;code&gt;B&lt;/code&gt;会自动完成登录流程。然而，在尝试获取用户信息&lt;code&gt;userInfo&lt;/code&gt;时，由于不同项目对数据格式的定义存在差异，导致项目&lt;code&gt;B&lt;/code&gt;无法准确获取用户的&lt;code&gt;ID&lt;/code&gt;，进而无法基于此&lt;code&gt;ID&lt;/code&gt;发起正确的网络请求。具体表现如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;项目&lt;code&gt;A&lt;/code&gt;的数据格式：&lt;code&gt;{ name: &#39;xiaoming&#39;, nick_name: &#39;小明&#39;, userID: &#39;9527&#39; }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;项目&lt;code&gt;B&lt;/code&gt;的数据格式：&lt;code&gt;{ userInfo: { name: &#39;xiaoming&#39;, nick_name: &#39;小明&#39;, userID: &#39;9527&#39; } }&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;由于插件默认将整个&lt;code&gt;state&lt;/code&gt;对象存储起来，导致数据多了一层&lt;code&gt;userInfo&lt;/code&gt;外壳，从而引发格式不一致的问题。&lt;/p&gt;
&lt;p&gt;为了去掉&lt;code&gt;userInfo&lt;/code&gt;这一层外壳，我们需要自定义序列化和反序列化逻辑。修改后的&lt;code&gt;Store&lt;/code&gt;配置如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;defineStore&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;pinia&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;useUserInfoStore&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;defineStore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;userInfo&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;userInfo&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;null&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;persist&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;userInfo&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;storage&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;localStorage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;paths&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;userInfo&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 明确声明要持久化的字段
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nx&#34;&gt;serializer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nx&#34;&gt;serialize&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;state&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;any&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;JSON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;stringify&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;userInfo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nx&#34;&gt;deserialize&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;str&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;userInfo&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;JSON.parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;any&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;actions&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;setUserInfo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;info&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;any&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;userInfo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;经过上述配置，用户信息的存储结构变为&lt;code&gt;{ name: &#39;xiaoming&#39;, nick_name: &#39;小明&#39;, userID: &#39;9527&#39; }&lt;/code&gt;，不再有额外的&lt;code&gt;userInfo&lt;/code&gt;外壳，从而解决了跨项目登录时的格式不一致问题。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="前言">前言</h1>
<p>在<code>Vue</code>项目开发过程中，状态管理是至关重要的环节。随着<code>Pinia</code>的推出，它凭借更简洁直观的<code>API</code>，逐渐成为<code>Vuex</code>的有力替代品。为了进一步简化本地存储的管理，<a href="https://www.npmjs.com/package/pinia-plugin-persistedstate">pinia-plugin-persistedstate</a> 插件应运而生，它能够帮助开发者轻松实现状态的持久化。</p>
<p>本文将详细介绍如何使用该插件，并解决在跨项目登录时由于数据格式不一致导致的问题。</p>
<h1 id="安装插件">安装插件</h1>
<p>在项目的根目录下运行以下命令以安装插件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="nx">npm</span> <span class="nx">i</span> <span class="nx">pinia</span><span class="o">-</span><span class="nx">plugin</span><span class="o">-</span><span class="nx">persistedstate</span>
</span></span></code></pre></div><p>随后，在<code>main.ts</code>文件中引入并配置插件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">createPinia</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;pinia&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">piniaPluginPersistedstate</span> <span class="kr">from</span> <span class="s1">&#39;pinia-plugin-persistedstate&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">pinia</span> <span class="o">=</span> <span class="nx">createPinia</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nx">pinia</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">piniaPluginPersistedstate</span><span class="p">)</span>
</span></span></code></pre></div><p>完成以上步骤后，<code>Pinia</code>便具备了持久化功能。</p>
<h1 id="基本使用">基本使用</h1>
<p>假设我们需要管理用户信息<code>userInfo</code>，并将其持久化到本地存储中，那么就可以这样实现：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">defineStore</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;pinia&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">useUserInfoStore</span> <span class="o">=</span> <span class="nx">defineStore</span><span class="p">(</span><span class="s1">&#39;userInfo&#39;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">state</span><span class="o">:</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">({</span>
</span></span><span class="line"><span class="cl">        <span class="nx">userInfo</span>: <span class="kt">null</span> <span class="kr">as</span> <span class="kt">any</span>
</span></span><span class="line"><span class="cl">    <span class="p">}),</span>
</span></span><span class="line"><span class="cl">    <span class="nx">persist</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">actions</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">setUserInfo</span><span class="p">(</span><span class="nx">info</span>: <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">this</span><span class="p">.</span><span class="nx">userInfo</span> <span class="o">=</span> <span class="nx">info</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>按照上述配置，用户信息将自动持久化到本地存储中。</p>
<h1 id="仅持久化对象中的特定字段">仅持久化对象中的特定字段</h1>
<p>在实际应用中，开发者可能会面临跨项目登录时出现的兼容性问题。具体场景为：用户在项目<code>A</code>完成登录操作后，随即打开项目<code>B</code>。由于<code>Token</code>的复用机制，项目<code>B</code>会自动完成登录流程。然而，在尝试获取用户信息<code>userInfo</code>时，由于不同项目对数据格式的定义存在差异，导致项目<code>B</code>无法准确获取用户的<code>ID</code>，进而无法基于此<code>ID</code>发起正确的网络请求。具体表现如下：</p>
<ol>
<li>项目<code>A</code>的数据格式：<code>{ name: 'xiaoming', nick_name: '小明', userID: '9527' }</code></li>
<li>项目<code>B</code>的数据格式：<code>{ userInfo: { name: 'xiaoming', nick_name: '小明', userID: '9527' } }</code></li>
</ol>
<p>由于插件默认将整个<code>state</code>对象存储起来，导致数据多了一层<code>userInfo</code>外壳，从而引发格式不一致的问题。</p>
<p>为了去掉<code>userInfo</code>这一层外壳，我们需要自定义序列化和反序列化逻辑。修改后的<code>Store</code>配置如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">defineStore</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;pinia&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">useUserInfoStore</span> <span class="o">=</span> <span class="nx">defineStore</span><span class="p">(</span><span class="s1">&#39;userInfo&#39;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">state</span><span class="o">:</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">({</span>
</span></span><span class="line"><span class="cl">        <span class="nx">userInfo</span>: <span class="kt">null</span> <span class="kr">as</span> <span class="kt">any</span>
</span></span><span class="line"><span class="cl">    <span class="p">}),</span>
</span></span><span class="line"><span class="cl">    <span class="nx">persist</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">key</span><span class="o">:</span> <span class="s1">&#39;userInfo&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">storage</span>: <span class="kt">localStorage</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">paths</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;userInfo&#39;</span><span class="p">],</span> <span class="c1">// 明确声明要持久化的字段
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="nx">serializer</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">serialize</span><span class="o">:</span> <span class="p">(</span><span class="nx">state</span>: <span class="kt">any</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">state</span><span class="p">.</span><span class="nx">userInfo</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="nx">deserialize</span><span class="o">:</span> <span class="p">(</span><span class="nx">str</span>: <span class="kt">string</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">({</span> <span class="nx">userInfo</span>: <span class="kt">JSON.parse</span><span class="p">(</span><span class="nx">str</span><span class="p">)</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="kr">as</span> <span class="kt">any</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">actions</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">setUserInfo</span><span class="p">(</span><span class="nx">info</span>: <span class="kt">any</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">this</span><span class="p">.</span><span class="nx">userInfo</span> <span class="o">=</span> <span class="nx">info</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>经过上述配置，用户信息的存储结构变为<code>{ name: 'xiaoming', nick_name: '小明', userID: '9527' }</code>，不再有额外的<code>userInfo</code>外壳，从而解决了跨项目登录时的格式不一致问题。</p>
<h1 id="其他配置选项">其他配置选项</h1>
<p>在使用该插件时，虽然主要需求是“仅持久化对象中的特定字段”，因此只使用了<code>serializer</code>配置项，但插件还支持其他功能。以下是部分可选配置：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">createPinia</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;pinia&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">piniaPluginPersistedstate</span> <span class="kr">from</span> <span class="s1">&#39;pinia-plugin-persistedstate&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">pinia</span> <span class="o">=</span> <span class="nx">createPinia</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">pinia</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">piniaPluginPersistedstate</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">storage</span>: <span class="kt">localStorage</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">key</span><span class="o">:</span> <span class="s1">&#39;myCustomStoreKey&#39;</span><span class="p">,</span> <span class="c1">// 自定义存储键名
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">debug</span>: <span class="kt">true</span><span class="p">,</span> <span class="c1">// 启用调试
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">serializer</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">serialize</span><span class="p">(</span><span class="nx">state</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// 自定义序列化逻辑
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="k">return</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">state</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">deserialize</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// 自定义反序列化逻辑
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="k">return</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">beforeHydrate</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 在恢复状态之前执行的逻辑
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Before hydrating:&#39;</span><span class="p">,</span> <span class="nx">context</span><span class="p">.</span><span class="nx">store</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">afterHydrate</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 在恢复状态之后执行的逻辑
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;After hydrating:&#39;</span><span class="p">,</span> <span class="nx">context</span><span class="p">.</span><span class="nx">store</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">pick</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;userInfo.name&#39;</span><span class="p">,</span> <span class="s1">&#39;userInfo.email&#39;</span><span class="p">],</span> <span class="c1">// 只持久化 userInfo 下的 name 和 email 属性
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="c1">// omit: [&#39;userInfo.password&#39;], // 省略 userInfo 下的 password 属性（与 pick 互斥）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// ... 定义你的 store ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">pinia</span><span class="p">;</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>unplugin-vue-router 的基本使用</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/unplugin-vue-router-%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/</link>
      <pubDate>Sun, 29 Dec 2024 00:00:00 +0000</pubDate>
      <guid>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/unplugin-vue-router-%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/</guid>
      <description>&lt;h1 id=&#34;1-前言&#34;&gt;1. 前言&lt;/h1&gt;
&lt;p&gt;在&lt;code&gt;Vue3&lt;/code&gt;开发过程中，每次创建新的页面都需要注册路由，需要在&lt;code&gt;src/router.ts&lt;/code&gt;中新增页面的路径，并将&lt;code&gt;URL&lt;/code&gt;路径映射到组件中，如下所示：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createMemoryHistory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createRouter&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;vue-router&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;HomePageView&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;./HomePageView.vue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;DevListView&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;./DevListView.vue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;routes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;component&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;HomePageView&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/DevListView&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;component&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;DevListView&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;router&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createRouter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;history&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;createMemoryHistory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;routes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;虽然看起来工作量不大，但如果页面特别多，就会感到繁琐。即使是微小的改动，如组件名的修改，也需要在路由文件中反复确认，反复如此就会感到不便。为了简化这部分工作，我想到了一个解决方案，那就是开发一个&lt;code&gt;Vue3&lt;/code&gt;菜单路由生成工具，只需填写组件的中文名称，根据树形结构生成一个与&lt;code&gt;routes&lt;/code&gt;结构相同的数组，然后替换使用即可。但还是觉得不够好，随后想到既然自己能发现这个问题，别人可能早已有了应对方案。接着，我就发现了 &lt;a href=&#34;https://uvr.esm.is/&#34;&gt;unplugin-vue-router&lt;/a&gt; 插件。&lt;/p&gt;
&lt;h1 id=&#34;2-配置&#34;&gt;2. 配置&lt;/h1&gt;
&lt;h2 id=&#34;21-安装&#34;&gt;2.1 安装&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;npm&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;install&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;D&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;unplugin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;vue&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;router&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;22-viteconfigts&#34;&gt;2.2 vite.config.ts&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;VueRouter&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;unplugin-vue-router/vite&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;defineConfig&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;plugins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;VueRouter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;cm&#34;&gt;/* options */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// ⚠️ Vue must be placed after VueRouter()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;Vue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;23-tsconfigjson&#34;&gt;2.3 tsconfig.json&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;include&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// other files...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;./typed-router.d.ts&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;compilerOptions&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;moduleResolution&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Bundler&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;24-vite-envdts&#34;&gt;2.4 vite-env.d.ts&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;/// &amp;lt;reference types=&amp;#34;unplugin-vue-router/client&amp;#34; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;3-应用&#34;&gt;3. 应用&lt;/h1&gt;
&lt;h2 id=&#34;31-常规方式&#34;&gt;3.1 常规方式&lt;/h2&gt;
&lt;p&gt;因为项目布局是基于&lt;code&gt;Element Plus&lt;/code&gt;组件库的&lt;code&gt;&amp;lt;el-container&amp;gt;&lt;/code&gt;搭建的，其中对&lt;code&gt;&amp;lt;e-main&amp;gt;&lt;/code&gt;进行了处理，&lt;code&gt;&amp;lt;router-view&amp;gt;&lt;/code&gt;是 Vue Router 的一个内置组件，用于渲染匹配当前路由的组件，如下所示：&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="1-前言">1. 前言</h1>
<p>在<code>Vue3</code>开发过程中，每次创建新的页面都需要注册路由，需要在<code>src/router.ts</code>中新增页面的路径，并将<code>URL</code>路径映射到组件中，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">createMemoryHistory</span><span class="p">,</span> <span class="nx">createRouter</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;vue-router&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">HomePageView</span> <span class="kr">from</span> <span class="s1">&#39;./HomePageView.vue&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">DevListView</span> <span class="kr">from</span> <span class="s1">&#39;./DevListView.vue&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">routes</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">path</span><span class="o">:</span> <span class="s1">&#39;/&#39;</span><span class="p">,</span> <span class="nx">component</span>: <span class="kt">HomePageView</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">path</span><span class="o">:</span> <span class="s1">&#39;/DevListView&#39;</span><span class="p">,</span> <span class="nx">component</span>: <span class="kt">DevListView</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">createRouter</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">history</span>: <span class="kt">createMemoryHistory</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">routes</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><p>虽然看起来工作量不大，但如果页面特别多，就会感到繁琐。即使是微小的改动，如组件名的修改，也需要在路由文件中反复确认，反复如此就会感到不便。为了简化这部分工作，我想到了一个解决方案，那就是开发一个<code>Vue3</code>菜单路由生成工具，只需填写组件的中文名称，根据树形结构生成一个与<code>routes</code>结构相同的数组，然后替换使用即可。但还是觉得不够好，随后想到既然自己能发现这个问题，别人可能早已有了应对方案。接着，我就发现了 <a href="https://uvr.esm.is/">unplugin-vue-router</a> 插件。</p>
<h1 id="2-配置">2. 配置</h1>
<h2 id="21-安装">2.1 安装</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="nx">npm</span> <span class="nx">install</span> <span class="o">-</span><span class="nx">D</span> <span class="nx">unplugin</span><span class="o">-</span><span class="nx">vue</span><span class="o">-</span><span class="nx">router</span>
</span></span></code></pre></div><h2 id="22-viteconfigts">2.2 vite.config.ts</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">VueRouter</span> <span class="kr">from</span> <span class="s1">&#39;unplugin-vue-router/vite&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineConfig</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">plugins</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="nx">VueRouter</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="cm">/* options */</span>
</span></span><span class="line"><span class="cl">    <span class="p">}),</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// ⚠️ Vue must be placed after VueRouter()
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">Vue</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><h2 id="23-tsconfigjson">2.3 tsconfig.json</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;include&#34;</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// other files...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="s2">&#34;./typed-router.d.ts&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;compilerOptions&#34;</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="s2">&#34;moduleResolution&#34;</span><span class="o">:</span> <span class="s2">&#34;Bundler&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="24-vite-envdts">2.4 vite-env.d.ts</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="c1">/// &lt;reference types=&#34;unplugin-vue-router/client&#34; /&gt;
</span></span></span></code></pre></div><h1 id="3-应用">3. 应用</h1>
<h2 id="31-常规方式">3.1 常规方式</h2>
<p>因为项目布局是基于<code>Element Plus</code>组件库的<code>&lt;el-container&gt;</code>搭建的，其中对<code>&lt;e-main&gt;</code>进行了处理，<code>&lt;router-view&gt;</code>是 Vue Router 的一个内置组件，用于渲染匹配当前路由的组件，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">el-main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">router-view</span> <span class="na">v-slot</span><span class="o">=</span><span class="s">&#34;{ Component }&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">component</span> <span class="na">:is</span><span class="o">=</span><span class="s">&#34;Component&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">router-view</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">el-main</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>所以，<code>DevList.vue</code>和<code>DataList.vue</code>组件都在<code>&lt;e-main&gt;</code>中渲染显示，常规的组件文件结构，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="nx">src</span><span class="o">/</span><span class="nx">components</span><span class="o">/</span>
</span></span><span class="line"><span class="cl"><span class="err">├──</span> <span class="nx">Login</span><span class="p">.</span><span class="nx">vue</span>
</span></span><span class="line"><span class="cl"><span class="err">├──</span> <span class="nx">Register</span><span class="p">.</span><span class="nx">vue</span>
</span></span><span class="line"><span class="cl"><span class="err">├──</span> <span class="nx">Container</span><span class="p">.</span><span class="nx">vue</span>
</span></span><span class="line"><span class="cl"><span class="err">└──</span> <span class="nx">DevManagement</span>
</span></span><span class="line"><span class="cl">    <span class="err">├──</span> <span class="nx">DevList</span><span class="p">.</span><span class="nx">vue</span>
</span></span><span class="line"><span class="cl">    <span class="err">└──</span> <span class="nx">DataList</span><span class="p">.</span><span class="nx">vue</span>
</span></span></code></pre></div><p>然后，在<code>router.ts</code>文件中是这样的：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">createRouter</span><span class="p">,</span> <span class="nx">createWebHistory</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;vue-router&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Login</span> <span class="kr">from</span> <span class="s1">&#39;@/components/Login.vue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Register</span> <span class="kr">from</span> <span class="s1">&#39;@/components/Register.vue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Container</span> <span class="kr">from</span> <span class="s1">&#39;@/components/Container.vue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">DevList</span> <span class="kr">from</span> <span class="s1">&#39;@/components/DevManagement/DevList.vue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">DataList</span> <span class="kr">from</span> <span class="s1">&#39;@/components/DevManagement/DataList.vue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">routes</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">path</span><span class="o">:</span> <span class="s1">&#39;/login&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;Login&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span>: <span class="kt">Login</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">path</span><span class="o">:</span> <span class="s1">&#39;/register&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;Register&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span>: <span class="kt">Register</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">path</span><span class="o">:</span> <span class="s1">&#39;/&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;Container&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span>: <span class="kt">Container</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">children</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">path</span><span class="o">:</span> <span class="s1">&#39;DevManagement/DevList&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;DevList&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">component</span>: <span class="kt">DevList</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">path</span><span class="o">:</span> <span class="s1">&#39;DevManagement/DataList&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;DataList&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">component</span>: <span class="kt">DataList</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">createRouter</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">history</span>: <span class="kt">createWebHistory</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">BASE_URL</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">routes</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><h2 id="32-使用unplugin-vue-router方式">3.2 使用unplugin-vue-router方式</h2>
<p>需将<code>src/components</code>修改为<code>src/pages</code>，然后把登录页<code>Login.vue</code>重命名为<code>index.vue</code>，再创建一个<code>Container</code>文件夹和<code>Container.vue</code>相对应，这样就会自动识别<code>DevList.vue</code>和<code>DataList.vue</code>为<code>Container.vue</code>的子路由，其路由为<code>/Container/DevManagement/DevList</code>，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="nx">src</span><span class="o">/</span><span class="nx">pages</span><span class="o">/</span>
</span></span><span class="line"><span class="cl"><span class="err">├──</span> <span class="nx">index</span><span class="p">.</span><span class="nx">vue</span>
</span></span><span class="line"><span class="cl"><span class="err">├──</span> <span class="nx">Register</span><span class="p">.</span><span class="nx">vue</span>
</span></span><span class="line"><span class="cl"><span class="err">├──</span> <span class="nx">Container</span><span class="p">.</span><span class="nx">vue</span>
</span></span><span class="line"><span class="cl"><span class="err">└──</span> <span class="nx">Container</span>
</span></span><span class="line"><span class="cl">    <span class="err">└──</span> <span class="nx">DevManagement</span>
</span></span><span class="line"><span class="cl">        <span class="err">├──</span> <span class="nx">DevList</span><span class="p">.</span><span class="nx">vue</span>
</span></span><span class="line"><span class="cl">        <span class="err">└──</span> <span class="nx">DataList</span><span class="p">.</span><span class="nx">vue</span>
</span></span></code></pre></div><p>在<code>src/router.ts</code>文件中配置如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">createRouter</span><span class="p">,</span> <span class="nx">createWebHashHistory</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;vue-router&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">routes</span><span class="p">,</span> <span class="nx">handleHotUpdate</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;vue-router/auto-routes&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">createRouter</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">history</span>: <span class="kt">createWebHashHistory</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">routes</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// This will update routes at runtime without reloading the page
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">if</span> <span class="p">(</span><span class="kr">import</span><span class="p">.</span><span class="nx">meta</span><span class="p">.</span><span class="nx">hot</span><span class="p">)</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">  <span class="nx">handleHotUpdate</span><span class="p">(</span><span class="nx">router</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl"><span class="p">}</span> 
</span></span></code></pre></div><p>如此一来，后续只需要在<code>src/pages</code>文件夹下按约定的规范处理即可，不需要在<code>router.ts</code>文件中进行修改了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>组态页面渲染器通过npm包方式使用页面没有渲染成功的问题</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/%E7%BB%84%E6%80%81%E9%A1%B5%E9%9D%A2%E6%B8%B2%E6%9F%93%E5%99%A8%E9%80%9A%E8%BF%87npm%E5%8C%85%E6%96%B9%E5%BC%8F%E4%BD%BF%E7%94%A8%E9%A1%B5%E9%9D%A2%E6%B2%A1%E6%9C%89%E6%B8%B2%E6%9F%93%E6%88%90%E5%8A%9F%E7%9A%84%E9%97%AE%E9%A2%98/</link>
      <pubDate>Fri, 20 Dec 2024 00:00:00 +0000</pubDate>
      <guid>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/%E7%BB%84%E6%80%81%E9%A1%B5%E9%9D%A2%E6%B8%B2%E6%9F%93%E5%99%A8%E9%80%9A%E8%BF%87npm%E5%8C%85%E6%96%B9%E5%BC%8F%E4%BD%BF%E7%94%A8%E9%A1%B5%E9%9D%A2%E6%B2%A1%E6%9C%89%E6%B8%B2%E6%9F%93%E6%88%90%E5%8A%9F%E7%9A%84%E9%97%AE%E9%A2%98/</guid>
      <description>&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;
&lt;p&gt;在项目开发过程中，计划将组态页面的渲染器集成到组件库，以 &lt;code&gt;npm&lt;/code&gt; 包的形式供后续项目模板复用。如此一来，倘若组态页面渲染出现问题，便能简化修复与迭代工作。&lt;/p&gt;
&lt;h1 id=&#34;遇到问题&#34;&gt;遇到问题&lt;/h1&gt;
&lt;p&gt;采用本地引入方式开发完成后，切换至 &lt;code&gt;npm&lt;/code&gt; 包方式使用，此时面包屑可正常显示，然而组态页面部分却呈现空白状态。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202412181540840.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;分析问题&#34;&gt;分析问题&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;既然面包屑显示正常，那就表明通过向组件传入 &lt;code&gt;Router&lt;/code&gt; 对象进行相关操作并无问题，毕竟面包屑与组态页面共同构成了项目中的具体功能页面。不可能 &lt;code&gt;Router&lt;/code&gt; 有问题，面包屑却还能正常显示。&lt;/li&gt;
&lt;li&gt;推测组件打包生成 &lt;code&gt;npm&lt;/code&gt; 包后，自身未携带 &lt;code&gt;Vue&lt;/code&gt; 环境，致使 &lt;code&gt;Vue&lt;/code&gt; 内置特殊元素 &lt;code&gt;&amp;lt;component&amp;gt;&lt;/code&gt; 渲染失败，此前使用 &lt;code&gt;Pinia&lt;/code&gt; 时就碰到过类似情况。&lt;/li&gt;
&lt;li&gt;那么，该如何在组件里创建 &lt;code&gt;Vue&lt;/code&gt; 环境呢？&lt;/li&gt;
&lt;li&gt;要是不使用 &lt;code&gt;&amp;lt;component&amp;gt;&lt;/code&gt;，而改用渲染函数来实现会怎样呢？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;markRaw&lt;/code&gt; 的作用是什么？&lt;/li&gt;
&lt;li&gt;利用渲染函数实现后，发现打包成 &lt;code&gt;npm&lt;/code&gt; 包使用时依旧出现空白，这就说明并非 &lt;code&gt;&amp;lt;component&amp;gt;&lt;/code&gt; 的问题，如此一来，问题范围便缩小到组态页面的数据源上了。&lt;/li&gt;
&lt;li&gt;对比本地引用和 &lt;code&gt;npm&lt;/code&gt; 包两种方式下的数据请求差异，发现使用 &lt;code&gt;npm&lt;/code&gt; 包时，存在接口未发起请求的情况，进而定位到问题根源。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;问题原因&#34;&gt;问题原因&lt;/h1&gt;
&lt;p&gt;由于该渲染器是在项目中使用，其请求的 &lt;code&gt;baseURL&lt;/code&gt; 是通过 &lt;code&gt;window.location.origin&lt;/code&gt; 获取的。在本地引入使用时，本地开发服务器地址为 &lt;code&gt;http://localhost:3000/&lt;/code&gt;，并且在 &lt;code&gt;Vue&lt;/code&gt; 项目的 &lt;code&gt;vite.config.ts&lt;/code&gt; 中已做代理，所以请求正常。但当把渲染器代码移至组件库并以 &lt;code&gt;npm&lt;/code&gt; 包方式使用时，它自行获取的请求地址仍是 &lt;code&gt;http://localhost:3000/&lt;/code&gt;，并未经过代理处理，致使请求资源的接口异常，最终造成页面空白。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-tsx&#34; data-lang=&#34;tsx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;baseURL&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;meta&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;DEV&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;http://192.168.50.20&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;location&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;origin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;总结&#34;&gt;总结&lt;/h1&gt;
&lt;p&gt;解决 &lt;code&gt;Bug&lt;/code&gt; 的思路仍有待提升，自己还是过于急于求成了。刚察觉到问题的一点苗头，就贸然行事、妄下结论，实在有些武断。一开始认定是 &lt;code&gt;&amp;lt;component&amp;gt;&lt;/code&gt; 的问题，就应当采用排除法，不该如此笃定。实际上，只需用简单示例测试一下，便能排除该选项，也不至于耗费大量精力深入研究如何在组件里创建 &lt;code&gt;Vue&lt;/code&gt; 环境？如何用渲染函数实现组件？平白浪费了许多时间。&lt;/p&gt;
&lt;p&gt;每次解决完一个 &lt;code&gt;Bug&lt;/code&gt; 之后都会觉得，这个算啥问题，真的不值一提。可在解决过程中，却常常感到无奈，好几次都差点放弃。原本代码放在项目中使用正常，非要解耦，感觉像是没事找事。不过，最终还是坚持了下来，觉得应该差不多能弄清楚问题所在了。虽说花费的时间不太划算，就如同这篇文章写得好似没什么价值一般，但总结一下解决 &lt;code&gt;Bug&lt;/code&gt; 的心路历程，相信还是会有所收获的。积累到一定程度，便能为自己提供更多面对问题时的视角与启发。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="前言">前言</h1>
<p>在项目开发过程中，计划将组态页面的渲染器集成到组件库，以 <code>npm</code> 包的形式供后续项目模板复用。如此一来，倘若组态页面渲染出现问题，便能简化修复与迭代工作。</p>
<h1 id="遇到问题">遇到问题</h1>
<p>采用本地引入方式开发完成后，切换至 <code>npm</code> 包方式使用，此时面包屑可正常显示，然而组态页面部分却呈现空白状态。</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202412181540840.png"></p>
<h1 id="分析问题">分析问题</h1>
<ol>
<li>既然面包屑显示正常，那就表明通过向组件传入 <code>Router</code> 对象进行相关操作并无问题，毕竟面包屑与组态页面共同构成了项目中的具体功能页面。不可能 <code>Router</code> 有问题，面包屑却还能正常显示。</li>
<li>推测组件打包生成 <code>npm</code> 包后，自身未携带 <code>Vue</code> 环境，致使 <code>Vue</code> 内置特殊元素 <code>&lt;component&gt;</code> 渲染失败，此前使用 <code>Pinia</code> 时就碰到过类似情况。</li>
<li>那么，该如何在组件里创建 <code>Vue</code> 环境呢？</li>
<li>要是不使用 <code>&lt;component&gt;</code>，而改用渲染函数来实现会怎样呢？</li>
<li><code>markRaw</code> 的作用是什么？</li>
<li>利用渲染函数实现后，发现打包成 <code>npm</code> 包使用时依旧出现空白，这就说明并非 <code>&lt;component&gt;</code> 的问题，如此一来，问题范围便缩小到组态页面的数据源上了。</li>
<li>对比本地引用和 <code>npm</code> 包两种方式下的数据请求差异，发现使用 <code>npm</code> 包时，存在接口未发起请求的情况，进而定位到问题根源。</li>
</ol>
<h1 id="问题原因">问题原因</h1>
<p>由于该渲染器是在项目中使用，其请求的 <code>baseURL</code> 是通过 <code>window.location.origin</code> 获取的。在本地引入使用时，本地开发服务器地址为 <code>http://localhost:3000/</code>，并且在 <code>Vue</code> 项目的 <code>vite.config.ts</code> 中已做代理，所以请求正常。但当把渲染器代码移至组件库并以 <code>npm</code> 包方式使用时，它自行获取的请求地址仍是 <code>http://localhost:3000/</code>，并未经过代理处理，致使请求资源的接口异常，最终造成页面空白。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">baseURL</span> <span class="o">=</span> <span class="kr">import</span><span class="p">.</span><span class="nx">meta</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">DEV</span> <span class="o">?</span> <span class="s2">&#34;http://192.168.50.20&#34;</span> <span class="o">:</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">origin</span>
</span></span></code></pre></div><h1 id="总结">总结</h1>
<p>解决 <code>Bug</code> 的思路仍有待提升，自己还是过于急于求成了。刚察觉到问题的一点苗头，就贸然行事、妄下结论，实在有些武断。一开始认定是 <code>&lt;component&gt;</code> 的问题，就应当采用排除法，不该如此笃定。实际上，只需用简单示例测试一下，便能排除该选项，也不至于耗费大量精力深入研究如何在组件里创建 <code>Vue</code> 环境？如何用渲染函数实现组件？平白浪费了许多时间。</p>
<p>每次解决完一个 <code>Bug</code> 之后都会觉得，这个算啥问题，真的不值一提。可在解决过程中，却常常感到无奈，好几次都差点放弃。原本代码放在项目中使用正常，非要解耦，感觉像是没事找事。不过，最终还是坚持了下来，觉得应该差不多能弄清楚问题所在了。虽说花费的时间不太划算，就如同这篇文章写得好似没什么价值一般，但总结一下解决 <code>Bug</code> 的心路历程，相信还是会有所收获的。积累到一定程度，便能为自己提供更多面对问题时的视角与启发。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Web应用实现在手机端访问和使用方案</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/web%E5%BA%94%E7%94%A8%E5%AE%9E%E7%8E%B0%E5%9C%A8%E6%89%8B%E6%9C%BA%E7%AB%AF%E8%AE%BF%E9%97%AE%E5%92%8C%E4%BD%BF%E7%94%A8%E6%96%B9%E6%A1%88/</link>
      <pubDate>Fri, 01 Nov 2024 00:00:00 +0000</pubDate>
      <guid>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/web%E5%BA%94%E7%94%A8%E5%AE%9E%E7%8E%B0%E5%9C%A8%E6%89%8B%E6%9C%BA%E7%AB%AF%E8%AE%BF%E9%97%AE%E5%92%8C%E4%BD%BF%E7%94%A8%E6%96%B9%E6%A1%88/</guid>
      <description>&lt;h1 id=&#34;1-背景&#34;&gt;1. 背景&lt;/h1&gt;
&lt;p&gt;当前的后台管理系统主要负责云平台和云服务器的管理，并且是以&lt;code&gt;Web&lt;/code&gt;应用的形式在使用。但是，当出现服务器紧急情况或需要进行平台注册审核时，如果这些任务发生在非工作时间，例如在通勤路上，我们就无法使用&lt;code&gt;PC&lt;/code&gt;浏览器进行访问和操作，这显然是不方便的。另外，由于后台管理系统仅供内部人员使用，我们只需要它能满足基本的查看和配置需求，对于便利性和美观性并没有太高要求。因此，将&lt;code&gt;Web&lt;/code&gt;端的所有功能移植到手机端并开发一个&lt;code&gt;App&lt;/code&gt;，显然很不划算。毕竟，每当&lt;code&gt;Web&lt;/code&gt;端功能迭代时，&lt;code&gt;App&lt;/code&gt;端也需要同步更新，这意味着同一功能需要实现两次，所以，开发&lt;code&gt;App&lt;/code&gt;的方案就不考虑了。&lt;/p&gt;
&lt;h1 id=&#34;2-方案&#34;&gt;2. 方案&lt;/h1&gt;
&lt;h2 id=&#34;21-方案一使用手机edgefirefox浏览器访问使用推荐&#34;&gt;2.1 方案一：使用手机Edge、Firefox浏览器访问使用【推荐】&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;使用手机通过&lt;code&gt;Edge&lt;/code&gt;或&lt;code&gt;Firefox&lt;/code&gt;浏览器访问时，设置为“查看桌面网站”（&lt;code&gt;Firefox&lt;/code&gt;中称为桌面版网站开关），即可浏览平台的完整布局，并通过手势放大和缩小来居中展示所需内容，操作便捷。&lt;/li&gt;
&lt;li&gt;可将后台管理系统的管理平台添加到手机主屏幕，实现快速访问。&lt;/li&gt;
&lt;li&gt;以&lt;code&gt;TDesign&lt;/code&gt;页面模板演示效果。&lt;/li&gt;
&lt;/ol&gt;
&lt;img src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202411010950736.jpg&#34; style=&#34;zoom: 50%;&#34; /&gt;
&lt;h2 id=&#34;22-方案二当前页面--全屏&#34;&gt;2.2 方案二：当前页面 + 全屏&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;创建一个专为手机端使用的手机端菜单，仅显示关注页面，手机端访问时读取该菜单显示。&lt;/li&gt;
&lt;li&gt;利用&lt;code&gt;@media&lt;/code&gt;媒体查询调整各页面布局，例如筛选条件等，以避免布局错乱。&lt;/li&gt;
&lt;li&gt;默认情况下，只能在手机横屏模式下使用，提供一个全屏按钮，点击后将当前页面全屏化，以争取更多展示空间。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202411011005842.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;23-方案三远程软件控制电脑访问使用&#34;&gt;2.3 方案三：远程软件控制电脑访问使用&lt;/h2&gt;
&lt;p&gt;使用远程软件（如向日葵）访问电脑，然后在手机端通过手势放大和缩小进行操作。效果与方案一相似，但存在以下不足：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;输入时需要手动打开键盘。&lt;/li&gt;
&lt;li&gt;页面有滚动条时操作繁琐。&lt;/li&gt;
&lt;li&gt;连接可能不稳定，画质不佳。&lt;/li&gt;
&lt;/ol&gt;
&lt;img src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202411011010811.jpg&#34; style=&#34;zoom:80%;&#34; /&gt;
&lt;h1 id=&#34;3-结论&#34;&gt;3. 结论&lt;/h1&gt;
&lt;ol&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;/ol&gt;</description>
      <content:encoded><![CDATA[<h1 id="1-背景">1. 背景</h1>
<p>当前的后台管理系统主要负责云平台和云服务器的管理，并且是以<code>Web</code>应用的形式在使用。但是，当出现服务器紧急情况或需要进行平台注册审核时，如果这些任务发生在非工作时间，例如在通勤路上，我们就无法使用<code>PC</code>浏览器进行访问和操作，这显然是不方便的。另外，由于后台管理系统仅供内部人员使用，我们只需要它能满足基本的查看和配置需求，对于便利性和美观性并没有太高要求。因此，将<code>Web</code>端的所有功能移植到手机端并开发一个<code>App</code>，显然很不划算。毕竟，每当<code>Web</code>端功能迭代时，<code>App</code>端也需要同步更新，这意味着同一功能需要实现两次，所以，开发<code>App</code>的方案就不考虑了。</p>
<h1 id="2-方案">2. 方案</h1>
<h2 id="21-方案一使用手机edgefirefox浏览器访问使用推荐">2.1 方案一：使用手机Edge、Firefox浏览器访问使用【推荐】</h2>
<ol>
<li>使用手机通过<code>Edge</code>或<code>Firefox</code>浏览器访问时，设置为“查看桌面网站”（<code>Firefox</code>中称为桌面版网站开关），即可浏览平台的完整布局，并通过手势放大和缩小来居中展示所需内容，操作便捷。</li>
<li>可将后台管理系统的管理平台添加到手机主屏幕，实现快速访问。</li>
<li>以<code>TDesign</code>页面模板演示效果。</li>
</ol>
<img src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202411010950736.jpg" style="zoom: 50%;" />
<h2 id="22-方案二当前页面--全屏">2.2 方案二：当前页面 + 全屏</h2>
<ol>
<li>创建一个专为手机端使用的手机端菜单，仅显示关注页面，手机端访问时读取该菜单显示。</li>
<li>利用<code>@media</code>媒体查询调整各页面布局，例如筛选条件等，以避免布局错乱。</li>
<li>默认情况下，只能在手机横屏模式下使用，提供一个全屏按钮，点击后将当前页面全屏化，以争取更多展示空间。</li>
</ol>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202411011005842.png"></p>
<h2 id="23-方案三远程软件控制电脑访问使用">2.3 方案三：远程软件控制电脑访问使用</h2>
<p>使用远程软件（如向日葵）访问电脑，然后在手机端通过手势放大和缩小进行操作。效果与方案一相似，但存在以下不足：</p>
<ol>
<li>输入时需要手动打开键盘。</li>
<li>页面有滚动条时操作繁琐。</li>
<li>连接可能不稳定，画质不佳。</li>
</ol>
<img src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202411011010811.jpg" style="zoom:80%;" />
<h1 id="3-结论">3. 结论</h1>
<ol>
<li>方案一无需额外开发成本，只需在指定手机浏览器上使用即可。</li>
<li>方案二需要额外开发，且最终呈现效果可能不如方案一。</li>
<li>方案三存在上述提到的缺点。</li>
<li>综合考虑，推荐采用方案一。</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>VuePress文档初始化请求过多问题探讨</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/vuepress%E6%96%87%E6%A1%A3%E5%88%9D%E5%A7%8B%E5%8C%96%E8%AF%B7%E6%B1%82%E8%BF%87%E5%A4%9A%E9%97%AE%E9%A2%98%E6%8E%A2%E8%AE%A8/</link>
      <pubDate>Thu, 31 Oct 2024 00:00:00 +0000</pubDate>
      <guid>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/vuepress%E6%96%87%E6%A1%A3%E5%88%9D%E5%A7%8B%E5%8C%96%E8%AF%B7%E6%B1%82%E8%BF%87%E5%A4%9A%E9%97%AE%E9%A2%98%E6%8E%A2%E8%AE%A8/</guid>
      <description>&lt;h1 id=&#34;1-背景&#34;&gt;1. 背景&lt;/h1&gt;
&lt;p&gt;公司有部门使用&lt;code&gt;VuePress 1.0&lt;/code&gt;搭建平台的帮助文档，前期文档不是很多，所以没有暴露出特别明显的问题。但随着文档的逐步迭代和内容的增多，出现了大量的并发请求，总共有218个请求，导致服务器带宽耗尽、响应速度下降，进而影响了文档的使用。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202410301528188.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;2-问题分析&#34;&gt;2. 问题分析&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;VuePress 1.0&lt;/code&gt;是基于&lt;code&gt;Vue 2&lt;/code&gt;和&lt;code&gt;webpack&lt;/code&gt;实现的，其模块化方式使用的是&lt;code&gt;CommonJS&lt;/code&gt;。这意味着，当项目打包部署在服务器并进行访问时，需要将源码全部加载完成后才能进行渲染，即同步加载。随着项目持续迭代，内容增多，性能问题逐渐显现。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202410312319263.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;3-解决方案&#34;&gt;3. 解决方案&lt;/h1&gt;
&lt;p&gt;考虑到向服务器发起了&lt;code&gt;200&lt;/code&gt;多个请求，但查看那些&lt;code&gt;.js&lt;/code&gt;文件，整个&lt;code&gt;js&lt;/code&gt;文件夹大小才&lt;code&gt;10.3MB&lt;/code&gt;，是否可以将&lt;code&gt;10.3MB&lt;/code&gt;分为&lt;code&gt;10&lt;/code&gt;个&lt;code&gt;.js&lt;/code&gt;文件，减少请求至&lt;code&gt;10&lt;/code&gt;次呢？&lt;/p&gt;
&lt;h2 id=&#34;31-方案一替换成showdoc&#34;&gt;3.1 方案一：替换成showDoc&lt;/h2&gt;
&lt;p&gt;使用&lt;code&gt;showDoc&lt;/code&gt;在线文档系统，相比&lt;code&gt;vuepress&lt;/code&gt;基于&lt;code&gt;vue.js&lt;/code&gt;的静态站点生成器，除了操作便利，对于解决并发请求&lt;code&gt;200&lt;/code&gt;次这个问题，还是有帮助的，毕竟&lt;code&gt;showDoc&lt;/code&gt;初始化的时候，是从服务器获取文档目录，再通过文档&lt;code&gt;ID&lt;/code&gt;，去请求文档详情，通常来说，不会有那么多文档目录，不太可能出现并发请求&lt;code&gt;200&lt;/code&gt;次这个问题，只是将&lt;code&gt;vuepress&lt;/code&gt;迁移至&lt;code&gt;showDoc&lt;/code&gt;，花费的成本很高，文档格式需要调整，图片需要上传，想想这个工作量就头大，再者，作为平台的帮助文档，本身带有宣传的作用，很难醒目地在&lt;code&gt;showDoc&lt;/code&gt;中体现平台的公司名和&lt;code&gt;Logo&lt;/code&gt;，所以这个方案不推荐。&lt;/p&gt;
&lt;h2 id=&#34;32-方案二研究webpack如何合并打包&#34;&gt;3.2 方案二：研究webpack如何合并打包&lt;/h2&gt;
&lt;p&gt;如果请求过多是因为文件太分散导致的，那么，能够在当前基础上，也就是&lt;code&gt;webpack&lt;/code&gt;里，找到，当打包时，将各个文件合并，减少请求次数呢？&lt;/p&gt;
&lt;p&gt;&lt;code&gt;VuePress 1.0&lt;/code&gt; 支持通过 &lt;a href=&#34;https://github.com/mozilla-neutrino/webpack-chain&#34;&gt;webpack-chain&lt;/a&gt; 链式操作来修改内部的 &lt;code&gt;webpack&lt;/code&gt; 配置，如下所示：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;exports&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;chainWebpack&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;isServer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// config 是一个 ChainableConfig 的实例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那在 &lt;code&gt;webpack&lt;/code&gt; 中，如何对打包的体积、文件等进行处理呢？在 &lt;code&gt;webpack&lt;/code&gt; 官方文档中，有推荐使用 &lt;code&gt;SplitChunksPlugin&lt;/code&gt; 插件，是为了代码分割，减少包的体积，然后优化加载效率，感觉和自己的初衷背道而驰，最终没达到自己想要的效果。还有就是研究了下 &lt;code&gt;ModuleConcatenationPlugin&lt;/code&gt; 插件，其作用是将所有模块的作用域“提升”或合并到一个闭包中，从而使得代码在浏览器中执行速度更快。但是因为要在使用 &lt;code&gt;webpack-chain&lt;/code&gt; 去调研 &lt;code&gt;webpack&lt;/code&gt; 的配置，尝试使用后也没达到预期，加上再花精力投入到 &lt;code&gt;VuePress 1.0&lt;/code&gt; 和 &lt;code&gt;webpack-chain&lt;/code&gt; 感觉有点不值。所以，就再想想其他方案。&lt;/p&gt;
&lt;h2 id=&#34;33-方案三替换成vitepress推荐&#34;&gt;3.3 方案三：替换成VitePress【推荐】&lt;/h2&gt;
&lt;p&gt;说到减少并发请求次数，实际上，&lt;code&gt;Vite&lt;/code&gt;就在做这样的工作。&lt;code&gt;Vite&lt;/code&gt;采用的JavaScript模块化方式是&lt;code&gt;ESM（ECMAScript Modules）&lt;/code&gt;。与&lt;code&gt;CommonJS&lt;/code&gt;相比，&lt;code&gt;ESM&lt;/code&gt;支持按需加载，并且是异步执行的，不会阻塞浏览器的其他事件处理。这意味着在首次加载时，我们无需加载所有资源，仅需加载首页所需的资源即可。这样就能减少了并发请求次数，解决当前遇到的问题。&lt;/p&gt;
&lt;p&gt;而&lt;code&gt;VitePress&lt;/code&gt;，正是基于&lt;code&gt;Vue 3&lt;/code&gt;和&lt;code&gt;Vite&lt;/code&gt;构建的。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202410312319296.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;5-方案验证&#34;&gt;5. 方案验证&lt;/h1&gt;
&lt;p&gt;以下是两个文档框架的对比，内容基本为空，可忽略不计。可以看到&lt;code&gt;VuePress 1.0&lt;/code&gt;初始化请求的就有&lt;code&gt;26&lt;/code&gt;个请求，大部分都是&lt;code&gt;.js&lt;/code&gt;文件，而&lt;code&gt;VitePress 1.0&lt;/code&gt;只有&lt;code&gt;9&lt;/code&gt;个请求，&lt;code&gt;.js&lt;/code&gt;文件的请求才&lt;code&gt;4&lt;/code&gt;个。&lt;/p&gt;
&lt;h2 id=&#34;51-vuepress-10&#34;&gt;5.1 VuePress 1.0&lt;/h2&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202410312319902.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;52-vitepress-10&#34;&gt;5.2 VitePress 1.0&lt;/h2&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202410312319744.png&#34;&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="1-背景">1. 背景</h1>
<p>公司有部门使用<code>VuePress 1.0</code>搭建平台的帮助文档，前期文档不是很多，所以没有暴露出特别明显的问题。但随着文档的逐步迭代和内容的增多，出现了大量的并发请求，总共有218个请求，导致服务器带宽耗尽、响应速度下降，进而影响了文档的使用。</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202410301528188.png"></p>
<h1 id="2-问题分析">2. 问题分析</h1>
<p><code>VuePress 1.0</code>是基于<code>Vue 2</code>和<code>webpack</code>实现的，其模块化方式使用的是<code>CommonJS</code>。这意味着，当项目打包部署在服务器并进行访问时，需要将源码全部加载完成后才能进行渲染，即同步加载。随着项目持续迭代，内容增多，性能问题逐渐显现。</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202410312319263.png"></p>
<h1 id="3-解决方案">3. 解决方案</h1>
<p>考虑到向服务器发起了<code>200</code>多个请求，但查看那些<code>.js</code>文件，整个<code>js</code>文件夹大小才<code>10.3MB</code>，是否可以将<code>10.3MB</code>分为<code>10</code>个<code>.js</code>文件，减少请求至<code>10</code>次呢？</p>
<h2 id="31-方案一替换成showdoc">3.1 方案一：替换成showDoc</h2>
<p>使用<code>showDoc</code>在线文档系统，相比<code>vuepress</code>基于<code>vue.js</code>的静态站点生成器，除了操作便利，对于解决并发请求<code>200</code>次这个问题，还是有帮助的，毕竟<code>showDoc</code>初始化的时候，是从服务器获取文档目录，再通过文档<code>ID</code>，去请求文档详情，通常来说，不会有那么多文档目录，不太可能出现并发请求<code>200</code>次这个问题，只是将<code>vuepress</code>迁移至<code>showDoc</code>，花费的成本很高，文档格式需要调整，图片需要上传，想想这个工作量就头大，再者，作为平台的帮助文档，本身带有宣传的作用，很难醒目地在<code>showDoc</code>中体现平台的公司名和<code>Logo</code>，所以这个方案不推荐。</p>
<h2 id="32-方案二研究webpack如何合并打包">3.2 方案二：研究webpack如何合并打包</h2>
<p>如果请求过多是因为文件太分散导致的，那么，能够在当前基础上，也就是<code>webpack</code>里，找到，当打包时，将各个文件合并，减少请求次数呢？</p>
<p><code>VuePress 1.0</code> 支持通过 <a href="https://github.com/mozilla-neutrino/webpack-chain">webpack-chain</a> 链式操作来修改内部的 <code>webpack</code> 配置，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">chainWebpack</span> <span class="p">(</span><span class="nx">config</span><span class="p">,</span> <span class="nx">isServer</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// config 是一个 ChainableConfig 的实例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>那在 <code>webpack</code> 中，如何对打包的体积、文件等进行处理呢？在 <code>webpack</code> 官方文档中，有推荐使用 <code>SplitChunksPlugin</code> 插件，是为了代码分割，减少包的体积，然后优化加载效率，感觉和自己的初衷背道而驰，最终没达到自己想要的效果。还有就是研究了下 <code>ModuleConcatenationPlugin</code> 插件，其作用是将所有模块的作用域“提升”或合并到一个闭包中，从而使得代码在浏览器中执行速度更快。但是因为要在使用 <code>webpack-chain</code> 去调研 <code>webpack</code> 的配置，尝试使用后也没达到预期，加上再花精力投入到 <code>VuePress 1.0</code> 和 <code>webpack-chain</code> 感觉有点不值。所以，就再想想其他方案。</p>
<h2 id="33-方案三替换成vitepress推荐">3.3 方案三：替换成VitePress【推荐】</h2>
<p>说到减少并发请求次数，实际上，<code>Vite</code>就在做这样的工作。<code>Vite</code>采用的JavaScript模块化方式是<code>ESM（ECMAScript Modules）</code>。与<code>CommonJS</code>相比，<code>ESM</code>支持按需加载，并且是异步执行的，不会阻塞浏览器的其他事件处理。这意味着在首次加载时，我们无需加载所有资源，仅需加载首页所需的资源即可。这样就能减少了并发请求次数，解决当前遇到的问题。</p>
<p>而<code>VitePress</code>，正是基于<code>Vue 3</code>和<code>Vite</code>构建的。</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202410312319296.png"></p>
<h1 id="5-方案验证">5. 方案验证</h1>
<p>以下是两个文档框架的对比，内容基本为空，可忽略不计。可以看到<code>VuePress 1.0</code>初始化请求的就有<code>26</code>个请求，大部分都是<code>.js</code>文件，而<code>VitePress 1.0</code>只有<code>9</code>个请求，<code>.js</code>文件的请求才<code>4</code>个。</p>
<h2 id="51-vuepress-10">5.1 VuePress 1.0</h2>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202410312319902.png"></p>
<h2 id="52-vitepress-10">5.2 VitePress 1.0</h2>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202410312319744.png"></p>
<h1 id="6-结论">6. 结论</h1>
<p>由于<code>VitePress</code>也是<code>VuePress</code>团队开发的，并且是他们重点推荐的文档框架，从<code>VuePress</code>迁移至<code>VitePress</code>不需要推倒重来，只需调整差异部分，迁移成本相对较低，因此建议迁移至<code>VitePress</code>。</p>
]]></content:encoded>
    </item>
    <item>
      <title>App开发Flutter支持Harmony OS Next方案</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/app%E5%BC%80%E5%8F%91flutter%E6%94%AF%E6%8C%81harmony-os-next%E6%96%B9%E6%A1%88/</link>
      <pubDate>Wed, 30 Oct 2024 00:00:00 +0000</pubDate>
      <guid>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/app%E5%BC%80%E5%8F%91flutter%E6%94%AF%E6%8C%81harmony-os-next%E6%96%B9%E6%A1%88/</guid>
      <description>&lt;h1 id=&#34;1-背景&#34;&gt;1. 背景&lt;/h1&gt;
&lt;p&gt;由于当前部门使用&lt;code&gt;Flutter&lt;/code&gt;框架进行开发，支持生成&lt;code&gt;Android&lt;/code&gt;和&lt;code&gt;iOS&lt;/code&gt;两端的&lt;code&gt;App&lt;/code&gt;应用。现在鸿蒙系统计划完全去掉&lt;code&gt;AOSP&lt;/code&gt;核心代码，将无法支持&lt;code&gt;Android&lt;/code&gt;应用。因此，鸿蒙手机接下来只能安装鸿蒙&lt;code&gt;App&lt;/code&gt;应用。鉴于此，从长远来看，部门&lt;code&gt;App&lt;/code&gt;后续也需要支持鸿蒙系统。那么，如何从成本和可维护性方面考虑后续的开发模式？可以兼顾到&lt;code&gt;Android&lt;/code&gt;、&lt;code&gt;iOS&lt;/code&gt;和鸿蒙系统，同时老项目又能支持在鸿蒙手机上运行？重新开发鸿蒙版本？显然不切实际。&lt;/p&gt;
&lt;h1 id=&#34;2-解决方案&#34;&gt;2. 解决方案&lt;/h1&gt;
&lt;h2 id=&#34;21-方案一flutter-for-openharmony&#34;&gt;2.1 方案一：Flutter for OpenHarmony&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://gitee.com/openharmony-sig/flutter_flutter&#34;&gt;https://gitee.com/openharmony-sig/flutter_flutter&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;鸿蒙官方计划对&lt;code&gt;Flutter&lt;/code&gt;进行反向适配，即基于&lt;code&gt;Flutter SDK&lt;/code&gt;的稳定版本进行拓展，使其能够在鸿蒙&lt;code&gt;DevEco Studio&lt;/code&gt;上构建和生成鸿蒙&lt;code&gt;App&lt;/code&gt;应用。&lt;/p&gt;
&lt;h3 id=&#34;211-优势&#34;&gt;2.1.1 优势&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;官方支持。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Flutter&lt;/code&gt;源码直接可用，只需简单适配，成本低。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;212-劣势&#34;&gt;2.1.2 劣势&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;因使用&lt;code&gt;Flutter&lt;/code&gt;版本为&lt;code&gt;3.7&lt;/code&gt;，与当前最新&lt;code&gt;3.24&lt;/code&gt;版本相差过大，加上&lt;code&gt;Flutter&lt;/code&gt;迭代特别频繁，很多开发方式、组件都在不断变化，后续要使用新的&lt;code&gt;Flutter&lt;/code&gt;特性，可能不会那么容易。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Flutter&lt;/code&gt;正在考虑使用自研的图形渲染引擎&lt;code&gt;Impeller&lt;/code&gt;替换掉&lt;code&gt;Skia&lt;/code&gt;，这无疑又加大了更多的变数。最后，可能会变成多个分支进行维护。&lt;/li&gt;
&lt;li&gt;部门已有项目，使用的&lt;code&gt;Flutter&lt;/code&gt;版本都是最新的，可能是没办法兼容的。除非新项目统一使用这个&lt;code&gt;3.7&lt;/code&gt;版本的&lt;code&gt;Flutter SDK&lt;/code&gt;来开发。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;22-方案二arkui-x-跨平台框架&#34;&gt;2.2 方案二：ArkUI-X 跨平台框架&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://gitee.com/arkui-x&#34;&gt;https://gitee.com/arkui-x&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;ArkUI-X&lt;/code&gt;扩展&lt;code&gt;ArkUI&lt;/code&gt;开发框架到多个&lt;code&gt;OS&lt;/code&gt;平台，让开发者基于一套主代码，就可以构建支持多平台的精美、高性能应用。目前支持&lt;code&gt;OpenHarmony&lt;/code&gt;、&lt;code&gt;HarmonyOS&lt;/code&gt;、&lt;code&gt;Android&lt;/code&gt;、&lt;code&gt;iOS&lt;/code&gt;，后续会逐步增加更多平台支持，可以简单理解为鸿蒙版的&lt;code&gt;Flutter&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id=&#34;221-优势&#34;&gt;2.2.1 优势&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;官方支持。&lt;/li&gt;
&lt;li&gt;鸿蒙版的&lt;code&gt;Flutter&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;222-劣势&#34;&gt;2.2.2 劣势&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;有学习成本，虽然鸿蒙和&lt;code&gt;Flutter&lt;/code&gt;是有一些共性的，学习成本相比之下不会太高，但是毕竟是新的开发模式，各种各样的知识和问题都是需要积累和时间的。&lt;/li&gt;
&lt;li&gt;有开发成本，已有的&lt;code&gt;Flutter&lt;/code&gt;项目需要重新开发。&lt;/li&gt;
&lt;li&gt;生态各方面还处于初期，还未成熟和完善，也不适合立马接入商业项目应用。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;23-方案三flutter-web推荐&#34;&gt;2.3 方案三：Flutter Web【推荐】&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;http://192.168.24.10/appweb/index.html&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;通过&lt;code&gt;Flutter Web&lt;/code&gt;可以部署在网页上，然后在手机浏览器上使用，并设置为全屏，则可以达到和&lt;code&gt;App&lt;/code&gt;一样的使用效果。&lt;/p&gt;
 &lt;img src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202410300919747.png&#34; style=&#34;zoom: 80%;&#34; /&gt;
&lt;h3 id=&#34;231-优势&#34;&gt;2.3.1 优势&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;无开发成本。&lt;/li&gt;
&lt;li&gt;使用时无需安装。&lt;/li&gt;
&lt;li&gt;与系统无关，只要有浏览器就可使用。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;232-劣势&#34;&gt;2.3.2 劣势&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;需要说服使用鸿蒙手机的客户接受这种使用方式。&lt;/li&gt;
&lt;li&gt;各手机浏览器需要支持全屏功能，不过可以代码实现，检测到当前是手机访问，则自动全屏即可。&lt;/li&gt;
&lt;li&gt;考虑到毕竟是在网页上使用，体验可能不如&lt;code&gt;App&lt;/code&gt;，但是现在手机性能、网络访问各方面发展都很不错，这方面应该不会特别明显。&lt;/li&gt;
&lt;li&gt;不联网的项目怎么办？可以基于鸿蒙开发一个基于&lt;code&gt;WebView&lt;/code&gt;的简单手机浏览器，并加载本地&lt;code&gt;Flutter Web&lt;/code&gt;部署的包，打开这个应用就可访问。&lt;/li&gt;
&lt;li&gt;额外多一些适配的工作，但不会很多，&lt;code&gt;Flutter&lt;/code&gt;项目开发，需同时考虑兼容&lt;code&gt;Web&lt;/code&gt;端。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;24-方案四flutter-官方支持-harmonyos&#34;&gt;2.4 方案四：Flutter 官方支持 HarmonyOS&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Flutter&lt;/code&gt;官方暂没有支持&lt;code&gt;HarmonyOS&lt;/code&gt;的计划，但是这个问答 &lt;a href=&#34;https://github.com/flutter/flutter/issues/38437&#34;&gt;《HarmonyOS Support》&lt;/a&gt; 毕竟是几年前了，以后的发展并不好说，如果鸿蒙系统大规模发展起来，发展到可以倒逼&lt;code&gt;Flutter&lt;/code&gt;官方支持也不是没有可能。&lt;/p&gt;
&lt;h1 id=&#34;3-结论&#34;&gt;3. 结论&lt;/h1&gt;
&lt;p&gt;到底选哪个方案，不是绝对的，只能是阶段性的，因为很多方案都还存在变数。考虑到部门的&lt;code&gt;App&lt;/code&gt;项目情况，推荐选择【方案三】，但是方案一、方案二可以在后续进行这方面的调研和准备工作，伺机而动。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="1-背景">1. 背景</h1>
<p>由于当前部门使用<code>Flutter</code>框架进行开发，支持生成<code>Android</code>和<code>iOS</code>两端的<code>App</code>应用。现在鸿蒙系统计划完全去掉<code>AOSP</code>核心代码，将无法支持<code>Android</code>应用。因此，鸿蒙手机接下来只能安装鸿蒙<code>App</code>应用。鉴于此，从长远来看，部门<code>App</code>后续也需要支持鸿蒙系统。那么，如何从成本和可维护性方面考虑后续的开发模式？可以兼顾到<code>Android</code>、<code>iOS</code>和鸿蒙系统，同时老项目又能支持在鸿蒙手机上运行？重新开发鸿蒙版本？显然不切实际。</p>
<h1 id="2-解决方案">2. 解决方案</h1>
<h2 id="21-方案一flutter-for-openharmony">2.1 方案一：Flutter for OpenHarmony</h2>
<blockquote>
<p><a href="https://gitee.com/openharmony-sig/flutter_flutter">https://gitee.com/openharmony-sig/flutter_flutter</a></p></blockquote>
<p>鸿蒙官方计划对<code>Flutter</code>进行反向适配，即基于<code>Flutter SDK</code>的稳定版本进行拓展，使其能够在鸿蒙<code>DevEco Studio</code>上构建和生成鸿蒙<code>App</code>应用。</p>
<h3 id="211-优势">2.1.1 优势</h3>
<ol>
<li>官方支持。</li>
<li><code>Flutter</code>源码直接可用，只需简单适配，成本低。</li>
</ol>
<h3 id="212-劣势">2.1.2 劣势</h3>
<ol>
<li>因使用<code>Flutter</code>版本为<code>3.7</code>，与当前最新<code>3.24</code>版本相差过大，加上<code>Flutter</code>迭代特别频繁，很多开发方式、组件都在不断变化，后续要使用新的<code>Flutter</code>特性，可能不会那么容易。</li>
<li><code>Flutter</code>正在考虑使用自研的图形渲染引擎<code>Impeller</code>替换掉<code>Skia</code>，这无疑又加大了更多的变数。最后，可能会变成多个分支进行维护。</li>
<li>部门已有项目，使用的<code>Flutter</code>版本都是最新的，可能是没办法兼容的。除非新项目统一使用这个<code>3.7</code>版本的<code>Flutter SDK</code>来开发。</li>
</ol>
<h2 id="22-方案二arkui-x-跨平台框架">2.2 方案二：ArkUI-X 跨平台框架</h2>
<blockquote>
<p><a href="https://gitee.com/arkui-x">https://gitee.com/arkui-x</a></p></blockquote>
<p><code>ArkUI-X</code>扩展<code>ArkUI</code>开发框架到多个<code>OS</code>平台，让开发者基于一套主代码，就可以构建支持多平台的精美、高性能应用。目前支持<code>OpenHarmony</code>、<code>HarmonyOS</code>、<code>Android</code>、<code>iOS</code>，后续会逐步增加更多平台支持，可以简单理解为鸿蒙版的<code>Flutter</code>。</p>
<h3 id="221-优势">2.2.1 优势</h3>
<ol>
<li>官方支持。</li>
<li>鸿蒙版的<code>Flutter</code>。</li>
</ol>
<h3 id="222-劣势">2.2.2 劣势</h3>
<ol>
<li>有学习成本，虽然鸿蒙和<code>Flutter</code>是有一些共性的，学习成本相比之下不会太高，但是毕竟是新的开发模式，各种各样的知识和问题都是需要积累和时间的。</li>
<li>有开发成本，已有的<code>Flutter</code>项目需要重新开发。</li>
<li>生态各方面还处于初期，还未成熟和完善，也不适合立马接入商业项目应用。</li>
</ol>
<h2 id="23-方案三flutter-web推荐">2.3 方案三：Flutter Web【推荐】</h2>
<blockquote>
<p>http://192.168.24.10/appweb/index.html</p></blockquote>
<p>通过<code>Flutter Web</code>可以部署在网页上，然后在手机浏览器上使用，并设置为全屏，则可以达到和<code>App</code>一样的使用效果。</p>
 <img src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202410300919747.png" style="zoom: 80%;" />
<h3 id="231-优势">2.3.1 优势</h3>
<ol>
<li>无开发成本。</li>
<li>使用时无需安装。</li>
<li>与系统无关，只要有浏览器就可使用。</li>
</ol>
<h3 id="232-劣势">2.3.2 劣势</h3>
<ol>
<li>需要说服使用鸿蒙手机的客户接受这种使用方式。</li>
<li>各手机浏览器需要支持全屏功能，不过可以代码实现，检测到当前是手机访问，则自动全屏即可。</li>
<li>考虑到毕竟是在网页上使用，体验可能不如<code>App</code>，但是现在手机性能、网络访问各方面发展都很不错，这方面应该不会特别明显。</li>
<li>不联网的项目怎么办？可以基于鸿蒙开发一个基于<code>WebView</code>的简单手机浏览器，并加载本地<code>Flutter Web</code>部署的包，打开这个应用就可访问。</li>
<li>额外多一些适配的工作，但不会很多，<code>Flutter</code>项目开发，需同时考虑兼容<code>Web</code>端。</li>
</ol>
<h2 id="24-方案四flutter-官方支持-harmonyos">2.4 方案四：Flutter 官方支持 HarmonyOS</h2>
<p><code>Flutter</code>官方暂没有支持<code>HarmonyOS</code>的计划，但是这个问答 <a href="https://github.com/flutter/flutter/issues/38437">《HarmonyOS Support》</a> 毕竟是几年前了，以后的发展并不好说，如果鸿蒙系统大规模发展起来，发展到可以倒逼<code>Flutter</code>官方支持也不是没有可能。</p>
<h1 id="3-结论">3. 结论</h1>
<p>到底选哪个方案，不是绝对的，只能是阶段性的，因为很多方案都还存在变数。考虑到部门的<code>App</code>项目情况，推荐选择【方案三】，但是方案一、方案二可以在后续进行这方面的调研和准备工作，伺机而动。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Vue3 &#43; Vite &#43; TypeScript &#43; Bootstrap5 开发指南</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/vue3-&#43;-vite-&#43;-typescript-&#43;-bootstrap5-%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/</link>
      <pubDate>Fri, 09 Jun 2023 00:00:00 +0000</pubDate>
      <guid>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/vue3-&#43;-vite-&#43;-typescript-&#43;-bootstrap5-%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/</guid>
      <description>&lt;h1 id=&#34;2025-年-web-响应式开发解决方案基于-vue3-生态&#34;&gt;2025 年 Web 响应式开发解决方案（基于 Vue3 生态）&lt;/h1&gt;
&lt;p&gt;随着移动设备碎片化加剧和跨端需求增长，2025 年的响应式开发已从单纯的 &amp;ldquo;适配多屏幕&amp;rdquo; 升级为 &amp;ldquo;全场景体验一致性&amp;rdquo;。结合当前技术演进，针对 PC、平板、手机多端适配需求，推荐以下增强方案：&lt;/p&gt;
&lt;h2 id=&#34;一核心技术栈升级&#34;&gt;一、核心技术栈升级&lt;/h2&gt;
&lt;h3 id=&#34;1-基础框架vue-3--vite-6--typescript-5&#34;&gt;1. 基础框架：Vue 3 + Vite 6 + TypeScript 5&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vite 6 优势&lt;/strong&gt;：新增的responsive-plugin可自动识别设备类型并注入环境变量，配合import.meta.env.DEVICE_TYPE在编译时优化条件渲染&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;TypeScript 5&lt;/strong&gt;：借助const type特性强化响应式断点类型定义，避免运行时类型错误&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;// 设备类型类型定义示例
type DeviceType = &amp;#39;mobile&amp;#39; | &amp;#39;tablet&amp;#39; | &amp;#39;desktop&amp;#39; | &amp;#39;large-screen&amp;#39;
const deviceType: DeviceType = import.meta.env.DEVICE_TYPE as DeviceType
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;2-响应式引擎tailwind-css-4--bootstrap-6-混合方案&#34;&gt;2. 响应式引擎：Tailwind CSS 4 + Bootstrap 6 混合方案&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tailwind CSS 4&lt;/strong&gt;：通过@container查询实现组件级响应式，比传统@media更精准控制元素布局&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bootstrap 6&lt;/strong&gt;：新增responsive-propsAPI，支持在组件上直接声明多端样式&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;!-- Bootstrap 6 响应式属性示例 --&amp;gt;
&amp;lt;button 
  class=&amp;#34;btn&amp;#34;
  :responsive=&amp;#34;{
    mobile: &amp;#39;btn-sm w-full&amp;#39;,
    tablet: &amp;#39;btn-md w-1/2&amp;#39;,
    desktop: &amp;#39;btn-lg w-auto&amp;#39;
  }&amp;#34;
&amp;gt;
  多端适配按钮
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;3-跨端状态管理pinia--设备传感器-api&#34;&gt;3. 跨端状态管理：Pinia + 设备传感器 API&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;利用Pinia存储设备状态（如屏幕方向、分辨率），结合ScreenOrientationAPI 实现动态适配&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;// 设备状态Store示例
import { defineStore } from &amp;#39;pinia&amp;#39;

export const useDeviceStore = defineStore(&amp;#39;device&amp;#39;, {
  state: () =&amp;gt; ({
    orientation: ScreenOrientation?.type || &amp;#39;portrait-primary&amp;#39;,
    breakpoint: &amp;#39;mobile&amp;#39;
  }),
  actions: {
    init() {
      window.addEventListener(&amp;#39;orientationchange&amp;#39;, () =&amp;gt; {
        this.orientation = ScreenOrientation.type
      })
    }
  }
})
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;二组件层优化方案&#34;&gt;二、组件层优化方案&lt;/h2&gt;
&lt;h3 id=&#34;1-自适应布局组件库primevue-4--vueuse&#34;&gt;1. 自适应布局组件库：PrimeVue 4 + VueUse&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PrimeVue 4&lt;/strong&gt;：所有组件默认支持responsive属性，内置 30 + 种设备预设&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="2025-年-web-响应式开发解决方案基于-vue3-生态">2025 年 Web 响应式开发解决方案（基于 Vue3 生态）</h1>
<p>随着移动设备碎片化加剧和跨端需求增长，2025 年的响应式开发已从单纯的 &ldquo;适配多屏幕&rdquo; 升级为 &ldquo;全场景体验一致性&rdquo;。结合当前技术演进，针对 PC、平板、手机多端适配需求，推荐以下增强方案：</p>
<h2 id="一核心技术栈升级">一、核心技术栈升级</h2>
<h3 id="1-基础框架vue-3--vite-6--typescript-5">1. 基础框架：Vue 3 + Vite 6 + TypeScript 5</h3>
<ul>
<li>
<p><strong>Vite 6 优势</strong>：新增的responsive-plugin可自动识别设备类型并注入环境变量，配合import.meta.env.DEVICE_TYPE在编译时优化条件渲染</p>
</li>
<li>
<p><strong>TypeScript 5</strong>：借助const type特性强化响应式断点类型定义，避免运行时类型错误</p>
</li>
</ul>
<pre tabindex="0"><code>// 设备类型类型定义示例
type DeviceType = &#39;mobile&#39; | &#39;tablet&#39; | &#39;desktop&#39; | &#39;large-screen&#39;
const deviceType: DeviceType = import.meta.env.DEVICE_TYPE as DeviceType
</code></pre><h3 id="2-响应式引擎tailwind-css-4--bootstrap-6-混合方案">2. 响应式引擎：Tailwind CSS 4 + Bootstrap 6 混合方案</h3>
<ul>
<li>
<p><strong>Tailwind CSS 4</strong>：通过@container查询实现组件级响应式，比传统@media更精准控制元素布局</p>
</li>
<li>
<p><strong>Bootstrap 6</strong>：新增responsive-propsAPI，支持在组件上直接声明多端样式</p>
</li>
</ul>
<pre tabindex="0"><code>&lt;!-- Bootstrap 6 响应式属性示例 --&gt;
&lt;button 
  class=&#34;btn&#34;
  :responsive=&#34;{
    mobile: &#39;btn-sm w-full&#39;,
    tablet: &#39;btn-md w-1/2&#39;,
    desktop: &#39;btn-lg w-auto&#39;
  }&#34;
&gt;
  多端适配按钮
&lt;/button&gt;
</code></pre><h3 id="3-跨端状态管理pinia--设备传感器-api">3. 跨端状态管理：Pinia + 设备传感器 API</h3>
<ul>
<li>利用Pinia存储设备状态（如屏幕方向、分辨率），结合ScreenOrientationAPI 实现动态适配</li>
</ul>
<pre tabindex="0"><code>// 设备状态Store示例
import { defineStore } from &#39;pinia&#39;

export const useDeviceStore = defineStore(&#39;device&#39;, {
  state: () =&gt; ({
    orientation: ScreenOrientation?.type || &#39;portrait-primary&#39;,
    breakpoint: &#39;mobile&#39;
  }),
  actions: {
    init() {
      window.addEventListener(&#39;orientationchange&#39;, () =&gt; {
        this.orientation = ScreenOrientation.type
      })
    }
  }
})
</code></pre><h2 id="二组件层优化方案">二、组件层优化方案</h2>
<h3 id="1-自适应布局组件库primevue-4--vueuse">1. 自适应布局组件库：PrimeVue 4 + VueUse</h3>
<ul>
<li>
<p><strong>PrimeVue 4</strong>：所有组件默认支持responsive属性，内置 30 + 种设备预设</p>
</li>
<li>
<p><strong>VueUse</strong>：使用useMediaQuery组合式 API 实现组件级响应式逻辑</p>
</li>
</ul>
<pre tabindex="0"><code>&lt;script setup&gt;
import { useMediaQuery } from &#39;@vueuse/core&#39;

const isMobile = useMediaQuery(&#39;(max-width: 640px)&#39;)
const isTablet = useMediaQuery(&#39;(min-width: 641px) and (max-width: 1024px)&#39;)
&lt;/script&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;mobile-header v-if=&#34;isMobile&#34; /&gt;
    &lt;tablet-header v-else-if=&#34;isTablet&#34; /&gt;
    &lt;desktop-header v-else /&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre><h3 id="2-响应式数据处理vuequery--设备感知数据请求">2. 响应式数据处理：VueQuery + 设备感知数据请求</h3>
<ul>
<li>根据设备性能动态调整数据粒度，移动端请求精简数据减少流量消耗</li>
</ul>
<pre tabindex="0"><code>// 设备感知数据请求示例
useQuery([&#39;dashboard-data&#39;, deviceType], () =&gt; {
  return fetchDashboardData({
    detailLevel: deviceType === &#39;mobile&#39; ? &#39;basic&#39; : &#39;full&#39;
  })
})
</code></pre><h2 id="三性能优化策略">三、性能优化策略</h2>
<h3 id="1-渲染优化组件级代码分割">1. 渲染优化：组件级代码分割</h3>
<p>借助 Vite 6 的deviceConditionalImport功能，实现设备专属组件的按需加载</p>
<pre tabindex="0"><code>&lt;script setup&gt;
// 按设备类型动态导入组件
const [MobileComponent, TabletComponent, DesktopComponent] = await Promise.all([
  import.meta.env.DEVICE_TYPE === &#39;mobile&#39; ? import(&#39;./MobileComponent.vue&#39;) : null,
  import.meta.env.DEVICE_TYPE === &#39;tablet&#39; ? import(&#39;./TabletComponent.vue&#39;) : null,
  import.meta.env.DEVICE_TYPE === &#39;desktop&#39; ? import(&#39;./DesktopComponent.vue&#39;) : null
])
&lt;/script&gt;
</code></pre><h3 id="2-图像适配nextgen-image--webp-2">2. 图像适配：NextGen Image + WebP 2</h3>
<ul>
<li>
<p>使用<picture>标签配合srcset实现不同设备加载对应分辨率图像</p>
</li>
<li>
<p>采用 WebP 2 格式减少 50% 图像体积，配合loading=&ldquo;lazy&quot;实现按需加载</p>
</li>
</ul>
<pre tabindex="0"><code>&lt;picture&gt;
  &lt;source srcset=&#34;image-200.webp&#34; media=&#34;(max-width: 640px)&#34;&gt;
  &lt;source srcset=&#34;image-400.webp&#34; media=&#34;(max-width: 1024px)&#34;&gt;
  &lt;source srcset=&#34;image-800.webp&#34; media=&#34;(min-width: 1025px)&#34;&gt;
  &lt;img src=&#34;image-400.webp&#34; alt=&#34;响应式图像&#34; loading=&#34;lazy&#34;&gt;
&lt;/picture&gt;
</code></pre><h2 id="四测试与调试方案">四、测试与调试方案</h2>
<h3 id="1-多设备同步测试browserstack-2025--vitest">1. 多设备同步测试：BrowserStack 2025 + Vitest</h3>
<ul>
<li>
<p>利用 BrowserStack 的实时同步功能，在 20 + 设备上同时预览效果</p>
</li>
<li>
<p>使用 Vitest 的device-simulator模拟不同设备环境进行单元测试</p>
</li>
</ul>
<h3 id="2-性能监控lighthouse-mobile--web-vitals">2. 性能监控：Lighthouse Mobile + Web Vitals</h3>
<ul>
<li>
<p>重点监控移动设备的 LCP（最大内容绘制）和 CLS（累积布局偏移）</p>
</li>
<li>
<p>配置 CI/CD 流程，移动端性能得分低于 80 分自动阻断发布</p>
</li>
</ul>
<h2 id="五方案对比与选择建议">五、方案对比与选择建议</h2>
<table>
  <thead>
      <tr>
          <th>方案</th>
          <th>优势场景</th>
          <th>学习成本</th>
          <th>性能表现</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>传统 Bootstrap</td>
          <td>快速原型开发</td>
          <td>低</td>
          <td>中</td>
      </tr>
      <tr>
          <td>Tailwind 纯 CSS</td>
          <td>高度定制化 UI</td>
          <td>中</td>
          <td>高</td>
      </tr>
      <tr>
          <td>混合方案（推荐）</td>
          <td>复杂多端应用</td>
          <td>中高</td>
          <td>高</td>
      </tr>
      <tr>
          <td>组件库驱动</td>
          <td>企业级后台系统</td>
          <td>低</td>
          <td>中高</td>
      </tr>
  </tbody>
</table>
<p><strong>决策建议</strong>：</p>
<ul>
<li>
<p>简单应用：选择 Tailwind CSS 4 + VueUse 组合</p>
</li>
<li>
<p>复杂企业应用：采用混合方案 + PrimeVue 组件库</p>
</li>
<li>
<p>极致性能要求：增加 Vite 设备级代码分割和图像优化策略</p>
</li>
</ul>
<p>通过上述方案，可在 2025 年的技术环境下实现 &ldquo;一次开发，全端适配&rdquo;，同时兼顾性能和开发效率。核心思路是将响应式逻辑从 CSS 层提升到组件层和应用层，结合编译时优化和设备感知能力，构建真正适配未来多端环境的 Web 应用。</p>
<h1 id="前言">前言</h1>
<p>因为之前只是用Vue来开发IaaS平台项目，其使用场景通常都是PC，所以没怎么涉及到Web响应式设计开发相关知识。最近项目刚好是应用在PC和平板，甚至是手机上的，所以就需要考虑响应式的问题。</p>
<h1 id="1-技术选型">1. 技术选型</h1>
<p>Web响应式开发，主要是基于CSS里@media媒体查询实现，允许不同视图尺寸使用不同的布局。</p>
<h2 id="11-方案一vue-3--vite--bootstrap5">1.1 方案一：Vue 3 + Vite + Bootstrap5</h2>
<h3 id="111-优点">1.1.1 优点</h3>
<ol>
<li>
<p>容易上手：只要对 HTML 和 CSS 有基本了解的人都可以很快速的使用 Bootstrap。</p>
</li>
<li>
<p>响应式设计：Bootstrap 可以根据不同平台（手机、平板电脑和台式机）进行调整。</p>
</li>
<li>
<p>移动优先：在 Bootstrap 中，自适应移动端是框架的核心部分。</p>
</li>
<li>
<p>浏览器兼容性：Bootstrap5 兼容所有主流浏览器（Chrome、Firefox、Edge、Safari 和 Opera）。 如果您需要支持 IE11 及以下版本，请使用 Bootstrap4 或 Bootstrap3。</p>
</li>
<li>
<p>github 星数 164k</p>
</li>
<li>
<p>Bootstrap5 效果演示：https://www.bootstrap-admin.top/</p>
</li>
</ol>
<h3 id="112-缺点">1.1.2 缺点</h3>
<ol>
<li>
<p>没办法使用我们积累的vue next组件库</p>
</li>
<li>
<p>Bootstrap5 需要学习成本，但不会很难</p>
</li>
<li>
<p>相对紧急的项目，通常不应该引入新技术去开发实现，而是以快速交付为主。</p>
</li>
</ol>
<h2 id="12-方案二vue-3--vite--element-plus--media">1.2 方案二：Vue 3 + Vite + Element Plus + @media</h2>
<h3 id="121-优点">1.2.1 优点</h3>
<ol>
<li>基于前端现有技术积累，可快速开发项目功能</li>
</ol>
<h3 id="122-缺点">1.2.2 缺点</h3>
<ol>
<li>
<p>前端封装组件库，并没考虑过响应式设计，潜在未知样式问题，如开发此项目，各组件需考虑各平台（电脑、平板、手机）屏幕适配的同时，还要考虑已引用该库开发的项目兼容性问题。</p>
</li>
<li>
<p>@media媒体查询需每个页面、每个平台去适配（Bootstrap5做的事情），工作量相对较大，因无更多平台设备去验证，潜在未知的样式问题。</p>
</li>
</ol>
<h2 id="13-结论">1.3 结论</h2>
<p>简单来说，可以理解为方案一Bootstrap5帮我们处理好了屏幕适配的问题，我们只需要关注功能开发即可，方案二则是功能也要开发，样式也要关注。长远来看，倾向于方案一开发。</p>
<h1 id="2-快速搭建">2. 快速搭建</h1>
<p>Bootstrap5官方文档有提供Vite基于开发的指南<a href="https://getbootstrap.com/docs/5.2/getting-started/vite/">《Bootstrap &amp; Vite》</a>，我们虽然是基于Vue3开发的，但是相关配置基本都一样的，只是有一点点差异而已。</p>
<h2 id="21-下载">2.1 下载</h2>
<p>通过Vite直接生成基于Typescript开发的Vue3模版。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="nx">npm</span> <span class="nx">create</span> <span class="nx">vite</span><span class="kd">@latest</span> <span class="nx">my</span><span class="o">-</span><span class="nx">vue</span><span class="o">-</span><span class="nx">app</span> <span class="o">--</span> <span class="o">--</span><span class="nx">template</span> <span class="nx">vue</span><span class="o">-</span><span class="nx">ts</span>
</span></span></code></pre></div><h2 id="22-安装">2.2 安装</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">npm</span> <span class="nx">install</span>
</span></span><span class="line"><span class="cl"><span class="c1">// bootstrap5、popperjs
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">npm</span> <span class="nx">install</span> <span class="o">--</span><span class="nx">save</span> <span class="nx">bootstrap</span> <span class="kd">@popperjs</span><span class="o">/</span><span class="nx">core</span>
</span></span><span class="line"><span class="cl"><span class="c1">// sass
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">npm</span> <span class="nx">install</span> <span class="o">--</span><span class="nx">save</span><span class="o">-</span><span class="nx">dev</span> <span class="nx">sass</span>
</span></span><span class="line"><span class="cl"><span class="c1">// bootstrap-icons 官方图标库
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">npm</span> <span class="nx">install</span> <span class="nx">bootstrap</span><span class="o">-</span><span class="nx">icons</span>
</span></span></code></pre></div><h2 id="23-配置">2.3 配置</h2>
<h3 id="231-开发热重载">2.3.1 开发热重载</h3>
<p>在<code>vite.config.ts</code>中配置，我们需要让Vite知道在哪里可以找到我们项目的TypeScript，以及开发服务器应该如何表现(热重载从src文件夹中拉取)。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">path</span> <span class="kr">from</span> <span class="s1">&#39;path&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineConfig</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">resolve</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">alias</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">root</span>: <span class="kt">path.resolve</span><span class="p">(</span><span class="nx">__dirname</span><span class="p">,</span> <span class="s1">&#39;src&#39;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">server</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">port</span>: <span class="kt">8080</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">host</span>: <span class="kt">true</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><h3 id="232-bootstrap5">2.3.2 Bootstrap5</h3>
<ol>
<li>
<p>在<code>vite.config.ts</code>中配置，让导入变得尽可能简单：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"> <span class="nx">resolve</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">alias</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;~bootstrap&#39;</span><span class="o">:</span> <span class="nx">path</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="nx">__dirname</span><span class="p">,</span> <span class="s1">&#39;node_modules/bootstrap&#39;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span></code></pre></div></li>
<li>
<p>在<code>src/assets/style</code>文件夹新建一个文件<code>bootstrap5.scss</code> ，引入bootstrap5样式：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="kd">@import</span> <span class="s2">&#34;~bootstrap/scss/bootstrap&#34;</span><span class="p">;</span>
</span></span></code></pre></div></li>
<li>
<p>将<code>main.ts</code>文件修改为<code>main.js</code>，然后在<code>index.html</code>中同步修改：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;module&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;/src/main.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div></li>
<li>
<p>在<code>main.js</code>中引入<code>bootstrap5</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="c1">// 自定义样式
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="s1">&#39;../src/assets/style/bootstrap5.scss&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Bootstrap5 JS
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">bootstrap</span> <span class="kr">from</span> <span class="s1">&#39;bootstrap&#39;</span>
</span></span></code></pre></div></li>
</ol>
<h2 id="23-验证">2.3 验证</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container mt-3&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;my-3 text-start&#34;</span><span class="p">&gt;</span><span class="nx">按钮样式</span><span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;button&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;btn&#34;</span><span class="p">&gt;</span><span class="nx">基本按钮</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;button&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;btn btn-primary ms-2&#34;</span><span class="p">&gt;</span><span class="nx">主要按钮</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;button&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;btn btn-secondary ms-2&#34;</span><span class="p">&gt;</span><span class="nx">次要按钮</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;button&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;btn btn-success ms-2&#34;</span><span class="p">&gt;</span><span class="nx">成功</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;button&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;btn btn-info ms-2&#34;</span><span class="p">&gt;</span><span class="nx">信息</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;button&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;btn btn-warning ms-2&#34;</span><span class="p">&gt;</span><span class="nx">警告</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;button&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;btn btn-danger ms-2&#34;</span><span class="p">&gt;</span><span class="nx">危险</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;button&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;btn btn-dark ms-2&#34;</span><span class="p">&gt;</span><span class="nx">黑色</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;button&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;btn btn-light ms-2&#34;</span><span class="p">&gt;</span><span class="nx">浅色</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;button&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;btn btn-link ms-2&#34;</span><span class="p">&gt;</span><span class="nx">链接</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span></code></pre></div><h2 id="24-效果">2.4 效果</h2>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202306121151455.png"></p>
<h1 id="3-组件">3. 组件</h1>
<h2 id="31-日期选择器">3.1 日期选择器</h2>
<p>一开始打算使用<code>&lt;input type=&quot;datetime-local&quot;&gt;</code>实现的，但是效果不是很理想，一些样式调整起来很复杂，加上本着不重复造轮子的思想，就打算引用相关日期插件实现。</p>
<ol>
<li>安装</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="nx">npm</span> <span class="nx">install</span> <span class="kd">@popperjs</span><span class="o">/</span><span class="nx">core</span> <span class="kd">@eonasdan</span><span class="o">/</span><span class="nx">tempus</span><span class="o">-</span><span class="nx">dominus</span>
</span></span></code></pre></div><ol start="2">
<li>main.js中引入样式</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="c1">// 日期组件样式
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="s1">&#39;@eonasdan/tempus-dominus/dist/css/tempus-dominus.css&#39;</span>
</span></span></code></pre></div><ol start="3">
<li>在.vue中使用时，需引入</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">TempusDominus</span><span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;@eonasdan/tempus-dominus&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span>  <span class="nx">name</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@eonasdan/tempus-dominus/dist/locales/ru&#34;</span><span class="p">;</span>
</span></span></code></pre></div><ol start="4">
<li>实现代码</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;input-group mb-3&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;datetimepicker1&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;form-control&#34;</span> <span class="na">readonly</span> <span class="na">aria-label</span><span class="o">=</span><span class="s">&#34;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;input-group-text&#34;</span><span class="p">&gt;&lt;</span><span class="nt">i</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;bi bi-calendar&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">i</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl"><span class="nx">onMounted</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">element</span>: <span class="kt">any</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">&#39;datetimepicker1&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">datetimepicker1</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">TempusDominus</span><span class="p">(</span><span class="nx">element</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">localization</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">format</span><span class="o">:</span> <span class="s1">&#39;yyyy-MM-dd HH:mm:ss&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nx">hourCycle</span><span class="o">:</span> <span class="s1">&#39;h24&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">display</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">viewMode</span><span class="o">:</span> <span class="s1">&#39;calendar&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nx">components</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nx">year</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">month</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">date</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">clock</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">hours</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">minutes</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">seconds</span>: <span class="kt">true</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="nx">icons</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nx">time</span><span class="o">:</span> <span class="s1">&#39;bi bi-clock&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">date</span><span class="o">:</span> <span class="s1">&#39;bi bi-calendar&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">up</span><span class="o">:</span> <span class="s1">&#39;bi bi-arrow-up&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">down</span><span class="o">:</span> <span class="s1">&#39;bi bi-arrow-down&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">previous</span><span class="o">:</span> <span class="s1">&#39;bi bi-chevron-left&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">next</span><span class="o">:</span> <span class="s1">&#39;bi bi-chevron-right&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">today</span><span class="o">:</span> <span class="s1">&#39;bi bi-calendar-check&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">clear</span><span class="o">:</span> <span class="s1">&#39;bi bi-trash&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">close</span><span class="o">:</span> <span class="s1">&#39;bi bi-x&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="nx">buttons</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nx">today</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">clear</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nx">close</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="nx">datetimepicker1</span><span class="p">.</span><span class="nx">locale</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><ol start="5">
<li>效果如下</li>
</ol>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202306091617823.png"></p>
<h2 id="32-自定义主题色">3.2 自定义主题色</h2>
<p>因为Bootstrap5主题默认是蓝色，和项目设计的主题色不一致，所以就需要修改定制主题色，这一块在<a href="https://bootstrapdoc.com/docs/5.0/customize/sass/">官网Sass模块</a>也有详细说明。特别注意的是，同一Sass文件中的变量覆盖可以在默认变量之前或之后。但是，当跨Sass文件覆盖时，必须在导入Bootstrap的Sass文件之前进行覆盖。比如要将主题色修改为紫色（#6610f2），就需要在我们自定义的样式文件bootstrap5.scss中设置，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scss" data-lang="scss"><span class="line"><span class="cl"><span class="nv">$primary</span><span class="o">:</span> <span class="mh">#6610f2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$danger</span><span class="o">:</span> <span class="mh">#ff4136</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$theme-colors</span><span class="o">:</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;primary&#34;</span><span class="o">:</span> <span class="nv">$primary</span><span class="o">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;danger&#34;</span><span class="o">:</span> <span class="nv">$danger</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// scss
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">@import</span> <span class="s2">&#34;~bootstrap/scss/bootstrap&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Required
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">@import</span> <span class="s2">&#34;../node_modules/bootstrap/scss/functions&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;../node_modules/bootstrap/scss/variables&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">@import</span> <span class="s2">&#34;../node_modules/bootstrap/scss/mixins&#34;</span><span class="p">;</span>
</span></span></code></pre></div><p>效果如下图所示，可以看到按钮设置为<code>primary</code>时，颜色已经变成紫色（#6610f2）了，但是出现了一个问题，那就是次要按钮、成功、信息等按钮样式异常。</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202306121719581.png"></p>
<p>为了解决这个问题，就去查看下<code>_variables.scss</code> 文件，其中有一段样式代码：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scss" data-lang="scss"><span class="line"><span class="cl"><span class="c1">// scss-docs-start theme-color-variables
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$primary</span><span class="o">:</span>       <span class="nv">$blue</span> <span class="k">!default</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$secondary</span><span class="o">:</span>     <span class="nv">$gray-600</span> <span class="k">!default</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$success</span><span class="o">:</span>       <span class="nv">$green</span> <span class="k">!default</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$info</span><span class="o">:</span>          <span class="nv">$cyan</span> <span class="k">!default</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$warning</span><span class="o">:</span>       <span class="nv">$yellow</span> <span class="k">!default</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$danger</span><span class="o">:</span>        <span class="nv">$red</span> <span class="k">!default</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$light</span><span class="o">:</span>         <span class="nv">$gray-100</span> <span class="k">!default</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$dark</span><span class="o">:</span>          <span class="nv">$gray-900</span> <span class="k">!default</span><span class="p">;</span>
</span></span></code></pre></div><p>也就是我们在自定义样式中覆盖了，导致相关字段颜色值丢失，所以就在自定义样式文件中，补上，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scss" data-lang="scss"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 修改主题色
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$primary</span><span class="o">:</span> <span class="mh">#6610f2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$secondary</span><span class="o">:</span> <span class="mh">#6c757d</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$success</span><span class="o">:</span> <span class="mh">#198754</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$info</span><span class="o">:</span> <span class="mh">#0dcaf0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$warning</span><span class="o">:</span> <span class="mh">#ffc107</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$danger</span><span class="o">:</span> <span class="mh">#dc3545</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$light</span><span class="o">:</span> <span class="mh">#f8f9fa</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$dark</span><span class="o">:</span> <span class="mh">#212529</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$theme-colors</span><span class="o">:</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;primary&#34;</span><span class="o">:</span> <span class="nv">$primary</span><span class="o">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;secondary&#34;</span><span class="o">:</span> <span class="nv">$secondary</span><span class="o">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;success&#34;</span><span class="o">:</span> <span class="nv">$success</span><span class="o">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;info&#34;</span><span class="o">:</span> <span class="nv">$info</span><span class="o">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;warning&#34;</span><span class="o">:</span> <span class="nv">$warning</span><span class="o">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;danger&#34;</span><span class="o">:</span> <span class="nv">$danger</span><span class="o">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;light&#34;</span><span class="o">:</span> <span class="nv">$light</span><span class="o">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;dark&#34;</span><span class="o">:</span> <span class="nv">$dark</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span></code></pre></div><p>效果如下所示，虽然解决了按钮的样式问题，但是其他组件其实可能有潜在的问题，这一块后续再补充。</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202306121727168.png"></p>
<h2 id="33-echarts">3.3 Echarts</h2>
<h3 id="331-安装">3.3.1 安装</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="nx">npm</span> <span class="nx">install</span> <span class="nx">echarts</span> <span class="o">--</span><span class="nx">save</span>
</span></span></code></pre></div><h3 id="332-引入-echarts">3.3.2 引入 ECharts</h3>
<p>因为Echarts官网上面其实都有Demo的，但是结合我们实际项目，还是可以把相对贴切的模版给出来的，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;card&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;echarts&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;width: 500px; height: 300px;&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">echarts</span> <span class="kr">from</span> <span class="s1">&#39;echarts&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">onMounted</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;vue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">onMounted</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// 基于准备好的dom，初始化echarts实例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">const</span> <span class="nx">element</span>: <span class="kt">any</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">&#39;echarts&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">myChart</span>: <span class="kt">any</span> <span class="o">=</span> <span class="nx">echarts</span><span class="p">.</span><span class="nx">init</span><span class="p">(</span><span class="nx">element</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">colors</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;#5470C6&#39;</span><span class="p">,</span> <span class="s1">&#39;#91CC75&#39;</span><span class="p">,</span> <span class="s1">&#39;#EE6666&#39;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">color</span>: <span class="kt">colors</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">tooltip</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">trigger</span><span class="o">:</span> <span class="s1">&#39;axis&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">axisPointer</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">type</span><span class="o">:</span> <span class="s1">&#39;cross&#39;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">grid</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">left</span><span class="o">:</span> <span class="s1">&#39;30%&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">legend</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">data</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;电压&#39;</span><span class="p">,</span> <span class="s1">&#39;电流&#39;</span><span class="p">,</span> <span class="s1">&#39;功率&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">xAxis</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">type</span><span class="o">:</span> <span class="s1">&#39;category&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">axisTick</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">alignWithLabel</span>: <span class="kt">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// prettier-ignore
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="nx">data</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;06:00:00&#39;</span><span class="p">,</span> <span class="s1">&#39;07:00:00&#39;</span><span class="p">,</span> <span class="s1">&#39;08:00:00&#39;</span><span class="p">,</span> <span class="s1">&#39;09:00:00&#39;</span><span class="p">,</span> <span class="s1">&#39;10:00:00&#39;</span><span class="p">,</span> <span class="s1">&#39;12:00:00&#39;</span><span class="p">,</span> <span class="s1">&#39;14:10:00&#39;</span><span class="p">,</span> <span class="s1">&#39;15:30:00&#39;</span><span class="p">,</span> <span class="s1">&#39;16:00:00&#39;</span><span class="p">,</span> <span class="s1">&#39;17:00:00&#39;</span><span class="p">,</span> <span class="s1">&#39;18:00:00&#39;</span><span class="p">,</span> <span class="s1">&#39;19:00:00&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">yAxis</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">type</span><span class="o">:</span> <span class="s1">&#39;value&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;电压&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">position</span><span class="o">:</span> <span class="s1">&#39;left&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">alignTicks</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">offset</span>: <span class="kt">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">axisLine</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">show</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">lineStyle</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">color</span>: <span class="kt">colors</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">axisLabel</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">formatter</span><span class="o">:</span> <span class="s1">&#39;{value} V&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">type</span><span class="o">:</span> <span class="s1">&#39;value&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;电流&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">position</span><span class="o">:</span> <span class="s1">&#39;left&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">alignTicks</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">offset</span>: <span class="kt">50</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">axisLine</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">show</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">lineStyle</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">color</span>: <span class="kt">colors</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">axisLabel</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">formatter</span><span class="o">:</span> <span class="s1">&#39;{value} A&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">type</span><span class="o">:</span> <span class="s1">&#39;value&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;功率&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">position</span><span class="o">:</span> <span class="s1">&#39;left&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">alignTicks</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">offset</span>: <span class="kt">100</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">axisLine</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">show</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">lineStyle</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">color</span>: <span class="kt">colors</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">axisLabel</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">formatter</span><span class="o">:</span> <span class="s1">&#39;{value} KW&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">series</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;电压&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="kr">type</span><span class="o">:</span> <span class="s1">&#39;line&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">data</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="mf">2.0</span><span class="p">,</span> <span class="mf">4.9</span><span class="p">,</span> <span class="mf">7.0</span><span class="p">,</span> <span class="mf">23.2</span><span class="p">,</span> <span class="mf">25.6</span><span class="p">,</span> <span class="mf">76.7</span><span class="p">,</span> <span class="mf">135.6</span><span class="p">,</span> <span class="mf">162.2</span><span class="p">,</span> <span class="mf">32.6</span><span class="p">,</span> <span class="mf">20.0</span><span class="p">,</span> <span class="mf">6.4</span><span class="p">,</span> <span class="mf">3.3</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;电流&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="kr">type</span><span class="o">:</span> <span class="s1">&#39;line&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">yAxisIndex</span>: <span class="kt">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">data</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="mf">2.6</span><span class="p">,</span> <span class="mf">5.9</span><span class="p">,</span> <span class="mf">9.0</span><span class="p">,</span> <span class="mf">26.4</span><span class="p">,</span> <span class="mf">28.7</span><span class="p">,</span> <span class="mf">70.7</span><span class="p">,</span> <span class="mf">175.6</span><span class="p">,</span> <span class="mf">182.2</span><span class="p">,</span> <span class="mf">48.7</span><span class="p">,</span> <span class="mf">18.8</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">,</span> <span class="mf">2.3</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;功率&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="kr">type</span><span class="o">:</span> <span class="s1">&#39;line&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">yAxisIndex</span>: <span class="kt">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">data</span><span class="o">:</span> <span class="p">[</span><span class="mf">2.0</span><span class="p">,</span> <span class="mf">2.2</span><span class="p">,</span> <span class="mf">3.3</span><span class="p">,</span> <span class="mf">4.5</span><span class="p">,</span> <span class="mf">6.3</span><span class="p">,</span> <span class="mf">10.2</span><span class="p">,</span> <span class="mf">20.3</span><span class="p">,</span> <span class="mf">23.4</span><span class="p">,</span> <span class="mf">23.0</span><span class="p">,</span> <span class="mf">16.5</span><span class="p">,</span> <span class="mf">12.0</span><span class="p">,</span> <span class="mf">6.2</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// 绘制图表
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">myChart</span><span class="p">.</span><span class="nx">setOption</span><span class="p">(</span><span class="nx">options</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span> <span class="na">scoped</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202306121758405.png"></p>
<h3 id="332-屏幕自适应">3.3.2 屏幕自适应</h3>
<p>因为使用Bootstrap5开发本身就是为了Web响应式功能，所以Echarts也需要处理屏幕自适应的问题，这个ECharts官方文档已经有相关说明了<a href="https://echarts.apache.org/handbook/zh/concepts/chart-size/">《响应容器大小的变化》</a>，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="err">#</span><span class="nx">main</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">html</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">body</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">width</span><span class="o">:</span> <span class="mi">100</span><span class="o">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="err">#</span><span class="nx">main</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">height</span><span class="o">:</span> <span class="mi">400</span><span class="nx">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;main&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text/javascript&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">myChart</span> <span class="o">=</span> <span class="nx">echarts</span><span class="p">.</span><span class="nx">init</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">&#39;main&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;resize&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">myChart</span><span class="p">.</span><span class="nx">resize</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h3 id="333-热更新">3.3.3 热更新</h3>
<p>待解决。</p>
<h1 id="4-打包">4. 打包</h1>
<h2 id="41-本地打开">4.1 本地打开</h2>
<p>因为项目应用场景不太一样，所以有些时候是想要直接打开<code>dist/index.html</code>就可以看到网页内容的，实现这个有现成的插件可以使用<a href="https://github.com/richardtallent/vite-plugin-singlefile">vite-plugin-singlefile</a>，其原理就是将<code>js</code>和<code>css</code>文件内容填充到<code>index.html</code>里，这样就可以通过打开<code>index.html</code>查看打包好的项目了。如下所示：</p>
<ol>
<li>安装</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="nx">npm</span> <span class="nx">install</span> <span class="nx">vite</span><span class="o">-</span><span class="nx">plugin</span><span class="o">-</span><span class="nx">singlefile</span> <span class="o">--</span><span class="nx">save</span><span class="o">-</span><span class="nx">dev</span>
</span></span></code></pre></div><ol start="2">
<li>在vite.config.ts中配置</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">defineConfig</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;vite&#34;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">vue</span> <span class="kr">from</span> <span class="s2">&#34;@vitejs/plugin-vue&#34;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">viteSingleFile</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;vite-plugin-singlefile&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineConfig</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">	<span class="nx">plugins</span><span class="o">:</span> <span class="p">[</span><span class="nx">vue</span><span class="p">(),</span> <span class="nx">viteSingleFile</span><span class="p">()],</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>部门静态导航页的设计与实现</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/%E9%83%A8%E9%97%A8%E9%9D%99%E6%80%81%E5%AF%BC%E8%88%AA%E9%A1%B5%E8%AE%BE%E8%AE%A1/</link>
      <pubDate>Sat, 11 Feb 2023 00:00:00 +0000</pubDate>
      <guid>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/%E9%83%A8%E9%97%A8%E9%9D%99%E6%80%81%E5%AF%BC%E8%88%AA%E9%A1%B5%E8%AE%BE%E8%AE%A1/</guid>
      <description>&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;
&lt;p&gt;每一个公司或者团队有会有相关的项目网址，考虑到团队共用的东西，所以计划是开发一个静态导航页，这样就不需要每个人自己维护了，使用同一套即可，当时在Github上面找了一些开源的静态导航页项目，使用的是开源库&lt;a href=&#34;https://github.com/TopVitamin/static-nav&#34;&gt;static-nav&lt;/a&gt;，它是使用HTML+CSS+JQ简单实现的，代码里面网址都是直接写死的，我只要将其替换就可以。&lt;/p&gt;
&lt;h1 id=&#34;1-遇到问题&#34;&gt;1. 遇到问题&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/TopVitamin/static-nav&#34;&gt;static-nav&lt;/a&gt;虽然可以正常应对当前的需求，但是使用一段时间之后发现，如果我要替换或者新增一些网址，每次都需要在.html文件中修改，然后再重新部署。一两次还好，次数多了，就有点受不了了，再加上一个模块的网址多了之后，好几个模块所占用的空间不一致的话，那布局就容易错乱，为了解决这个问题，我每次都需要使用占位符解决。&lt;/p&gt;
&lt;h1 id=&#34;2-解决方案&#34;&gt;2. 解决方案&lt;/h1&gt;
&lt;p&gt;考虑到维护、后期拓展难的问题，就打算重构这个项目，并命名为&lt;a href=&#34;https://github.com/dstweihao/dst-static-nav&#34;&gt;dst-static-nav&lt;/a&gt;，基于vue next + vite + element-plus 实现，通过一个navLists.ts文件动态配置，后期只需要将这个文件存放在服务器，如有任何需求，只需要改动这个navLists.ts文件即可，不需要改动项目界面，然后又要重新部署一遍，因为最近百度捣鼓了一个开发者搜索，所以也加了一下，项目效果图，如下所示：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/image-20230227220909107.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;功能主要是以下几点，分别是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;左边菜单栏快速定位，右边静态导航页动态渲染&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过 navList.ts 配置，无需改动前端页面&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;支持百度开发者搜索&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当前只是这些功能，后期可能考虑部署线上，然后怎么可以做到通用一点。&lt;/p&gt;
&lt;h1 id=&#34;3-技术要点&#34;&gt;3. 技术要点&lt;/h1&gt;
&lt;p&gt;项目虽然很小，但是有一些细节点还是可以梳理记录一下的，技术没有高低之分，只要能解决了问题就是好技术。&lt;/p&gt;
&lt;h2 id=&#34;31-基于el-scrollbar实现左右联动定位到标题栏&#34;&gt;3.1 基于el-scrollbar实现左右联动定位到标题栏&lt;/h2&gt;
&lt;p&gt;项目开发过程中，主要解决的问题是，左侧菜单栏和右边导航布局页面的联动，需求就是左侧菜单栏选中，右边导航页对应的标题栏滚动到顶部显示，在实现中主要使用document.getElementsByName()这个函数，当&lt;div&gt;&lt;/div&gt;上定义了name属性，就可以通过这个函数获取到它与顶部的距离offsetTop，以此可以将滚动条滚动到指定的位置，如下所示：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-tsx&#34; data-lang=&#34;tsx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;handleSelect&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;key&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;keyPath&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;offsetTop&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getElementsByName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;offsetTop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nx&#34;&gt;scrollbarRef&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setScrollTop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;offsetTop&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;32-实现左侧菜单栏最后几个菜单的标题置顶&#34;&gt;3.2 实现左侧菜单栏最后几个菜单的标题置顶&lt;/h2&gt;
&lt;p&gt;在项目使用过程中，发现左侧菜单栏最后几个菜单，来回切换，导航标题没有置顶，原因很简单，因为布局不够，为了解决这个问题，就需要在最后一个导航模块增加布局，但是应该要增加多少呢？每个导航模块的高度都是不定的，所以要新增的布局高度只能通过计算，动态设置。&lt;/p&gt;
&lt;p&gt;首先，需要知道最后一个导航模块的名称，如下所示：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-tsx&#34; data-lang=&#34;tsx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 获取左侧菜单最后一项，基于它加上需补充的空间高度(浏览器内高度-卡片整个高度)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;lastNavName&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;navLists&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;at&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chindren&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;at&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;label&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后，需要获取当前浏览器页面的高度，减去这个导航模块的高度，就可以知道需要新增多高的布局了，如下所示：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-tsx&#34; data-lang=&#34;tsx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;handleSelect&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;key&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;keyPath&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;offsetTop&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getElementsByName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;offsetTop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;nx&#34;&gt;scrollbarRef&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;setScrollTop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;offsetTop&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;总结&#34;&gt;总结&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/dstweihao/dst-static-nav&#34;&gt;dst-static-nav&lt;/a&gt; 项目还有蛮多东西需要完善的，也是在逐步新增需求，虽然不是什么了不起的项目，但是项目开发整个流程规范是一样的，争取培养起来用心做事情的感觉，从中体验到丝丝成就感。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202508132253218.jpeg&#34;&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="前言">前言</h1>
<p>每一个公司或者团队有会有相关的项目网址，考虑到团队共用的东西，所以计划是开发一个静态导航页，这样就不需要每个人自己维护了，使用同一套即可，当时在Github上面找了一些开源的静态导航页项目，使用的是开源库<a href="https://github.com/TopVitamin/static-nav">static-nav</a>，它是使用HTML+CSS+JQ简单实现的，代码里面网址都是直接写死的，我只要将其替换就可以。</p>
<h1 id="1-遇到问题">1. 遇到问题</h1>
<p><a href="https://github.com/TopVitamin/static-nav">static-nav</a>虽然可以正常应对当前的需求，但是使用一段时间之后发现，如果我要替换或者新增一些网址，每次都需要在.html文件中修改，然后再重新部署。一两次还好，次数多了，就有点受不了了，再加上一个模块的网址多了之后，好几个模块所占用的空间不一致的话，那布局就容易错乱，为了解决这个问题，我每次都需要使用占位符解决。</p>
<h1 id="2-解决方案">2. 解决方案</h1>
<p>考虑到维护、后期拓展难的问题，就打算重构这个项目，并命名为<a href="https://github.com/dstweihao/dst-static-nav">dst-static-nav</a>，基于vue next + vite + element-plus 实现，通过一个navLists.ts文件动态配置，后期只需要将这个文件存放在服务器，如有任何需求，只需要改动这个navLists.ts文件即可，不需要改动项目界面，然后又要重新部署一遍，因为最近百度捣鼓了一个开发者搜索，所以也加了一下，项目效果图，如下所示：</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/image-20230227220909107.png"></p>
<p>功能主要是以下几点，分别是：</p>
<ol>
<li>
<p>左边菜单栏快速定位，右边静态导航页动态渲染</p>
</li>
<li>
<p>通过 navList.ts 配置，无需改动前端页面</p>
</li>
<li>
<p>支持百度开发者搜索</p>
</li>
</ol>
<p>当前只是这些功能，后期可能考虑部署线上，然后怎么可以做到通用一点。</p>
<h1 id="3-技术要点">3. 技术要点</h1>
<p>项目虽然很小，但是有一些细节点还是可以梳理记录一下的，技术没有高低之分，只要能解决了问题就是好技术。</p>
<h2 id="31-基于el-scrollbar实现左右联动定位到标题栏">3.1 基于el-scrollbar实现左右联动定位到标题栏</h2>
<p>项目开发过程中，主要解决的问题是，左侧菜单栏和右边导航布局页面的联动，需求就是左侧菜单栏选中，右边导航页对应的标题栏滚动到顶部显示，在实现中主要使用document.getElementsByName()这个函数，当<div></div>上定义了name属性，就可以通过这个函数获取到它与顶部的距离offsetTop，以此可以将滚动条滚动到指定的位置，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">handleSelect</span> <span class="o">=</span> <span class="p">(</span><span class="nx">key</span>: <span class="kt">string</span><span class="p">,</span> <span class="nx">keyPath</span>: <span class="kt">string</span><span class="p">[])</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="kd">let</span> <span class="nx">offsetTop</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByName</span><span class="p">(</span><span class="nx">key</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="nx">offsetTop</span>
</span></span><span class="line"><span class="cl">		<span class="nx">scrollbarRef</span><span class="p">.</span><span class="nx">value</span><span class="o">!</span><span class="p">.</span><span class="nx">setScrollTop</span><span class="p">(</span><span class="nx">offsetTop</span> <span class="o">-</span> <span class="mi">20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="32-实现左侧菜单栏最后几个菜单的标题置顶">3.2 实现左侧菜单栏最后几个菜单的标题置顶</h2>
<p>在项目使用过程中，发现左侧菜单栏最后几个菜单，来回切换，导航标题没有置顶，原因很简单，因为布局不够，为了解决这个问题，就需要在最后一个导航模块增加布局，但是应该要增加多少呢？每个导航模块的高度都是不定的，所以要新增的布局高度只能通过计算，动态设置。</p>
<p>首先，需要知道最后一个导航模块的名称，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="c1">// 获取左侧菜单最后一项，基于它加上需补充的空间高度(浏览器内高度-卡片整个高度)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">let</span> <span class="nx">lastNavName</span> <span class="o">=</span> <span class="nx">navLists</span><span class="p">.</span><span class="nx">at</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">?</span><span class="p">.</span><span class="nx">chindren</span><span class="p">.</span><span class="nx">at</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">?</span><span class="p">.</span><span class="nx">label</span>
</span></span></code></pre></div><p>然后，需要获取当前浏览器页面的高度，减去这个导航模块的高度，就可以知道需要新增多高的布局了，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">handleSelect</span> <span class="o">=</span> <span class="p">(</span><span class="nx">key</span>: <span class="kt">string</span><span class="p">,</span> <span class="nx">keyPath</span>: <span class="kt">string</span><span class="p">[])</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kd">let</span> <span class="nx">offsetTop</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByName</span><span class="p">(</span><span class="nx">key</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="nx">offsetTop</span>
</span></span><span class="line"><span class="cl">   <span class="nx">scrollbarRef</span><span class="p">.</span><span class="nx">value</span><span class="o">!</span><span class="p">.</span><span class="nx">setScrollTop</span><span class="p">(</span><span class="nx">offsetTop</span> <span class="o">-</span> <span class="mi">20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span></code></pre></div><h1 id="总结">总结</h1>
<p><a href="https://github.com/dstweihao/dst-static-nav">dst-static-nav</a> 项目还有蛮多东西需要完善的，也是在逐步新增需求，虽然不是什么了不起的项目，但是项目开发整个流程规范是一样的，争取培养起来用心做事情的感觉，从中体验到丝丝成就感。</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202508132253218.jpeg"></p>
]]></content:encoded>
    </item>
    <item>
      <title>基于 VuePress 2.x 与 ElementPlus 的组件库文档搭建实践</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/%E5%9F%BA%E4%BA%8E-vuepress-2.x-%E4%B8%8E-elementplus-%E7%9A%84%E7%BB%84%E4%BB%B6%E5%BA%93%E6%96%87%E6%A1%A3%E6%90%AD%E5%BB%BA%E5%AE%9E%E8%B7%B5/</link>
      <pubDate>Wed, 22 Dec 2021 00:00:00 +0000</pubDate>
      <guid>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/%E5%9F%BA%E4%BA%8E-vuepress-2.x-%E4%B8%8E-elementplus-%E7%9A%84%E7%BB%84%E4%BB%B6%E5%BA%93%E6%96%87%E6%A1%A3%E6%90%AD%E5%BB%BA%E5%AE%9E%E8%B7%B5/</guid>
      <description>&lt;h1 id=&#34;1-前言&#34;&gt;1. 前言&lt;/h1&gt;
&lt;p&gt;计划使用 &lt;code&gt;VuePress 2.x&lt;/code&gt; 结合 &lt;code&gt;ElementPlus&lt;/code&gt; 实现一个封装组件库的文档说明网站。本文将详细介绍如何搭建环境、配置项目以及解决过程中遇到的问题。&lt;/p&gt;
&lt;h1 id=&#34;2-vuepress项目初始化&#34;&gt;2. Vuepress项目初始化&lt;/h1&gt;
&lt;h2 id=&#34;21-准备工作&#34;&gt;2.1 准备工作&lt;/h2&gt;
&lt;p&gt;创建一个名为 &lt;code&gt;VuePressTest&lt;/code&gt; 的项目目录，然后进入该目录并安装依赖：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir VuePressTest &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; VuePressTest
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;npm init -y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;npm install -D vuepress@next
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;npm install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;22-配置&#34;&gt;2.2 配置&lt;/h2&gt;
&lt;p&gt;在项目根目录下的 &lt;code&gt;package.json&lt;/code&gt; 文件中添加以下脚本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;scripts&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;dev&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vuepress dev docs&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;build&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vuepress build docs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;23-示例&#34;&gt;2.3 示例&lt;/h2&gt;
&lt;p&gt;在项目根目录下创建 &lt;code&gt;docs/README.md&lt;/code&gt; 文件，并添加以下内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;home: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;heroImage: https://artice-code-1258339218.cos.ap-beijing.myqcloud.com/vuepress/element-index.png
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;heroText: Element
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;features:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; title: 一致性 Consistency
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  details: 与现实生活一致：与现实生活的流程、逻辑保持一致，遵循用户习惯的语言和概念
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; title: 反馈 Feedback
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  details: 通过界面样式和交互动效让用户可以清晰的感知自己的操作
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; title: 效率 Efficiency
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  details: 界面简单直白，让用户快速识别而非回忆，减少用户记忆负担。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;footer: by饿了么
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行 &lt;code&gt;npm run dev&lt;/code&gt; 命令后，效果如下：&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="1-前言">1. 前言</h1>
<p>计划使用 <code>VuePress 2.x</code> 结合 <code>ElementPlus</code> 实现一个封装组件库的文档说明网站。本文将详细介绍如何搭建环境、配置项目以及解决过程中遇到的问题。</p>
<h1 id="2-vuepress项目初始化">2. Vuepress项目初始化</h1>
<h2 id="21-准备工作">2.1 准备工作</h2>
<p>创建一个名为 <code>VuePressTest</code> 的项目目录，然后进入该目录并安装依赖：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir VuePressTest <span class="o">&amp;&amp;</span> <span class="nb">cd</span> VuePressTest
</span></span><span class="line"><span class="cl">npm init -y
</span></span><span class="line"><span class="cl">npm install -D vuepress@next
</span></span><span class="line"><span class="cl">npm install
</span></span></code></pre></div><h2 id="22-配置">2.2 配置</h2>
<p>在项目根目录下的 <code>package.json</code> 文件中添加以下脚本：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;scripts&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;dev&#34;</span><span class="p">:</span> <span class="s2">&#34;vuepress dev docs&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;build&#34;</span><span class="p">:</span> <span class="s2">&#34;vuepress build docs&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="23-示例">2.3 示例</h2>
<p>在项目根目录下创建 <code>docs/README.md</code> 文件，并添加以下内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">home: true
</span></span><span class="line"><span class="cl">heroImage: https://artice-code-1258339218.cos.ap-beijing.myqcloud.com/vuepress/element-index.png
</span></span><span class="line"><span class="cl">heroText: Element
</span></span><span class="line"><span class="cl">features:
</span></span><span class="line"><span class="cl"><span class="k">-</span> title: 一致性 Consistency
</span></span><span class="line"><span class="cl">  details: 与现实生活一致：与现实生活的流程、逻辑保持一致，遵循用户习惯的语言和概念
</span></span><span class="line"><span class="cl"><span class="k">-</span> title: 反馈 Feedback
</span></span><span class="line"><span class="cl">  details: 通过界面样式和交互动效让用户可以清晰的感知自己的操作
</span></span><span class="line"><span class="cl"><span class="k">-</span> title: 效率 Efficiency
</span></span><span class="line"><span class="cl">  details: 界面简单直白，让用户快速识别而非回忆，减少用户记忆负担。
</span></span><span class="line"><span class="cl">footer: by饿了么
</span></span><span class="line"><span class="cl">---
</span></span></code></pre></div><p>运行 <code>npm run dev</code> 命令后，效果如下：</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/image004.png"></p>
<h1 id="3-使用element-plus">3. 使用Element-Plus</h1>
<h2 id="31-安装">3.1 安装</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install element-plus --save
</span></span></code></pre></div><h2 id="32-配置">3.2 配置</h2>
<p>在 <code>.vuepress</code> 目录下创建 <code>clientAppEnhance.ts</code> 文件，引入 ElementPlus：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">defineClientAppEnhance</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;@vuepress/client&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">ElementPlus</span> <span class="kr">from</span> <span class="s1">&#39;element-plus&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="s1">&#39;element-plus/dist/index.css&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineClientAppEnhance</span><span class="p">(({</span> <span class="nx">app</span><span class="p">,</span> <span class="nx">router</span><span class="p">,</span> <span class="nx">siteData</span> <span class="p">})</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">ElementPlus</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><h2 id="33-示例">3.3 示例</h2>
<p>修改 <code>docs/README.md</code> 文件，添加一个 ElementPlus 按钮组件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">home: true
</span></span><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">el-button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;primary&#34;</span> <span class="na">:icon</span><span class="o">=</span><span class="s">&#34;Edit&#34;</span><span class="p">&gt;</span>我是Element-Plus<span class="p">&lt;/</span><span class="nt">el-button</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>运行项目后，效果如下：</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/image005.png"></p>
<h2 id="34-webpack-下的-mjs-文件报错处理">3.4 Webpack 下的 .mjs 文件报错处理</h2>
<p>当前项目使用 Vite 打包工具可以正常启动，但如果使用 Webpack 打包，运行 <code>npm run dev</code> 时可能会出现与 ElementPlus 相关的报错，错误信息如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a &#39;*. mjs&#39; file, or a &#39;*.js&#39; file where the package. json contains &#39;&#34;type&#34;: &#34;module&#34;&#39;). 
</span></span><span class="line"><span class="cl">The extension in the request is mandatory for it to be fully specified. 
</span></span><span class="line"><span class="cl">Add the extension to the request.
</span></span></code></pre></div><p>根据 <a href="https://webpack.docschina.org/api/module-methods/">Webpack 官方文档</a> 的解释，需要将 <code>Rule.resolve.fullySpecified</code> 选项设置为 <code>false</code> 来解决这个问题。在 <code>config.ts</code> 文件中添加以下配置：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">defineUserConfig</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;vuepress&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="kr">type</span> <span class="p">{</span> <span class="nx">DefaultThemeOptions</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;vuepress&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineUserConfig</span><span class="p">&lt;</span><span class="nt">DefaultThemeOptions</span><span class="p">&gt;({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">bundler</span><span class="o">:</span> <span class="s1">&#39;@vuepress/webpack&#39;</span><span class="p">,</span> <span class="c1">// 指定使用 Webpack 打包
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">bundlerConfig</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">chainWebpack</span><span class="o">:</span> <span class="p">(</span><span class="nx">config</span><span class="p">,</span> <span class="nx">isServer</span><span class="p">,</span> <span class="nx">isBuild</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">config</span><span class="p">.</span><span class="nx">module</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">rule</span><span class="p">(</span><span class="s1">&#39;mjs&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="sr">/\.m?jsx?$/</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">resolve</span><span class="p">.</span><span class="kr">set</span><span class="p">(</span><span class="s1">&#39;fullySpecified&#39;</span><span class="p">,</span> <span class="kc">false</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><h2 id="35-elementplus-组件图标显示">3.5 ElementPlus 组件图标显示</h2>
<p>在前面的按钮示例中，设置 <code>:icon=&quot;Edit&quot;</code> 图标并未生效，这是因为 ElementPlus 的图标需要单独引入。</p>
<p>首先安装图标库：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install @element-plus/icons-vue
</span></span></code></pre></div><p>然后修改 <code>.vuepress/clientAppEnhance.ts</code> 文件，注册所有图标组件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">defineClientAppEnhance</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;@vuepress/client&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">ElementPlus</span> <span class="kr">from</span> <span class="s1">&#39;element-plus&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="s1">&#39;element-plus/dist/index.css&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">ElIcons</span> <span class="kr">from</span> <span class="s1">&#39;@element-plus/icons-vue&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineClientAppEnhance</span><span class="p">(({</span> <span class="nx">app</span><span class="p">,</span> <span class="nx">router</span><span class="p">,</span> <span class="nx">siteData</span> <span class="p">})</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">ElementPlus</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="c1">// 全局注册 ElementPlus 图标组件
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nb">Object</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="nx">ElIcons</span><span class="p">).</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">key</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">app</span><span class="p">.</span><span class="nx">component</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">ElIcons</span><span class="p">[</span><span class="nx">key</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><p>修改按钮示例，使用已注册的图标：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">home: true
</span></span><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">el-button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;primary&#34;</span> <span class="na">icon</span><span class="o">=</span><span class="s">&#34;Edit&#34;</span><span class="p">&gt;</span>带图标的按钮<span class="p">&lt;/</span><span class="nt">el-button</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>添加图标后的效果如下：</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/image006.png"></p>
<h1 id="4-markdown-中使用-vue">4. Markdown 中使用 Vue</h1>
<p>如果要对自己封装的组件进行说明，最好能像 ElementPlus 文档那样，既有组件示例，又能查看源码。VuePress 支持在 Markdown 文件中直接使用 Vue 组件。</p>
<h2 id="41-自定义组件">4.1 自定义组件</h2>
<p>在 <code>.vuepress</code> 目录下创建 <code>components</code> 文件夹，然后在其中创建 <code>Test.vue</code> 组件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;test-component&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span><span class="nx">在</span> <span class="nx">Markdown</span> <span class="nx">中引入自定义组件</span><span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">el-button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;success&#34;</span><span class="p">&gt;</span><span class="nx">这是一个</span> <span class="nx">ElementPlus</span> <span class="nx">按钮</span><span class="p">&lt;/</span><span class="nt">el-button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">defineComponent</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;vue&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineComponent</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">setup</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 组件逻辑
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">return</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;less&#34;</span> <span class="na">scoped</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nx">test</span><span class="o">-</span><span class="nx">component</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">padding</span><span class="o">:</span> <span class="mi">20</span><span class="nx">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">border</span><span class="o">:</span> <span class="mi">1</span><span class="nx">px</span> <span class="nx">solid</span> <span class="err">#</span><span class="nx">eaeaea</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">border</span><span class="o">-</span><span class="nx">radius</span><span class="o">:</span> <span class="mi">4</span><span class="nx">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">margin</span><span class="o">:</span> <span class="mi">20</span><span class="nx">px</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><h2 id="42-自动注册-vue-组件">4.2 自动注册 Vue 组件</h2>
<p>安装组件自动注册插件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm i -D @vuepress/plugin-register-components@next
</span></span></code></pre></div><p>在 <code>config.ts</code> 中配置插件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">defineUserConfig</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;vuepress&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="kr">type</span> <span class="p">{</span> <span class="nx">DefaultThemeOptions</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;vuepress&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">path</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;@vuepress/utils&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineUserConfig</span><span class="p">&lt;</span><span class="nt">DefaultThemeOptions</span><span class="p">&gt;({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">plugins</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;@vuepress/register-components&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">componentsDir</span>: <span class="kt">path.resolve</span><span class="p">(</span><span class="nx">__dirname</span><span class="p">,</span> <span class="s1">&#39;./components&#39;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><h2 id="43-基本使用">4.3 基本使用</h2>
<p>在 <code>docs/README.md</code> 文件中引入自定义组件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">home: true
</span></span><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">Test</span> <span class="p">/&gt;</span>
</span></span></code></pre></div><p>引入组件后的效果如下：</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/image007.png"></p>
]]></content:encoded>
    </item>
    <item>
      <title>展厅3D项目实现方案</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/java%E5%AE%89%E5%85%A8%E4%B8%93%E9%A2%98/</link>
      <pubDate>Tue, 28 Feb 2017 00:00:00 +0000</pubDate>
      <guid>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/java%E5%AE%89%E5%85%A8%E4%B8%93%E9%A2%98/</guid>
      <description>&lt;h4 id=&#34;凯撒密码&#34;&gt;凯撒密码&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;凯撒密码作为一种最为古老的**对称加密体制，通过把字母移动一定的位数来实现加密和解密。**明文中的所有字母都在字母表上向后（或向前）按照一个固定数目进行偏移后被替换成密文。例如，当偏移量是3的时候，所有的字母A将被替换成D，B变成E，因此，&lt;strong&gt;位数&lt;/strong&gt;就是凯撒密码加密和解密的密匙。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;凯撒密码的简单demo实现&#34;&gt;凯撒密码的简单demo实现&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Caesar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//需要加密的数据&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enc&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;bravewh&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//需要解密的数据&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dec&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;eudyhzk&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//密匙，即偏移量&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//举例，用来验证统计字符串出各字符出现的字数&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;asdasgasdasdad  adawdawd1112212ad&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//打印&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;加密后：&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;encrypt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;解密后：&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;decrypt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//加密方法&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;encrypt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//得到字符串里的每一个字符&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toCharArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//字符转换成 ASCII 码值&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ascii&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//字符偏移，例如 a-&amp;gt;b&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ascii&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ascii&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//ASCII 码值转换为 char&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;newChar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ascii&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//替换原有字符&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;newChar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//以上 4 行代码可以简写为一行&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//array[i] = (char) (array[i] + key);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//字符数组转换成 String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//解密方法&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;decrypt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//得到字符串里的每一个字符&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toCharArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//字符转换成 ASCII 码值&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ascii&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//恢复字符偏移，例如 b-&amp;gt;a&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ascii&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ascii&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//ASCII 码值转换为 char&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;newChar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ascii&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//替换原有字符&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;newChar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//以上 4 行代码可以简写为一行&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//array[i] = (char) (array[i] - key);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//字符数组转换成 String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;则此时，运行，打印结果为：&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h4 id="凯撒密码">凯撒密码</h4>
<ul>
<li>凯撒密码作为一种最为古老的**对称加密体制，通过把字母移动一定的位数来实现加密和解密。**明文中的所有字母都在字母表上向后（或向前）按照一个固定数目进行偏移后被替换成密文。例如，当偏移量是3的时候，所有的字母A将被替换成D，B变成E，因此，<strong>位数</strong>就是凯撒密码加密和解密的密匙。</li>
</ul>
<h5 id="凯撒密码的简单demo实现">凯撒密码的简单demo实现</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">Caesar</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="n">String</span><span class="o">[]</span><span class="w"> </span><span class="n">args</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">//需要加密的数据</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">String</span><span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&#34;bravewh&#34;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">//需要解密的数据</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">String</span><span class="w"> </span><span class="n">dec</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&#34;eudyhzk&#34;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">//密匙，即偏移量</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="kt">int</span><span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">3</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">//举例，用来验证统计字符串出各字符出现的字数</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">String</span><span class="w"> </span><span class="n">str</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&#34;asdasgasdasdad  adawdawd1112212ad&#34;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">//打印</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">.</span><span class="na">println</span><span class="p">(</span><span class="s">&#34;加密后：&#34;</span><span class="o">+</span><span class="n">encrypt</span><span class="p">(</span><span class="n">enc</span><span class="p">,</span><span class="w"> </span><span class="n">3</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">.</span><span class="na">println</span><span class="p">(</span><span class="s">&#34;解密后：&#34;</span><span class="o">+</span><span class="n">decrypt</span><span class="p">(</span><span class="n">dec</span><span class="p">,</span><span class="w"> </span><span class="n">3</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="w">    </span><span class="c1">//加密方法</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">encrypt</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">enc</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">key</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">//得到字符串里的每一个字符</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="kt">char</span><span class="o">[]</span><span class="w"> </span><span class="n">array</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">enc</span><span class="p">.</span><span class="na">toCharArray</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">array</span><span class="p">.</span><span class="na">length</span><span class="p">;</span><span class="w"> </span><span class="o">++</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c1">//字符转换成 ASCII 码值</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="kt">int</span><span class="w"> </span><span class="n">ascii</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">array</span><span class="o">[</span><span class="n">i</span><span class="o">]</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c1">//字符偏移，例如 a-&gt;b</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">ascii</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ascii</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">key</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c1">//ASCII 码值转换为 char</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="kt">char</span><span class="w"> </span><span class="n">newChar</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="p">)</span><span class="w"> </span><span class="n">ascii</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c1">//替换原有字符</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">array</span><span class="o">[</span><span class="n">i</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">newChar</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c1">//以上 4 行代码可以简写为一行</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c1">//array[i] = (char) (array[i] + key);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">//字符数组转换成 String</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">String</span><span class="p">(</span><span class="n">array</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="w">    </span><span class="c1">//解密方法</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">decrypt</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">input</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">key</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">//得到字符串里的每一个字符</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="kt">char</span><span class="o">[]</span><span class="w"> </span><span class="n">array</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">input</span><span class="p">.</span><span class="na">toCharArray</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">array</span><span class="p">.</span><span class="na">length</span><span class="p">;</span><span class="w"> </span><span class="o">++</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c1">//字符转换成 ASCII 码值</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="kt">int</span><span class="w"> </span><span class="n">ascii</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">array</span><span class="o">[</span><span class="n">i</span><span class="o">]</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c1">//恢复字符偏移，例如 b-&gt;a</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">ascii</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ascii</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">key</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c1">//ASCII 码值转换为 char</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="kt">char</span><span class="w"> </span><span class="n">newChar</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="p">)</span><span class="w"> </span><span class="n">ascii</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c1">//替换原有字符</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">array</span><span class="o">[</span><span class="n">i</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">newChar</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c1">//以上 4 行代码可以简写为一行</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="c1">//array[i] = (char) (array[i] - key);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">//字符数组转换成 String</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">String</span><span class="p">(</span><span class="n">array</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>则此时，运行，打印结果为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">  加密后：eudyhzk
</span></span><span class="line"><span class="cl">  解密后：bravewh
</span></span></code></pre></div><h5 id="频率分析法破解凯撒密码">频率分析法（破解凯撒密码）</h5>
<ul>
<li>凯撒密码加密强度太低，只需要用频度分析法即可破解。</li>
<li>在任何一种书面语言中，不同的字母或字母组合出现的频率各不相同。而且，对于以这种语言书写的任意一段文本，都具有大致相同的特征字母分布。比如，在英语中，字母 E 出现的频率很高，而 X 则出现得较少。</li>
</ul>
<h5 id="破解流程">破解流程</h5>
<ul>
<li>统计密文里出现次数最多的字符，例如出现次数最多的字符是是’h’。</li>
<li>计算字符’h’到’e’的偏移量，值为 3，则表示原文偏移了 3 个位置。</li>
<li>将密文所有字符恢复偏移 3 个位置。</li>
<li><strong>注意点：</strong>
<ul>
<li>统计密文里出现次数最多的字符时，需多统计几个备选，因为最多的可能是空格或者其他字符，例如下图出现次数最多的字符’#’是空格加密后的字符，’h’才是’e’偏移后的值。
<img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202505211631079.webp"></li>
<li><strong>解密时要多几次尝试，因为不一定出现次数最多的字符就是我们想要的目标字符，如下图，第二次解密的结果才是正确的。</strong>
<img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202505211631940.webp"></li>
</ul>
</li>
</ul>
<p>写一个方法，输入一串字符串，获取到出现次数最多的字符，并且知道多少次。用来推算出密匙，即偏移量。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">Caesar</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="n">String</span><span class="o">[]</span><span class="w"> </span><span class="n">args</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">//举例，用来验证统计字符串出各字符出现的字数</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">String</span><span class="w"> </span><span class="n">str</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&#34;asdasgasdasdad  adawdawd1112212ad&#34;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">//输入一串字符串，获取到出现次数最多的字符，并且知道多少次。</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">getCount</span><span class="p">(</span><span class="n">str</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">private</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">getCount</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">str</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">HashMap</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">Integer</span><span class="o">&gt;</span><span class="w"> </span><span class="n">hashMap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">HashMap</span><span class="o">&lt;&gt;</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">str</span><span class="p">.</span><span class="na">length</span><span class="p">();</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">String</span><span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="p">.</span><span class="na">valueOf</span><span class="p">(</span><span class="n">str</span><span class="p">.</span><span class="na">charAt</span><span class="p">(</span><span class="n">i</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">hashMap</span><span class="p">.</span><span class="na">containsKey</span><span class="p">(</span><span class="n">key</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="n">hashMap</span><span class="p">.</span><span class="na">put</span><span class="p">(</span><span class="n">key</span><span class="p">,</span><span class="w"> </span><span class="n">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="kt">int</span><span class="w"> </span><span class="n">val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">hashMap</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">key</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="n">hashMap</span><span class="p">.</span><span class="na">put</span><span class="p">(</span><span class="n">key</span><span class="p">,</span><span class="w"> </span><span class="n">val</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">//将HashMap.entrySet()转换成list</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">ArrayList</span><span class="o">&lt;</span><span class="n">HashMap</span><span class="p">.</span><span class="na">Entry</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">Integer</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">list</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">ArrayList</span><span class="o">&lt;&gt;</span><span class="p">(</span><span class="n">hashMap</span><span class="p">.</span><span class="na">entrySet</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c1">//然后通过比较器来实现排序</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">Collections</span><span class="p">.</span><span class="na">sort</span><span class="p">(</span><span class="n">list</span><span class="p">,</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Comparator</span><span class="o">&lt;</span><span class="n">HashMap</span><span class="p">.</span><span class="na">Entry</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">Integer</span><span class="o">&gt;&gt;</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nd">@Override</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="kd">public</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="nf">compare</span><span class="p">(</span><span class="n">HashMap</span><span class="p">.</span><span class="na">Entry</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">Integer</span><span class="o">&gt;</span><span class="w"> </span><span class="n">e1</span><span class="p">,</span><span class="w"> </span><span class="n">HashMap</span><span class="p">.</span><span class="na">Entry</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">Integer</span><span class="o">&gt;</span><span class="w"> </span><span class="n">e2</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="k">return</span><span class="w"> </span><span class="n">e2</span><span class="p">.</span><span class="na">getValue</span><span class="p">().</span><span class="na">compareTo</span><span class="p">(</span><span class="n">e1</span><span class="p">.</span><span class="na">getValue</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">Map</span><span class="p">.</span><span class="na">Entry</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">Integer</span><span class="o">&gt;</span><span class="w"> </span><span class="n">lis</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">list</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">.</span><span class="na">println</span><span class="p">(</span><span class="s">&#34;字符 &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">lis</span><span class="p">.</span><span class="na">getKey</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s">&#34; 出现了 &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">lis</span><span class="p">.</span><span class="na">getValue</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s">&#34; 次。&#34;</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>则此时，运行，打印结果为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">字符 a 出现了 9 次。
</span></span><span class="line"><span class="cl">字符 d 出现了 8 次。
</span></span><span class="line"><span class="cl">字符 1 出现了 4 次。
</span></span><span class="line"><span class="cl">字符 s 出现了 4 次。
</span></span><span class="line"><span class="cl">字符 2 出现了 3 次。
</span></span><span class="line"><span class="cl">字符   出现了 2 次。
</span></span><span class="line"><span class="cl">字符 w 出现了 2 次。
</span></span><span class="line"><span class="cl">字符 g 出现了 1 次。
</span></span></code></pre></div><h5 id="中场休息总结写博文时获取到的一些小知识">中场休息，总结写博文时获取到的一些小知识</h5>
<ul>
<li>在Android Studio中，要<strong>运行main( ) 方法</strong>，只需要自定义一个类，然后在类里面写好main方法，就可以右键选择Run &lsquo;xxxClass.main() &lsquo;即可。</li>
<li><strong>简书markdown语法</strong>里面强行换行方法就是加上&lt; /br&gt;，只因还不知怎么可以原样显示&lt; /br&gt;，而不是被markdown当成语法解析掉，所以在里面多了空格。而且<strong>首行缩进</strong>的方法是，通过 “ shift + 空格键 ” 将搜狗输入法变成圆角拼音，再按两次空格键即可。还有，水平分割线的语法是 *** 。</li>
</ul>
<blockquote>
<h4 id="对称加密">对称加密</h4>
<h4 id="对称加密-1">对称加密</h4></blockquote>
<ul>
<li>加密和解密都使用同一把秘钥，这种加密方法称为对称加密，也称为单密钥加密。**简单理解就是，加密解密都是同一把钥匙。</li>
</ul>
<h5 id="对称加密常用算法">对称加密常用算法</h5>
<ul>
<li><strong>DES</strong> —— 数据加密标准，是一种使用密钥加密的块算法。</li>
<li><strong>3DES</strong> —— 三重数据加密算法，块密码的通称。它相当于是对每个数据块应用三次 DES 加密算法。</li>
<li><strong>AES</strong> —— 在密码学中又称 Rijndael 加密法，是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的 DES，已经被多方分析且广为全世界所使用。</li>
</ul>
]]></content:encoded>
    </item>
  </channel>
</rss>
