<?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/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/</link>
    <description>Recent content in 技术与架构 on 码上生长 - 探索个人成长的无限可能</description>
    <generator>Hugo -- 0.144.2</generator>
    <language>zh</language>
    <lastBuildDate>Wed, 29 Apr 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://dstweihao.cn/categories/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>AI工具使用心得</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/ai%E4%B8%8E%E6%8E%A2%E7%B4%A2/ai%E5%B7%A5%E5%85%B7%E4%BD%BF%E7%94%A8%E5%BF%83%E5%BE%97/</link>
      <pubDate>Wed, 29 Apr 2026 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/ai%E4%B8%8E%E6%8E%A2%E7%B4%A2/ai%E5%B7%A5%E5%85%B7%E4%BD%BF%E7%94%A8%E5%BF%83%E5%BE%97/</guid>
      <description>&lt;p&gt;如果可以，想办法用上ChatGPT、Google Genmini这些AI工具。不管是工作还是学习，与国内的几个AI大模型相比，差距真的巨大，这不是崇洋媚外，我相信国内大模型会有赶超的那一天，但现在看来，还没到那个时候，没有特别有依据的实验验证，只是从体感来说，至少提前半年甚至一年以上。&lt;/p&gt;
&lt;p&gt;所以，使用相较于国内前沿的工具，无形之中就像是打了信息差，在各方面都会比别人领先一些，可能你和别人是同一个任务，但是，你的效率和产出都会比别人好上很多，而这仅仅是因为工具的不同而已，绝无其他。&lt;/p&gt;
&lt;p&gt;AI的发展是极为迅速的，这个都是显而易见的，从2023年，开始有这种对话式的问答交流，获取想要的资讯，或者说让AI帮忙完成一些文本上的修改任务。&lt;/p&gt;
&lt;p&gt;那时文言一心还没有上线，自己看到一些网站提供了这种功能，然后180元大洋买断了，结果时不时就网页打不开，好像一段时间，就在换域名。现在想起来，当时这种平台，自己好像也没有用来干嘛，无非就是翻译一篇短文、检查下写的文章的错别字等，后来，文言一心上线了，kimi，豆包等都纷纷出现，然后，注意力就转移了，这个买断的平台就没再去打开过了。&lt;/p&gt;
&lt;p&gt;在使用AI的过程中，但印象中，较为深刻的，还是第一次知道和使用 Deepseek ，看到那个思考过程，极为惊艳。在 2025 年年初爆火，后来，只是后来人多了之后，总是因为使用人数太多，服务器资源不足，每次要用一下，经常是没有成功的，这是其一，第二个原因，就是人多了之后，数据被污染得太多了，回答的质量直线下降。然后，转到了豆包AI。&lt;/p&gt;
&lt;p&gt;公司的微信文章，也只是根据公开的平台资料，让它按我提供的模板生成，这部分的工作，之前预估是两天的工作量，我半天就搞定了。在我看来，实在是没有什么必要深究一字一句，只要把表达的东西，传达到位，以及不要显得太过于AI味，就可以了，时间更应该花在高价值上的事情。&lt;/p&gt;
&lt;p&gt;第一次使用超能模式，就知道这个又升级了，这个超能模式，可以抓取平台，只要你提供账号和密码，完全可以帮你做平台系统的测试，当时我第一次使用，都惊呆了。&lt;/p&gt;
&lt;p&gt;后来，我就尝试让它登录公网的平台，让它对每个功能都测试，把暴露的问题，整理成表格给我，我在逐一检查，是否真实有效。&lt;/p&gt;
&lt;p&gt;可以说，豆包是我用过的相对满意的一款AI工具了，至少2025年是这样的。可以说，为我的事情，提供了很大的帮助，但是，这一些，都在2026年爆火之后，戛然而止。&lt;/p&gt;
&lt;p&gt;现在的问题是，使用超能模式，经常被告知当前功能使用爆火，要等几分钟才行。我是没有那么多耐心的，偶尔一两次才行，多了之后，可能要找替代品了。&lt;/p&gt;
&lt;p&gt;恰逢和朋友交流最近基于AI开发的一些事情，说到很多公司都完全是面向AI开发了，大家都称之为“氛围编程”，就是不适应代码交流了，直接就是自然语言，把需求描述清楚，让AI完成项目的代码开发。&lt;/p&gt;
&lt;p&gt;而选择的则是Google提供的IDE工具Google Antigravity，中文名是反重力，完全就是一键生成全部的代码，还自行调试，编译，运行，出现问题，还自行修复，就是到你手上的时候，已经成品了。&lt;/p&gt;
&lt;p&gt;我想起之前使用 dev0 工具，尝试开发一键发文的工具，就是一篇文章，可以同时发布到不同的平台，比如微信公众号、掘金、博客园等，当时，用起来觉得很一般，以为这个方式还不够成熟，接着，也听说豆包提供的TACE插件，都以为，只是能局部支持，而不是整个项目都全部提供，就在这块上面，没有多去关注。&lt;/p&gt;
&lt;p&gt;但是，真正使用起Google Antigravity之后，我心里只觉得，程序员被替代，真的不是痴人说梦。真的，这个时代真的要来了。&lt;/p&gt;
&lt;p&gt;真的，完全可以使用自然语言完成整个项目的代码开发，我是不会Java后端开发的，但是，不影响我把之前在 dev0 工具开发的项目，我直接把项目在Google Antigravity打开，然后，让它根据需求，把这个项目重构，重构后的项目，真的是删除很多错误的代码，错误的功能，错误的编程语言选择，比如之前的前端代码里，有.vue文件的，又有.rect，显得不伦不类的，这次就完全重构，完全基于Vue3框架来开发。&lt;/p&gt;
&lt;p&gt;接着，Java后端的代码也重构，搭配前端项目一起，把项目的架构都梳理清楚了。然后，项目也运行成功了。&lt;/p&gt;
&lt;p&gt;我知道，真的太让我惊叹了。&lt;/p&gt;
&lt;p&gt;如果我要创业，完全可以几个人组成小公司，完全基于这个Google Antigravity来开发项目，至于代码泄漏等问题，小公司完全就是利益至上，先赚到钱再说，管你什么核心技术泄漏，让Google去爬取了。&lt;/p&gt;
&lt;p&gt;这一点大公司完全是不能做的，就是AI这些走的第三方的服务器，他们肯定是先读取到你项目的全部代码，才能给你提供建议，而这个过程，意味着你项目的全部源码，都被第三方公司获取了，这个就是代码泄漏风险，这也是这个氛围编程，无法那么快推进的原因。&lt;/p&gt;
&lt;p&gt;如果你要私有化部署的话，成本是一方面，再者，你成本再高，能比大模型母公司高吗？花的钱越多，意味着功能越强大，如果投入钱搞私有化部署，效果和公网提供的一对比，心里落差极大，这种情况下，真的能坚持使用私有化部署的大模型吗？估计真的忍不了一点。&lt;/p&gt;
&lt;p&gt;当前ini 帮我处理一个因为网络代理，导致在 Mac 电脑上使用VSCode 访问Ubuntu系统的工具，一直失败的问题。&lt;/p&gt;
&lt;p&gt;然后，各种权限都给它了，就一直执行脚本处理，直到解决了为止。类似就是龙虾这个托管电脑。&lt;/p&gt;
&lt;p&gt;可以说，AI工具，用得比较多的是豆包、deekseep、kmini、纳米AI，这些或多或少，都使用过，频次较高，其他的就不提及了。&lt;/p&gt;
&lt;p&gt;只能说AI会发展越来越快，我始终相信，国内的AI工具迟早有一天会超过国外，但是，不是现在，现在来看，还是有很大的差距的，所以，我的看法是，如果可以，真的要赶紧用上Google Genmini和 ChatGPT，真的最少要比国内的AI工具，至少超半年以上。&lt;/p&gt;
&lt;p&gt;很多编程的问题，让豆包和Deekseep排查的时候，明明提供的是同一份信息，但是得出的结果千差万别，Gmini 直接指出了问题出在哪里，一招就命中要害，但是豆包、deekseep提供的方案还是差的太多太多了。&lt;/p&gt;
&lt;p&gt;我的三观真的刷新了，我第一次见到，给出的答案，是如此直接而有效。&lt;/p&gt;
&lt;p&gt;正是在使用 Gmini 的这一段时间，我反复喂给它我的全部信息，让它给我诊断，以及提供发展路径，很多东西说的还是很有道理的。而且，少了很多献媚的措词，至少，让我发现了一个快十年来，一直被我忽视的一个特别主要的一个点，这个点就是所有问题的根源，而我一直以来，都没有注意到。&lt;/p&gt;
&lt;p&gt;打一点这种信息差和时间差，你会比国内没有用这款AI工具的，远超半年甚至一年以上，效果更高，掌握的信息更为准确，何乐而不为。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>如果可以，想办法用上ChatGPT、Google Genmini这些AI工具。不管是工作还是学习，与国内的几个AI大模型相比，差距真的巨大，这不是崇洋媚外，我相信国内大模型会有赶超的那一天，但现在看来，还没到那个时候，没有特别有依据的实验验证，只是从体感来说，至少提前半年甚至一年以上。</p>
<p>所以，使用相较于国内前沿的工具，无形之中就像是打了信息差，在各方面都会比别人领先一些，可能你和别人是同一个任务，但是，你的效率和产出都会比别人好上很多，而这仅仅是因为工具的不同而已，绝无其他。</p>
<p>AI的发展是极为迅速的，这个都是显而易见的，从2023年，开始有这种对话式的问答交流，获取想要的资讯，或者说让AI帮忙完成一些文本上的修改任务。</p>
<p>那时文言一心还没有上线，自己看到一些网站提供了这种功能，然后180元大洋买断了，结果时不时就网页打不开，好像一段时间，就在换域名。现在想起来，当时这种平台，自己好像也没有用来干嘛，无非就是翻译一篇短文、检查下写的文章的错别字等，后来，文言一心上线了，kimi，豆包等都纷纷出现，然后，注意力就转移了，这个买断的平台就没再去打开过了。</p>
<p>在使用AI的过程中，但印象中，较为深刻的，还是第一次知道和使用 Deepseek ，看到那个思考过程，极为惊艳。在 2025 年年初爆火，后来，只是后来人多了之后，总是因为使用人数太多，服务器资源不足，每次要用一下，经常是没有成功的，这是其一，第二个原因，就是人多了之后，数据被污染得太多了，回答的质量直线下降。然后，转到了豆包AI。</p>
<p>公司的微信文章，也只是根据公开的平台资料，让它按我提供的模板生成，这部分的工作，之前预估是两天的工作量，我半天就搞定了。在我看来，实在是没有什么必要深究一字一句，只要把表达的东西，传达到位，以及不要显得太过于AI味，就可以了，时间更应该花在高价值上的事情。</p>
<p>第一次使用超能模式，就知道这个又升级了，这个超能模式，可以抓取平台，只要你提供账号和密码，完全可以帮你做平台系统的测试，当时我第一次使用，都惊呆了。</p>
<p>后来，我就尝试让它登录公网的平台，让它对每个功能都测试，把暴露的问题，整理成表格给我，我在逐一检查，是否真实有效。</p>
<p>可以说，豆包是我用过的相对满意的一款AI工具了，至少2025年是这样的。可以说，为我的事情，提供了很大的帮助，但是，这一些，都在2026年爆火之后，戛然而止。</p>
<p>现在的问题是，使用超能模式，经常被告知当前功能使用爆火，要等几分钟才行。我是没有那么多耐心的，偶尔一两次才行，多了之后，可能要找替代品了。</p>
<p>恰逢和朋友交流最近基于AI开发的一些事情，说到很多公司都完全是面向AI开发了，大家都称之为“氛围编程”，就是不适应代码交流了，直接就是自然语言，把需求描述清楚，让AI完成项目的代码开发。</p>
<p>而选择的则是Google提供的IDE工具Google Antigravity，中文名是反重力，完全就是一键生成全部的代码，还自行调试，编译，运行，出现问题，还自行修复，就是到你手上的时候，已经成品了。</p>
<p>我想起之前使用 dev0 工具，尝试开发一键发文的工具，就是一篇文章，可以同时发布到不同的平台，比如微信公众号、掘金、博客园等，当时，用起来觉得很一般，以为这个方式还不够成熟，接着，也听说豆包提供的TACE插件，都以为，只是能局部支持，而不是整个项目都全部提供，就在这块上面，没有多去关注。</p>
<p>但是，真正使用起Google Antigravity之后，我心里只觉得，程序员被替代，真的不是痴人说梦。真的，这个时代真的要来了。</p>
<p>真的，完全可以使用自然语言完成整个项目的代码开发，我是不会Java后端开发的，但是，不影响我把之前在 dev0 工具开发的项目，我直接把项目在Google Antigravity打开，然后，让它根据需求，把这个项目重构，重构后的项目，真的是删除很多错误的代码，错误的功能，错误的编程语言选择，比如之前的前端代码里，有.vue文件的，又有.rect，显得不伦不类的，这次就完全重构，完全基于Vue3框架来开发。</p>
<p>接着，Java后端的代码也重构，搭配前端项目一起，把项目的架构都梳理清楚了。然后，项目也运行成功了。</p>
<p>我知道，真的太让我惊叹了。</p>
<p>如果我要创业，完全可以几个人组成小公司，完全基于这个Google Antigravity来开发项目，至于代码泄漏等问题，小公司完全就是利益至上，先赚到钱再说，管你什么核心技术泄漏，让Google去爬取了。</p>
<p>这一点大公司完全是不能做的，就是AI这些走的第三方的服务器，他们肯定是先读取到你项目的全部代码，才能给你提供建议，而这个过程，意味着你项目的全部源码，都被第三方公司获取了，这个就是代码泄漏风险，这也是这个氛围编程，无法那么快推进的原因。</p>
<p>如果你要私有化部署的话，成本是一方面，再者，你成本再高，能比大模型母公司高吗？花的钱越多，意味着功能越强大，如果投入钱搞私有化部署，效果和公网提供的一对比，心里落差极大，这种情况下，真的能坚持使用私有化部署的大模型吗？估计真的忍不了一点。</p>
<p>当前ini 帮我处理一个因为网络代理，导致在 Mac 电脑上使用VSCode 访问Ubuntu系统的工具，一直失败的问题。</p>
<p>然后，各种权限都给它了，就一直执行脚本处理，直到解决了为止。类似就是龙虾这个托管电脑。</p>
<p>可以说，AI工具，用得比较多的是豆包、deekseep、kmini、纳米AI，这些或多或少，都使用过，频次较高，其他的就不提及了。</p>
<p>只能说AI会发展越来越快，我始终相信，国内的AI工具迟早有一天会超过国外，但是，不是现在，现在来看，还是有很大的差距的，所以，我的看法是，如果可以，真的要赶紧用上Google Genmini和 ChatGPT，真的最少要比国内的AI工具，至少超半年以上。</p>
<p>很多编程的问题，让豆包和Deekseep排查的时候，明明提供的是同一份信息，但是得出的结果千差万别，Gmini 直接指出了问题出在哪里，一招就命中要害，但是豆包、deekseep提供的方案还是差的太多太多了。</p>
<p>我的三观真的刷新了，我第一次见到，给出的答案，是如此直接而有效。</p>
<p>正是在使用 Gmini 的这一段时间，我反复喂给它我的全部信息，让它给我诊断，以及提供发展路径，很多东西说的还是很有道理的。而且，少了很多献媚的措词，至少，让我发现了一个快十年来，一直被我忽视的一个特别主要的一个点，这个点就是所有问题的根源，而我一直以来，都没有注意到。</p>
<p>打一点这种信息差和时间差，你会比国内没有用这款AI工具的，远超半年甚至一年以上，效果更高，掌握的信息更为准确，何乐而不为。</p>
]]></content:encoded>
    </item>
    <item>
      <title>VirtualBox 虚拟机里的 Ubuntu系统怎么扩容？</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/c&#43;&#43;%E4%B8%8E%E5%B5%8C%E5%85%A5%E5%BC%8F/oracle-vm-virtualbox-%E8%99%9A%E6%8B%9F%E6%9C%BA%E9%87%8C%E7%9A%84-ubuntu-%E6%80%8E%E4%B9%88%E6%89%A9%E5%AE%B9/</link>
      <pubDate>Tue, 28 Apr 2026 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/c&#43;&#43;%E4%B8%8E%E5%B5%8C%E5%85%A5%E5%BC%8F/oracle-vm-virtualbox-%E8%99%9A%E6%8B%9F%E6%9C%BA%E9%87%8C%E7%9A%84-ubuntu-%E6%80%8E%E4%B9%88%E6%89%A9%E5%AE%B9/</guid>
      <description>&lt;h2 id=&#34;1-前言&#34;&gt;1. 前言&lt;/h2&gt;
&lt;p&gt;基于 Oracle VM VirtualBox 虚拟机安装的 Ubuntu 系统，主要用于 C++ 嵌入式项目开发，最开始只是分配了 40G 硬盘内存。现在项目分支过多，加上项目一些插件、依赖库，导致现在系统硬盘内存不够了，经常提示只剩 1G 内存。想到一直这样下去也不是办法，只能先看下怎么清理大文件，然后，再怎么给 Ubuntu 系统扩容。&lt;/p&gt;
&lt;h2 id=&#34;2-使用-baobab-工具检索大文件&#34;&gt;2. 使用 baobab 工具检索大文件&lt;/h2&gt;
&lt;p&gt;在 Ubuntu 系统终端，使用以下命令安装 Baobab 工具并打开：&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-sh&#34; data-lang=&#34;sh&#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;sudo apt install baobab -y
&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;baobab
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Baobab 会扫描分区，然后通过颜色，来区分哪些文件是占内存最大的，并且排在最前，这个时候，你就可以看下一些比如&lt;code&gt;.cache&lt;/code&gt;、&lt;code&gt;.vscode&lt;/code&gt;、&lt;code&gt;.lingma&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/202604281851862.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;但这只是用来优化一下内存而已，真正起到作用，还是要 VirtualBox 虚拟机扩容。&lt;/p&gt;
&lt;h2 id=&#34;3-在-virtualbox-虚拟机扩容至-80g&#34;&gt;3. 在 VirtualBox 虚拟机扩容至 80G&lt;/h2&gt;
&lt;p&gt;考虑到办公电脑一般硬盘都很大的，所以，多分配一些内存问题不大，关闭虚拟机之后，在 &lt;code&gt;管理 - 工具 - 虚拟介质管理 - 属性&lt;/code&gt;，然后把下面的滑块，滑到 80G 的大小位置。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202604281853674.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;4-在-ubuntu-系统安装-gparted-图形化分区工具&#34;&gt;4. 在 Ubuntu 系统安装 gparted 图形化分区工具&lt;/h2&gt;
&lt;p&gt;在虚拟机上扩容到 80G 后，到 Ubuntu 系统里，你就会发现，还是会提示剩余空间不足的问题，原因是虽然扩容了，但是这个空间没有真正使用起来，就需要安装 gparted 分区工具来处理：&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="1-前言">1. 前言</h2>
<p>基于 Oracle VM VirtualBox 虚拟机安装的 Ubuntu 系统，主要用于 C++ 嵌入式项目开发，最开始只是分配了 40G 硬盘内存。现在项目分支过多，加上项目一些插件、依赖库，导致现在系统硬盘内存不够了，经常提示只剩 1G 内存。想到一直这样下去也不是办法，只能先看下怎么清理大文件，然后，再怎么给 Ubuntu 系统扩容。</p>
<h2 id="2-使用-baobab-工具检索大文件">2. 使用 baobab 工具检索大文件</h2>
<p>在 Ubuntu 系统终端，使用以下命令安装 Baobab 工具并打开：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">// 安装
</span></span><span class="line"><span class="cl">sudo apt install baobab -y
</span></span><span class="line"><span class="cl">// 启动
</span></span><span class="line"><span class="cl">baobab
</span></span></code></pre></div><p>Baobab 会扫描分区，然后通过颜色，来区分哪些文件是占内存最大的，并且排在最前，这个时候，你就可以看下一些比如<code>.cache</code>、<code>.vscode</code>、<code>.lingma</code>等占空间很大的文件，就可以考虑清空了。</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202604281851862.png"></p>
<p>但这只是用来优化一下内存而已，真正起到作用，还是要 VirtualBox 虚拟机扩容。</p>
<h2 id="3-在-virtualbox-虚拟机扩容至-80g">3. 在 VirtualBox 虚拟机扩容至 80G</h2>
<p>考虑到办公电脑一般硬盘都很大的，所以，多分配一些内存问题不大，关闭虚拟机之后，在 <code>管理 - 工具 - 虚拟介质管理 - 属性</code>，然后把下面的滑块，滑到 80G 的大小位置。</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202604281853674.png"></p>
<h2 id="4-在-ubuntu-系统安装-gparted-图形化分区工具">4. 在 Ubuntu 系统安装 gparted 图形化分区工具</h2>
<p>在虚拟机上扩容到 80G 后，到 Ubuntu 系统里，你就会发现，还是会提示剩余空间不足的问题，原因是虽然扩容了，但是这个空间没有真正使用起来，就需要安装 gparted 分区工具来处理：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">sudo apt update
</span></span><span class="line"><span class="cl">sudo apt install gparted
</span></span></code></pre></div><p>然后，在应用列表找到 gparted 工具，打开，就能看到 <code>/dev/sda2</code> 有 40G，然后 <code>/dev/sda5</code> 有 40G，这个类似一个父文件和子文件的结构，意思就是 sda2 是包裹着 sda5 的，要增大 sda5 的内存，就先增大 sda2 的内存，选中 <code>/dev/sda2</code>，然后右键，选择 “调整大小 / 移动”，然后把滑块拖动到 80G，接着也把 sda5 拖到 80G，然后点一下操作栏上的 “√”，这样内存扩容就生效了。</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202604281849593.png"></p>
<p>这个时候，你可以再看下，主目录下就会显示，还剩余 50G 的内存空间，一部分是清理了缓存，另一部分就是我们刚新增的 40G 空间。</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202604281852353.png"></p>
]]></content:encoded>
    </item>
    <item>
      <title>AI真的可以取代程序员吗？</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/ai%E4%B8%8E%E6%8E%A2%E7%B4%A2/ai%E7%9C%9F%E7%9A%84%E5%8F%AF%E4%BB%A5%E5%8F%96%E4%BB%A3%E7%A8%8B%E5%BA%8F%E5%91%98%E5%90%97/</link>
      <pubDate>Wed, 16 Jul 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/ai%E4%B8%8E%E6%8E%A2%E7%B4%A2/ai%E7%9C%9F%E7%9A%84%E5%8F%AF%E4%BB%A5%E5%8F%96%E4%BB%A3%E7%A8%8B%E5%BA%8F%E5%91%98%E5%90%97/</guid>
      <description>&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202507161950721.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;说到 AI 是否会取代程序员，我的答案是会，但又不完全会。&lt;/p&gt;
&lt;p&gt;在我看来，所谓的取代，其实是要求程序员提升自身能力，向更高层次发展，将比如某个通用函数的封装、代码漏洞检查这类已熟练掌握的工作交给 AI，自己则转变为发布和验收的角色，也就是按照自己的想法下达任务，然后验收任务，形成一个闭环。&lt;/p&gt;
&lt;p&gt;AI 在实际应用中确实面临一些问题，以下是我想到的几点：&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;怎样确保 AI 能完全依照你的想法，实现你想要的效果？&lt;/li&gt;
&lt;li&gt;如何判断 AI 生成的内容是否正确？&lt;/li&gt;
&lt;li&gt;何时该使用 AI，何时不该用？&lt;/li&gt;
&lt;/ol&gt;&lt;/blockquote&gt;
&lt;p&gt;就第一个问题而言，未来很可能会演变成面向 AI 编程。你看，现在都已经有 “Prompt 工程师” 这个职位了，他们的职责就是做好与 AI 的沟通工作，思考如何用精准的描述告诉 AI 该做什么。&lt;/p&gt;
&lt;p&gt;回顾人与计算器的交互历史，从最初使用 0 和 1 二进制进行沟通，到后来发展出 C/C++/Java 等高级语言，这些都是对 0 和 1 的上层封装。如今与 AI 交互也是同理，只不过现在我们是用现实中的自然语言与它交流。&lt;/p&gt;
&lt;p&gt;至于第二个问题，关键在于你自己得懂，也就是说不可能完全依赖 AI 而不学习新知识。不然，你怎么判断 AI 生成的内容是否正确呢？&lt;/p&gt;
&lt;p&gt;对于第三个问题，何时使用 AI 就需要进行评估判断了。有些事情看似用 AI 能很快完成，但实际使用时，因输入指令不够具体准确，产出结果可能天差地别，常需多次调整才能满意，自己动手做或许更快，还免得在与 AI 的磨合中浪费时间、徒增郁闷。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202507161950372.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;除此之外，很多人都提到，既然 AI 能生成一整个项目的代码，那还要程序员干什么呢？&lt;/p&gt;
&lt;p&gt;其实，AI 生成的只是项目第一版需求的代码，可项目又不是一锤子买卖，后续还需要不断迭代和更新。这时候该怎么办？全都交给 AI 处理吗？&lt;/p&gt;
&lt;p&gt;理论上似乎是可行的，但就我使用 dev0、豆包和阿里云 AI 等工具开发网页的体验来看，效率实在不高。每次修改一点点内容，AI 都要重新生成全部代码，这个过程极其漫长，项目越大，等待的时间就越久。而且，如果输入的指令不够详细具体，得到的结果相差甚远，还得不断调整到满意为止。有这时间，我自己早就把代码改好了。所以在这种情况下，除非你的 prompt 能力特别强，否则真的是对 AI 又爱又恨。不过话说回来，人与人之间沟通都可能出现信息失真，更何况是与机器沟通呢？面对全是 AI 生成的代码，你真的有足够的信心直接部署到生产环境吗？&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202507161950721.png"></p>
<p>说到 AI 是否会取代程序员，我的答案是会，但又不完全会。</p>
<p>在我看来，所谓的取代，其实是要求程序员提升自身能力，向更高层次发展，将比如某个通用函数的封装、代码漏洞检查这类已熟练掌握的工作交给 AI，自己则转变为发布和验收的角色，也就是按照自己的想法下达任务，然后验收任务，形成一个闭环。</p>
<p>AI 在实际应用中确实面临一些问题，以下是我想到的几点：</p>
<blockquote>
<ol>
<li>怎样确保 AI 能完全依照你的想法，实现你想要的效果？</li>
<li>如何判断 AI 生成的内容是否正确？</li>
<li>何时该使用 AI，何时不该用？</li>
</ol></blockquote>
<p>就第一个问题而言，未来很可能会演变成面向 AI 编程。你看，现在都已经有 “Prompt 工程师” 这个职位了，他们的职责就是做好与 AI 的沟通工作，思考如何用精准的描述告诉 AI 该做什么。</p>
<p>回顾人与计算器的交互历史，从最初使用 0 和 1 二进制进行沟通，到后来发展出 C/C++/Java 等高级语言，这些都是对 0 和 1 的上层封装。如今与 AI 交互也是同理，只不过现在我们是用现实中的自然语言与它交流。</p>
<p>至于第二个问题，关键在于你自己得懂，也就是说不可能完全依赖 AI 而不学习新知识。不然，你怎么判断 AI 生成的内容是否正确呢？</p>
<p>对于第三个问题，何时使用 AI 就需要进行评估判断了。有些事情看似用 AI 能很快完成，但实际使用时，因输入指令不够具体准确，产出结果可能天差地别，常需多次调整才能满意，自己动手做或许更快，还免得在与 AI 的磨合中浪费时间、徒增郁闷。</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202507161950372.png"></p>
<p>除此之外，很多人都提到，既然 AI 能生成一整个项目的代码，那还要程序员干什么呢？</p>
<p>其实，AI 生成的只是项目第一版需求的代码，可项目又不是一锤子买卖，后续还需要不断迭代和更新。这时候该怎么办？全都交给 AI 处理吗？</p>
<p>理论上似乎是可行的，但就我使用 dev0、豆包和阿里云 AI 等工具开发网页的体验来看，效率实在不高。每次修改一点点内容，AI 都要重新生成全部代码，这个过程极其漫长，项目越大，等待的时间就越久。而且，如果输入的指令不够详细具体，得到的结果相差甚远，还得不断调整到满意为止。有这时间，我自己早就把代码改好了。所以在这种情况下，除非你的 prompt 能力特别强，否则真的是对 AI 又爱又恨。不过话说回来，人与人之间沟通都可能出现信息失真，更何况是与机器沟通呢？面对全是 AI 生成的代码，你真的有足够的信心直接部署到生产环境吗？</p>
<p>要是让 AI 生成第一版需求代码，后续的迭代和维护交给程序员呢？</p>
<p>这同样存在问题，因为 AI 生成的代码大概率不符合团队的代码规范，程序员得花时间去熟悉。而且团队可能已经有封装好的组件库，AI 生成的代码却无法复用这些组件，而是自行实现相同功能，这在迭代和维护时反而重复造轮子了。只是一个项目还好，要是所有项目都是如此，那组件库就形同虚设了。就像 A、B、C 三个由 AI 生成的项目，在迭代过程中又得抽取复用的组件和工具类，绕了一圈又回到组件库这里，仿佛回到了原点。</p>
<p>所以现阶段，无论是想完全依靠 AI 生成项目代码并直接发布到生产环境，还是仅让 AI 生成第一版代码，后续由程序员接手迭代和维护，都不太现实。</p>
<p>不过，现阶段 AI 在演示项目、UI 原型设计方面的表现还是不错的。比如我要实现一个大屏，把需求整理好后让 AI 生成效果图，虽仍需调整，但可作为参考，提高了工作效率。</p>
<blockquote>
<p>智慧工厂大屏需求：</p>
<ol>
<li>实时数据可视化：设备状态、产能、良率、能耗等核心指标实时展示，10 秒刷新</li>
<li>异常预警：设备故障、指标超标等异常即时报警</li>
<li>灵活查看：支持按车间 / 产线切换视图，适配大屏显示</li>
</ol></blockquote>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202507162001847.png"></p>
<p>而且，AI 还降低了学习某种技术的门槛。以前学习知识点遇到问题，在网上搜了又搜，到处请教，都不一定能得到有效的解释。现在不同了，虽说不能保证 AI 给出的答案一定准确，但你可以要求它提供答案的依据，比如它是从哪篇文章总结出这个答案的，这样你只需进一步甄别就行。在这种情况下，只要你想学，学习任何技术都不是难事。</p>
<p>除了在项目开发和学习方面，AI 还有一些有趣的设想。在 AI 智能体出现之前，我就琢磨过，以后能不能有个 AI 智能体当我的 “替身”。把我所有的信息都喂给它，让它替我完成一些工作，比如写文章。我自己写文章时，对话题的看法、行文风格是怎样的，就希望 AI 智能体写出来的文章也符合这个风格。等把这个 AI 智能体训练到一定程度，说不定都能替我去公司上班。</p>
<p>但这个想法存在不少问题，目前能想到的就有两个。一个是责任承担的问题，这和当下的自动驾驶类似，如果出了事，责任该由谁承担呢？这个责任归属不明确，就阻碍了这种设想的推进；二是温度的问题，人是有温度的，可 AI 有吗？现实中的很多事，对错并非像 1 + 1 = 2 那么绝对，对不一定全对，错也不一定全错，遇到这种情况，AI 真的能解决吗？</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202507162019293.png"></p>
<p>所以，综合 AI 在实际应用中的各种表现，AI 真的可以取代程序员吗？有这种想法固然很好，但<strong>想法需要生长的土壤，任何激进的想法，没有因地制宜，只能是失败的。</strong></p>
<p>事实上，并不是 AI 取代了程序员，而是掌握了 AI 技能或者更有能力的人，淘汰了其他能力差的程序员。因此，在当前形势下，我们该如何增强自己的核心竞争力呢？</p>
<p>我认为，一方面，要做到知己知彼，既然想用好 AI，就得学习 AI 相关知识。另一方面，借助 AI 快速掌握更多技能，最重要的是<strong>提升解决问题的能力。</strong></p>
<p>这里我说的是技能，而非单纯的技术。因为**技术好固然重要，但如果不能为业务增长提供帮助，那技术再好也没太大价值，现实就是如此，现在都在说降本增效，公司只想看到盈利。**所以追求技术无可厚非，但最好是在清楚认识到这一点的前提下进行。</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202507162019261.png"></p>
]]></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/%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>基于Selenium实现的必应企业信息抓取工具</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/ai%E4%B8%8E%E6%8E%A2%E7%B4%A2/%E5%9F%BA%E4%BA%8Eselenium%E7%9A%84%E5%BF%85%E5%BA%94%E4%BC%81%E4%B8%9A%E4%BF%A1%E6%81%AF%E6%8A%93%E5%8F%96%E5%B7%A5%E5%85%B7%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/</link>
      <pubDate>Sat, 22 Feb 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/ai%E4%B8%8E%E6%8E%A2%E7%B4%A2/%E5%9F%BA%E4%BA%8Eselenium%E7%9A%84%E5%BF%85%E5%BA%94%E4%BC%81%E4%B8%9A%E4%BF%A1%E6%81%AF%E6%8A%93%E5%8F%96%E5%B7%A5%E5%85%B7%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/</guid>
      <description>&lt;h1 id=&#34;1-前言&#34;&gt;1. 前言&lt;/h1&gt;
&lt;p&gt;因为近期在做一些行业客户群的数据分析，拿到&lt;code&gt;600&lt;/code&gt;多条客户信息，需要对其进行分析。由于所在的是&lt;code&gt;To B&lt;/code&gt;行业，所以只能先清理掉个人以及没有明确显示企业相关信息的数据。在此之后，需要基于这些企业名单，仔细分析各企业的情况。这可以通过爱企查的批量功能快速导出各企业的情况，但其要求模板中提供的企业名称必须是全称。&lt;/p&gt;
&lt;p&gt;因此，我需要把剩下的&lt;code&gt;500&lt;/code&gt;多条企业数据的名称一一补全。一开始是打算使用&lt;code&gt;DeepSeek&lt;/code&gt;帮我基于关键词把企业名称补全，但反复验证后发现给的数据基本都是瞎编的。无奈之下，我只能一个一个查，具体操作是通过必应搜索关键词，比如“宁德时代”，然后从搜索结果中找到完整的企业名称“宁德时代新能源科技股份有限公司”复制到表格中。&lt;/p&gt;
&lt;p&gt;可是，如果只是几十条数据还好，这&lt;code&gt;500&lt;/code&gt;多条数据，我要查到猴年马月了，这人工操作实在太繁琐，而且效率太低了，实在忍不了，就想着怎么把这一整个流程实现自动化。&lt;/p&gt;
&lt;p&gt;通过&lt;code&gt;DeepSeek&lt;/code&gt;查了下，可以使用&lt;code&gt;Python&lt;/code&gt;实现，但我没学过&lt;code&gt;Python&lt;/code&gt;，不过编程语言嘛，大同小异，就依葫芦画瓢，把教程走一遍。最开始是打算使用必应搜索&lt;code&gt;API&lt;/code&gt;实现的，因为必应搜索&lt;code&gt;API&lt;/code&gt;可以免费使用，虽然有额度，但对我来说已经足够。但在开通相关服务时需要用到&lt;code&gt;VISA&lt;/code&gt;卡，各种操作实在太麻烦了，只能研究其他方案。结果好几个方案验证都行不通，我都打算放弃了，想老老实实一个个查算了，但昨晚回去又研究了一下，发现&lt;code&gt;Selenium&lt;/code&gt;可以实现这个需求。&lt;/p&gt;
&lt;h1 id=&#34;2-需求描述&#34;&gt;2. 需求描述&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;有一个&lt;code&gt;.txt&lt;/code&gt;文档用来存放关键词，有一个&lt;code&gt;.xlsx&lt;/code&gt;表格用来存放输出的结果，表格格式包含两个表头：关键词、企业名称。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;代码读取&lt;code&gt;.txt&lt;/code&gt;文档中的关键词，依次通过必应搜索，将结果中来自爱企查的信息补充到表格的企业全称中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于来自爱企查的结果，去掉后缀“ - 爱企查”，只保留企业名称内容。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;因为来自爱企查的结果通常很精准，所以第一次执行时，得到的相关公司信息基本不会有问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果没有来自爱企查的结果，则可能是关键词信息有误，这种情况下只能默认选择第一个出现的企业名称。待全部匹配输出成功后，再通过人工逐一确认。由于这种情况通常不会很多，所以工作量相对较小。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提供一个变量，可以控制是否要获取来自爱企查的结果。如果设置为“是”，则限制结果必须来自爱企查；否则选择必应搜索第一个出现的企业。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;3-项目地址&#34;&gt;3. 项目地址&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/dstweihao/bing-aiqicha-scraper&#34;&gt;GitHub - dstweihao/bing-aiqicha-scraper&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;4-项目结构&#34;&gt;4. 项目结构&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;bing&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;aiqicha&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scraper&lt;/span&gt;&lt;span class=&#34;o&#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;err&#34;&gt;├──&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;keywords&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;txt&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;err&#34;&gt;├──&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;企业名称清单&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;xlsx&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;err&#34;&gt;└──&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;py&lt;/span&gt;     					&lt;span class=&#34;c1&#34;&gt;# 主程序&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;5-依赖安装&#34;&gt;5. 依赖安装&lt;/h1&gt;
&lt;p&gt;脚本需在Python 3.6及以上版本运行，检查Python版本：&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-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;python&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;version&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-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;python&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;venv&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;venv&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;n&#34;&gt;source&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;venv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;bin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;activate&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# Windows: .venv\Scripts\activate&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-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;pip&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;install&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;selenium&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;webdriver&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;manager&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pandas&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;openpyxl&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;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;库名称&lt;/th&gt;
          &lt;th&gt;作用&lt;/th&gt;
          &lt;th&gt;安装命令&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;selenium&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;浏览器自动化控制&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;pip install selenium&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;webdriver-manager&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;自动管理浏览器驱动&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;pip install webdriver-manager&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;pandas&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;数据处理和Excel导出&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;pip install pandas&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;openpyxl&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;增强Excel文件支持&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;pip install openpyxl&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 id=&#34;6-脚本代码&#34;&gt;6. 脚本代码&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;./bing-aiqicha-scraper/run.py&lt;/code&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="1-前言">1. 前言</h1>
<p>因为近期在做一些行业客户群的数据分析，拿到<code>600</code>多条客户信息，需要对其进行分析。由于所在的是<code>To B</code>行业，所以只能先清理掉个人以及没有明确显示企业相关信息的数据。在此之后，需要基于这些企业名单，仔细分析各企业的情况。这可以通过爱企查的批量功能快速导出各企业的情况，但其要求模板中提供的企业名称必须是全称。</p>
<p>因此，我需要把剩下的<code>500</code>多条企业数据的名称一一补全。一开始是打算使用<code>DeepSeek</code>帮我基于关键词把企业名称补全，但反复验证后发现给的数据基本都是瞎编的。无奈之下，我只能一个一个查，具体操作是通过必应搜索关键词，比如“宁德时代”，然后从搜索结果中找到完整的企业名称“宁德时代新能源科技股份有限公司”复制到表格中。</p>
<p>可是，如果只是几十条数据还好，这<code>500</code>多条数据，我要查到猴年马月了，这人工操作实在太繁琐，而且效率太低了，实在忍不了，就想着怎么把这一整个流程实现自动化。</p>
<p>通过<code>DeepSeek</code>查了下，可以使用<code>Python</code>实现，但我没学过<code>Python</code>，不过编程语言嘛，大同小异，就依葫芦画瓢，把教程走一遍。最开始是打算使用必应搜索<code>API</code>实现的，因为必应搜索<code>API</code>可以免费使用，虽然有额度，但对我来说已经足够。但在开通相关服务时需要用到<code>VISA</code>卡，各种操作实在太麻烦了，只能研究其他方案。结果好几个方案验证都行不通，我都打算放弃了，想老老实实一个个查算了，但昨晚回去又研究了一下，发现<code>Selenium</code>可以实现这个需求。</p>
<h1 id="2-需求描述">2. 需求描述</h1>
<ol>
<li>
<p>有一个<code>.txt</code>文档用来存放关键词，有一个<code>.xlsx</code>表格用来存放输出的结果，表格格式包含两个表头：关键词、企业名称。</p>
</li>
<li>
<p>代码读取<code>.txt</code>文档中的关键词，依次通过必应搜索，将结果中来自爱企查的信息补充到表格的企业全称中。</p>
</li>
<li>
<p>对于来自爱企查的结果，去掉后缀“ - 爱企查”，只保留企业名称内容。</p>
</li>
<li>
<p>因为来自爱企查的结果通常很精准，所以第一次执行时，得到的相关公司信息基本不会有问题。</p>
</li>
<li>
<p>如果没有来自爱企查的结果，则可能是关键词信息有误，这种情况下只能默认选择第一个出现的企业名称。待全部匹配输出成功后，再通过人工逐一确认。由于这种情况通常不会很多，所以工作量相对较小。</p>
</li>
<li>
<p>提供一个变量，可以控制是否要获取来自爱企查的结果。如果设置为“是”，则限制结果必须来自爱企查；否则选择必应搜索第一个出现的企业。</p>
</li>
</ol>
<h1 id="3-项目地址">3. 项目地址</h1>
<p><a href="https://github.com/dstweihao/bing-aiqicha-scraper">GitHub - dstweihao/bing-aiqicha-scraper</a></p>
<h1 id="4-项目结构">4. 项目结构</h1>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">bing</span><span class="o">-</span><span class="n">aiqicha</span><span class="o">-</span><span class="n">scraper</span><span class="o">/</span>
</span></span><span class="line"><span class="cl"><span class="err">├──</span> <span class="n">keywords</span><span class="o">.</span><span class="n">txt</span>         		<span class="c1"># 输入关键词文件</span>
</span></span><span class="line"><span class="cl"><span class="err">├──</span> <span class="n">企业名称清单</span><span class="o">.</span><span class="n">xlsx</span>  		      <span class="c1"># 输出文件</span>
</span></span><span class="line"><span class="cl"><span class="err">└──</span> <span class="n">run</span><span class="o">.</span><span class="n">py</span>     					<span class="c1"># 主程序</span>
</span></span></code></pre></div><h1 id="5-依赖安装">5. 依赖安装</h1>
<p>脚本需在Python 3.6及以上版本运行，检查Python版本：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">python</span> <span class="o">--</span><span class="n">version</span>
</span></span></code></pre></div><p>创建虚拟环境：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">venv</span> <span class="o">.</span><span class="n">venv</span>
</span></span><span class="line"><span class="cl"><span class="n">source</span> <span class="o">.</span><span class="n">venv</span><span class="o">/</span><span class="nb">bin</span><span class="o">/</span><span class="n">activate</span>  <span class="c1"># Windows: .venv\Scripts\activate</span>
</span></span></code></pre></div><p>安装核心依赖：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">pip</span> <span class="n">install</span> <span class="n">selenium</span> <span class="n">webdriver</span><span class="o">-</span><span class="n">manager</span> <span class="n">pandas</span> <span class="n">openpyxl</span>
</span></span></code></pre></div><p>其中，各依赖说明如下：</p>
<table>
  <thead>
      <tr>
          <th>库名称</th>
          <th>作用</th>
          <th>安装命令</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>selenium</code></td>
          <td>浏览器自动化控制</td>
          <td><code>pip install selenium</code></td>
      </tr>
      <tr>
          <td><code>webdriver-manager</code></td>
          <td>自动管理浏览器驱动</td>
          <td><code>pip install webdriver-manager</code></td>
      </tr>
      <tr>
          <td><code>pandas</code></td>
          <td>数据处理和Excel导出</td>
          <td><code>pip install pandas</code></td>
      </tr>
      <tr>
          <td><code>openpyxl</code></td>
          <td>增强Excel文件支持</td>
          <td><code>pip install openpyxl</code></td>
      </tr>
  </tbody>
</table>
<h1 id="6-脚本代码">6. 脚本代码</h1>
<p><code>./bing-aiqicha-scraper/run.py</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">selenium.webdriver.chrome.service</span> <span class="kn">import</span> <span class="n">Service</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">webdriver_manager.chrome</span> <span class="kn">import</span> <span class="n">ChromeDriverManager</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">selenium.webdriver.common.by</span> <span class="kn">import</span> <span class="n">By</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><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="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;keywords.txt&#34;</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">search_keywords</span> <span class="o">=</span> <span class="p">[</span><span class="n">line</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">()]</span>
</span></span><span class="line"><span class="cl"><span class="n">output_file</span> <span class="o">=</span> <span class="s2">&#34;企业名称清单.xlsx&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">USE_AIQICHA</span> <span class="o">=</span> <span class="kc">True</span>  <span class="c1"># 模式切换开关：True=仅爱企查结果，False=普通模式</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">bing_search</span><span class="p">(</span><span class="n">keyword</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 动态构建查询URL</span>
</span></span><span class="line"><span class="cl">    <span class="n">query</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">keyword</span><span class="si">}</span><span class="s2">+site%3Aaiqicha.baidu.com&#34;</span> <span class="k">if</span> <span class="n">USE_AIQICHA</span> <span class="k">else</span> <span class="n">keyword</span>
</span></span><span class="line"><span class="cl">    <span class="n">driver</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;https://cn.bing.com/search?q=</span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">try</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="n">selector</span> <span class="o">=</span> <span class="s1">&#39;li.b_algo h2 a[href*=&#34;aiqicha.baidu.com&#34;]&#39;</span> <span class="k">if</span> <span class="n">USE_AIQICHA</span> <span class="k">else</span> <span class="s1">&#39;li.b_algo h2 a&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="n">result</span> <span class="o">=</span> <span class="n">driver</span><span class="o">.</span><span class="n">find_element</span><span class="p">(</span><span class="n">By</span><span class="o">.</span><span class="n">CSS_SELECTOR</span><span class="p">,</span> <span class="n">selector</span><span class="p">)</span>
</span></span><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="n">clean_name</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">text</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39; - 爱企查&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;【&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">clean_name</span><span class="p">,</span> <span class="s2">&#34;爱企查&#34;</span> <span class="k">if</span> <span class="n">USE_AIQICHA</span> <span class="k">else</span> <span class="s2">&#34;普通结果&#34;</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">USE_AIQICHA</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="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">fallback</span> <span class="o">=</span> <span class="n">driver</span><span class="o">.</span><span class="n">find_element</span><span class="p">(</span><span class="n">By</span><span class="o">.</span><span class="n">CSS_SELECTOR</span><span class="p">,</span> <span class="s1">&#39;li.b_algo h2 a&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="n">fallback</span><span class="o">.</span><span class="n">text</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39; - &#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">(),</span> <span class="s2">&#34;普通结果（待确认）&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="k">except</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="n">keyword</span><span class="p">,</span> <span class="s2">&#34;未找到&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">keyword</span><span class="p">,</span> <span class="s2">&#34;未找到（爱企查）&#34;</span>
</span></span><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="n">driver</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Chrome</span><span class="p">(</span><span class="n">service</span><span class="o">=</span><span class="n">Service</span><span class="p">(</span><span class="n">ChromeDriverManager</span><span class="p">()</span><span class="o">.</span><span class="n">install</span><span class="p">()))</span>
</span></span><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="n">results</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">kw</span> <span class="ow">in</span> <span class="n">search_keywords</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">name</span><span class="p">,</span> <span class="n">source</span> <span class="o">=</span> <span class="n">bing_search</span><span class="p">(</span><span class="n">kw</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;关键词&#34;</span><span class="p">:</span> <span class="n">kw</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;企业全称&#34;</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;来源&#34;</span><span class="p">:</span> <span class="n">source</span>  <span class="c1"># 新增来源标识列</span>
</span></span><span class="line"><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;[</span><span class="si">{</span><span class="n">source</span><span class="si">}</span><span class="s2">] </span><span class="si">{</span><span class="n">kw</span><span class="si">}</span><span class="s2"> -&gt; </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><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="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">results</span><span class="p">)[[</span><span class="s2">&#34;关键词&#34;</span><span class="p">,</span> <span class="s2">&#34;企业全称&#34;</span><span class="p">,</span> <span class="s2">&#34;来源&#34;</span><span class="p">]]</span><span class="o">.</span><span class="n">to_excel</span><span class="p">(</span><span class="n">output_file</span><span class="p">,</span> <span class="n">index</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">driver</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>
</span></span></code></pre></div><h1 id="7-运行验证">7. 运行验证</h1>
<p>在网上随机找了一些企业进行验证，关键词示例如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">极光动力
</span></span><span class="line"><span class="cl">上海明我
</span></span><span class="line"><span class="cl">易能数字能源
</span></span></code></pre></div><p>仅爱企查结果：</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202502221542457.png"></p>
<p>普通模式：</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/202502221545729.png"></p>
<h1 id="8-真实应用">8. 真实应用</h1>
<p>在真实使用过程中，可以结合企业微信文档进行操作。首先运行第一次查询，拿到“仅爱企查结果”。然后，通过爱企查的批量查询功能，将第一次查询得到的全部数据导入，进行批量查询。接着，从爱企查导出的表格中，筛选出“经营状态”为<code>--</code>的条目（这些通常是无效或无法查询到的企业信息），并将这些条目复制到爱企查的导入模板中，再进行第二次导入，这次可以使用普通模式。这样基本能简化很多工作量。</p>
]]></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>物联网开发名词解释</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E7%B3%BB%E7%BB%9F%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%90%8D%E8%AF%8D%E8%A7%A3%E9%87%8A_%E7%89%A9%E8%81%94%E7%BD%91%E5%BC%80%E5%8F%91/</link>
      <pubDate>Wed, 06 Dec 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/%E7%B3%BB%E7%BB%9F%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%90%8D%E8%AF%8D%E8%A7%A3%E9%87%8A_%E7%89%A9%E8%81%94%E7%BD%91%E5%BC%80%E5%8F%91/</guid>
      <description>&lt;h2 id=&#34;zigbee协议&#34;&gt;Zigbee协议&lt;/h2&gt;
&lt;p&gt;Zigbee协议是一种无线通信协议，专门设计用于低功耗、低数据速率、短距离的无线通信应用。它基于IEEE 802.15.4标准，并添加了网络和应用层的协议，用于构建低功耗无线传感器网络和物联网设备。&lt;/p&gt;
&lt;p&gt;以下是Zigbee协议的主要特点和组成部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;低功耗：Zigbee协议设计用于低功耗应用，节点可以进入睡眠状态以节省能量，并通过周期性唤醒来进行通信。&lt;/li&gt;
&lt;li&gt;网络拓扑：Zigbee支持多种网络拓扑结构，包括星型、网状和混合结构。其中，协调器（Coordinator）负责网络的管理和协调，路由器（Router）用于中继数据，终端设备（End Device）作为最低级的节点。&lt;/li&gt;
&lt;li&gt;自组织网络：Zigbee网络具有自组织和自愈能力，可动态调整网络拓扑结构，使网络具备容错性和鲁棒性。&lt;/li&gt;
&lt;li&gt;低数据速率：Zigbee协议适用于低数据速率的应用，通常在10-100 kbps的范围内。&lt;/li&gt;
&lt;li&gt;安全性：Zigbee协议提供多层安全机制，包括加密、认证和访问控制，以确保数据的安全性和网络的保密性。&lt;/li&gt;
&lt;li&gt;应用层协议：Zigbee协议定义了一系列的应用层协议，用于特定的应用领域，如家庭自动化、智能能源管理、工业控制等。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Zigbee协议广泛应用于物联网领域，包括智能家居、智能建筑、工业自动化、农业监测等。它提供了一种低成本、低功耗、可靠且安全的无线通信解决方案。&lt;/p&gt;
&lt;h2 id=&#34;zigbee网关&#34;&gt;Zigbee网关&lt;/h2&gt;
&lt;p&gt;Zigbee网关是连接Zigbee无线通信网络与其他网络（如以太网、Wi-Fi等）的设备。它充当一个桥梁，通过与Zigbee设备建立无线连接，将Zigbee设备的数据转发到其他网络，或将其他网络的命令传递给Zigbee设备。Zigbee网关通常具备数据转换和协议转换的功能，以适应不同网络之间的数据交互需求。&lt;/p&gt;
&lt;h2 id=&#34;zigbee组播&#34;&gt;Zigbee组播&lt;/h2&gt;
&lt;p&gt;Zigbee组播是Zigbee网络中的一种通信方式，用于一对多的数据传输。在Zigbee网络中，多个设备可以加入同一个组播组，并通过组播组地址进行通信。当一个设备发送数据到组播组地址时，所有加入该组播组的设备都可以接收到该数据。Zigbee组播可以用于广播命令、控制多个设备或进行集群通信等场景。&lt;/p&gt;
&lt;h2 id=&#34;zigbee节点&#34;&gt;Zigbee节点&lt;/h2&gt;
&lt;p&gt;Zigbee节点是指加入Zigbee无线通信网络的设备。每个Zigbee节点可以是传感器、执行器、控制器或其他类型的设备。Zigbee节点通过与Zigbee协调器通信，参与组网、数据传输和网络管理等操作。每个Zigbee节点具有唯一的64位或16位的节点地址，用于在Zigbee网络中进行标识和通信。&lt;/p&gt;
&lt;h2 id=&#34;zigbee设备&#34;&gt;Zigbee设备&lt;/h2&gt;
&lt;p&gt;Zigbee设备是指采用Zigbee通信协议的终端设备，如智能灯泡、智能插座、传感器等。这些设备可以通过Zigbee协议进行通信和互联，构建起一个Zigbee网络。在Zigbee网络中，虽然Zigbee节点和Zigbee设备通常可以视为相同的概念，但有一些微妙的区别：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;角色：Zigbee节点可以扮演不同的角色，例如协调器（Coordinator）、路由器（Router）和终端设备（End Device）。而Zigbee设备通常被视为终端设备，扮演终端设备角色。&lt;/li&gt;
&lt;li&gt;能力：Zigbee节点通常具有更复杂的功能和能力，可以作为网络的核心，负责管理网络的拓扑结构、路由选择等。而Zigbee设备通常具有更简单的功能，执行特定的任务或提供特定的服务。&lt;/li&gt;
&lt;li&gt;参与程度：Zigbee节点更强调对整个Zigbee网络的参与和管理，通常需要进行配置和设置。而Zigbee设备更强调作为终端设备的使用，通常不需要进行复杂的配置和管理。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;需要注意的是，这些区别并不是严格的定义，而是对于Zigbee网络中的概念的一种常见理解。在实际应用中，节点和设备的概念可能会交叉使用，具体的区分可以根据具体的实际情况和需求来确定。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="zigbee协议">Zigbee协议</h2>
<p>Zigbee协议是一种无线通信协议，专门设计用于低功耗、低数据速率、短距离的无线通信应用。它基于IEEE 802.15.4标准，并添加了网络和应用层的协议，用于构建低功耗无线传感器网络和物联网设备。</p>
<p>以下是Zigbee协议的主要特点和组成部分：</p>
<ol>
<li>低功耗：Zigbee协议设计用于低功耗应用，节点可以进入睡眠状态以节省能量，并通过周期性唤醒来进行通信。</li>
<li>网络拓扑：Zigbee支持多种网络拓扑结构，包括星型、网状和混合结构。其中，协调器（Coordinator）负责网络的管理和协调，路由器（Router）用于中继数据，终端设备（End Device）作为最低级的节点。</li>
<li>自组织网络：Zigbee网络具有自组织和自愈能力，可动态调整网络拓扑结构，使网络具备容错性和鲁棒性。</li>
<li>低数据速率：Zigbee协议适用于低数据速率的应用，通常在10-100 kbps的范围内。</li>
<li>安全性：Zigbee协议提供多层安全机制，包括加密、认证和访问控制，以确保数据的安全性和网络的保密性。</li>
<li>应用层协议：Zigbee协议定义了一系列的应用层协议，用于特定的应用领域，如家庭自动化、智能能源管理、工业控制等。</li>
</ol>
<p>Zigbee协议广泛应用于物联网领域，包括智能家居、智能建筑、工业自动化、农业监测等。它提供了一种低成本、低功耗、可靠且安全的无线通信解决方案。</p>
<h2 id="zigbee网关">Zigbee网关</h2>
<p>Zigbee网关是连接Zigbee无线通信网络与其他网络（如以太网、Wi-Fi等）的设备。它充当一个桥梁，通过与Zigbee设备建立无线连接，将Zigbee设备的数据转发到其他网络，或将其他网络的命令传递给Zigbee设备。Zigbee网关通常具备数据转换和协议转换的功能，以适应不同网络之间的数据交互需求。</p>
<h2 id="zigbee组播">Zigbee组播</h2>
<p>Zigbee组播是Zigbee网络中的一种通信方式，用于一对多的数据传输。在Zigbee网络中，多个设备可以加入同一个组播组，并通过组播组地址进行通信。当一个设备发送数据到组播组地址时，所有加入该组播组的设备都可以接收到该数据。Zigbee组播可以用于广播命令、控制多个设备或进行集群通信等场景。</p>
<h2 id="zigbee节点">Zigbee节点</h2>
<p>Zigbee节点是指加入Zigbee无线通信网络的设备。每个Zigbee节点可以是传感器、执行器、控制器或其他类型的设备。Zigbee节点通过与Zigbee协调器通信，参与组网、数据传输和网络管理等操作。每个Zigbee节点具有唯一的64位或16位的节点地址，用于在Zigbee网络中进行标识和通信。</p>
<h2 id="zigbee设备">Zigbee设备</h2>
<p>Zigbee设备是指采用Zigbee通信协议的终端设备，如智能灯泡、智能插座、传感器等。这些设备可以通过Zigbee协议进行通信和互联，构建起一个Zigbee网络。在Zigbee网络中，虽然Zigbee节点和Zigbee设备通常可以视为相同的概念，但有一些微妙的区别：</p>
<ol>
<li>角色：Zigbee节点可以扮演不同的角色，例如协调器（Coordinator）、路由器（Router）和终端设备（End Device）。而Zigbee设备通常被视为终端设备，扮演终端设备角色。</li>
<li>能力：Zigbee节点通常具有更复杂的功能和能力，可以作为网络的核心，负责管理网络的拓扑结构、路由选择等。而Zigbee设备通常具有更简单的功能，执行特定的任务或提供特定的服务。</li>
<li>参与程度：Zigbee节点更强调对整个Zigbee网络的参与和管理，通常需要进行配置和设置。而Zigbee设备更强调作为终端设备的使用，通常不需要进行复杂的配置和管理。</li>
</ol>
<p>需要注意的是，这些区别并不是严格的定义，而是对于Zigbee网络中的概念的一种常见理解。在实际应用中，节点和设备的概念可能会交叉使用，具体的区分可以根据具体的实际情况和需求来确定。</p>
]]></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/%E7%B3%BB%E7%BB%9F%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%85%B3%E4%BA%8E%E6%8A%80%E8%83%BD%E6%A0%91/</link>
      <pubDate>Thu, 07 Sep 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/%E7%B3%BB%E7%BB%9F%E4%B8%8E%E6%9E%B6%E6%9E%84/%E5%85%B3%E4%BA%8E%E6%8A%80%E8%83%BD%E6%A0%91/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;之前也算研究过”高效学习“这方面的书籍和课程，总的来说，无非就是意识和实践，意识是指明白以教代学是什么，实际上就是以终为始——先假设你想得到的结果，然后再倒逼我们从源头去规划应该怎么去做这个事情。如果你打算教别人东西，为了怕被别人问住，你不得不把相关知识都弄明白了，这无形之中，就给你施加了学习的压力，有处于你全面掌握这个知识点。实践，也就是毛泽东《实践论》里的观点，实践与理论反复验证，只有动手了人才会更加专注，也才会真正感受得到所要学的东西到底是什么？如果只停留在书籍上面，因为都是一些理论的东西，注意力很容易分散，学习效果大大折扣。&lt;/p&gt;
&lt;p&gt;比如，如果要学习Flutter开发，我不会一字不漏地看完官网文档才动手敲代码，我会立马开始敲代码，是的，啥都不知道，完全凭感觉去做这个事情，然后呢，如果要实现一个按钮，我就去看按钮的部分，动手实现了，如果要实现一个弹窗，我就去看弹窗的部分，把弹窗实现了，一步一步，慢慢先把用到的东西学起来，在这个过程中，你一定是带着问题去查看文档的，这无形之中，就会加深了印象。&lt;/p&gt;
&lt;p&gt;这个方法其实也是可以用在学校的，我就先做练习本或者试卷，根本就没学过这个知识，凭感觉去做，不知道就记下来，猜测应该是什么意思，然后再去找答案，再去收集，总结，再去做题。&lt;/p&gt;
&lt;p&gt;我们通常都会说，人心不足蛇吞象，想什么都学，结果什么都学不会。这个道理没错，但是，人这一生本来就很短暂，不可能看完古今中外所有的书，学到所有的知识，我只打算享受过程，哪怕最后都是半桶水也没有关系，我希望自己能成为一个有点知识的人，一方面我无法忍受自身知识的匮乏和认知的浅薄；另一个方面，我想学很多很多东西，将来可以给村里小朋友教点东西也行，或者其他地方的，很小的时候，就已经想过，将来要在二楼弄个书房，全都堆满书，然后可以借给很多人看，再有个房间，学习乐器什么的。乡下教育，一直以来的问题，其实不一定都是经济，经济当然是很大的原因，但其实更多的是缺少引路人，引路人一般都是父母，父母的知识面，眼界，信息差其实很大程度决定了小朋友的命运，他们不知道外面世界是什么样子的，每个人看到的世界有好坏之分，但是世界自身没有好坏之分，你看到什么是你个人主观投射而成，这就是引路人的价值所在，怎么去给小朋友搭建一个符合他们自身个性的世界，让他们看得到，摸得着，至于他们怎么选择，就完全看他们自己了，但是现在的情况是，很多大人没有什么知识面和眼界，那么搭建能力也就无从说起了。&lt;/p&gt;
&lt;p&gt;希望能以身践行，学习每一个技能，从实践总结成理论，将理论整理为教程。&lt;/p&gt;
&lt;h2 id=&#34;怎么学&#34;&gt;怎么学&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;怎么减肥？&lt;/li&gt;
&lt;li&gt;怎么增肌？&lt;/li&gt;
&lt;li&gt;怎么跑步？&lt;/li&gt;
&lt;li&gt;怎么游泳？&lt;/li&gt;
&lt;li&gt;怎么早睡早起？&lt;/li&gt;
&lt;li&gt;怎么学Vue开发？&lt;/li&gt;
&lt;li&gt;怎么学Flutter开发？&lt;/li&gt;
&lt;li&gt;怎么学Android开发？&lt;/li&gt;
&lt;li&gt;怎么学Nodejs开发？&lt;/li&gt;
&lt;li&gt;怎么学Java开发？&lt;/li&gt;
&lt;li&gt;怎么学ToB产品设计&lt;/li&gt;
&lt;li&gt;怎么学市场营销？&lt;/li&gt;
&lt;li&gt;怎么学项目管理？&lt;/li&gt;
&lt;li&gt;怎么学团队管理？&lt;/li&gt;
&lt;li&gt;怎么徒步？&lt;/li&gt;
&lt;li&gt;怎么学吉他？&lt;/li&gt;
&lt;li&gt;怎么学钢琴？&lt;/li&gt;
&lt;li&gt;怎么学英语？&lt;/li&gt;
&lt;li&gt;怎么学普通话？&lt;/li&gt;
&lt;li&gt;怎么学习画画？&lt;/li&gt;
&lt;li&gt;怎么做饭？&lt;/li&gt;
&lt;li&gt;怎么护肤？&lt;/li&gt;
&lt;li&gt;怎么穿搭？&lt;/li&gt;
&lt;li&gt;怎么阅读？&lt;/li&gt;
&lt;li&gt;怎么写读书笔记？&lt;/li&gt;
&lt;li&gt;怎么写电影日志？&lt;/li&gt;
&lt;li&gt;怎么写诗词？&lt;/li&gt;
&lt;li&gt;怎么创作歌词？&lt;/li&gt;
&lt;li&gt;怎么写小说？&lt;/li&gt;
&lt;li&gt;怎么写日记？&lt;/li&gt;
&lt;li&gt;怎么摄影？&lt;/li&gt;
&lt;li&gt;怎么创业？&lt;/li&gt;
&lt;/ul&gt;</description>
      <content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>之前也算研究过”高效学习“这方面的书籍和课程，总的来说，无非就是意识和实践，意识是指明白以教代学是什么，实际上就是以终为始——先假设你想得到的结果，然后再倒逼我们从源头去规划应该怎么去做这个事情。如果你打算教别人东西，为了怕被别人问住，你不得不把相关知识都弄明白了，这无形之中，就给你施加了学习的压力，有处于你全面掌握这个知识点。实践，也就是毛泽东《实践论》里的观点，实践与理论反复验证，只有动手了人才会更加专注，也才会真正感受得到所要学的东西到底是什么？如果只停留在书籍上面，因为都是一些理论的东西，注意力很容易分散，学习效果大大折扣。</p>
<p>比如，如果要学习Flutter开发，我不会一字不漏地看完官网文档才动手敲代码，我会立马开始敲代码，是的，啥都不知道，完全凭感觉去做这个事情，然后呢，如果要实现一个按钮，我就去看按钮的部分，动手实现了，如果要实现一个弹窗，我就去看弹窗的部分，把弹窗实现了，一步一步，慢慢先把用到的东西学起来，在这个过程中，你一定是带着问题去查看文档的，这无形之中，就会加深了印象。</p>
<p>这个方法其实也是可以用在学校的，我就先做练习本或者试卷，根本就没学过这个知识，凭感觉去做，不知道就记下来，猜测应该是什么意思，然后再去找答案，再去收集，总结，再去做题。</p>
<p>我们通常都会说，人心不足蛇吞象，想什么都学，结果什么都学不会。这个道理没错，但是，人这一生本来就很短暂，不可能看完古今中外所有的书，学到所有的知识，我只打算享受过程，哪怕最后都是半桶水也没有关系，我希望自己能成为一个有点知识的人，一方面我无法忍受自身知识的匮乏和认知的浅薄；另一个方面，我想学很多很多东西，将来可以给村里小朋友教点东西也行，或者其他地方的，很小的时候，就已经想过，将来要在二楼弄个书房，全都堆满书，然后可以借给很多人看，再有个房间，学习乐器什么的。乡下教育，一直以来的问题，其实不一定都是经济，经济当然是很大的原因，但其实更多的是缺少引路人，引路人一般都是父母，父母的知识面，眼界，信息差其实很大程度决定了小朋友的命运，他们不知道外面世界是什么样子的，每个人看到的世界有好坏之分，但是世界自身没有好坏之分，你看到什么是你个人主观投射而成，这就是引路人的价值所在，怎么去给小朋友搭建一个符合他们自身个性的世界，让他们看得到，摸得着，至于他们怎么选择，就完全看他们自己了，但是现在的情况是，很多大人没有什么知识面和眼界，那么搭建能力也就无从说起了。</p>
<p>希望能以身践行，学习每一个技能，从实践总结成理论，将理论整理为教程。</p>
<h2 id="怎么学">怎么学</h2>
<ul>
<li>怎么减肥？</li>
<li>怎么增肌？</li>
<li>怎么跑步？</li>
<li>怎么游泳？</li>
<li>怎么早睡早起？</li>
<li>怎么学Vue开发？</li>
<li>怎么学Flutter开发？</li>
<li>怎么学Android开发？</li>
<li>怎么学Nodejs开发？</li>
<li>怎么学Java开发？</li>
<li>怎么学ToB产品设计</li>
<li>怎么学市场营销？</li>
<li>怎么学项目管理？</li>
<li>怎么学团队管理？</li>
<li>怎么徒步？</li>
<li>怎么学吉他？</li>
<li>怎么学钢琴？</li>
<li>怎么学英语？</li>
<li>怎么学普通话？</li>
<li>怎么学习画画？</li>
<li>怎么做饭？</li>
<li>怎么护肤？</li>
<li>怎么穿搭？</li>
<li>怎么阅读？</li>
<li>怎么写读书笔记？</li>
<li>怎么写电影日志？</li>
<li>怎么写诗词？</li>
<li>怎么创作歌词？</li>
<li>怎么写小说？</li>
<li>怎么写日记？</li>
<li>怎么摄影？</li>
<li>怎么创业？</li>
</ul>
]]></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>怎么学Vue开发</title>
      <link>https://dstweihao.cn/posts/%E6%8A%80%E6%9C%AF%E4%B8%8E%E6%9E%B6%E6%9E%84/%E7%B3%BB%E7%BB%9F%E4%B8%8E%E6%9E%B6%E6%9E%84/%E6%80%8E%E4%B9%88%E5%AD%A6vue%E5%BC%80%E5%8F%91/</link>
      <pubDate>Sun, 21 Aug 2022 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/%E7%B3%BB%E7%BB%9F%E4%B8%8E%E6%9E%B6%E6%9E%84/%E6%80%8E%E4%B9%88%E5%AD%A6vue%E5%BC%80%E5%8F%91/</guid>
      <description>&lt;h1 id=&#34;第1章-简介&#34;&gt;第1章 简介&lt;/h1&gt;
&lt;p&gt;我们在学习新技术的时候，习惯于将官方文档先过一遍，将全部的知识点全部掌握之后，再进行项目实战，但是因为太多都是概念的知识，学习过程枯燥乏味，很少有人能坚持下来。&lt;/p&gt;
&lt;p&gt;所以我在想，怎么改变这种现象？以我个人的经验来说，过多深究官方文档，反而将自己陷入知识点的海洋之中，抓不到重点，往往水过鸭背，因为学了没有真正应用，不久之后就会忘记，我的意思是，不用看什么官方文档，以终为始，不用管自己到底会不会，直接上手开发项目，根据当前的需求，去学习对应的知识点，比如现在你要生成一个 Vue3.0 项目，那么你可能只需要去学一下Vite对应的知识点就好了，不用去学Vue3.0中父子组件应该怎么传值？比如你要学习开发一个登陆页面，那你就需要去看Element-Plus应该怎么引入？如果你所学并不能为当下所用，那将毫无意义。&lt;/p&gt;
&lt;p&gt;其实在你一步一步完成真实项目的过程中，就一直在学习Vue3.0的知识点了。&lt;/p&gt;
&lt;p&gt;本书计划将 &lt;code&gt;Vue3.0&lt;/code&gt; 的知识过一遍，所以一些 &lt;code&gt;Vue2.0&lt;/code&gt; 就需要的环境配置就不再过多说明，只会提到 &lt;code&gt;Vue3.0&lt;/code&gt; 开发环境配置相关的内容，用到的技术有 &lt;code&gt;Vue3.0+Vite+TypeScript+Element-Plus+Less &lt;/code&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;p&gt;在 &lt;a href=&#34;https://cn.vitejs.dev/&#34;&gt;Vite官方文档&lt;/a&gt; 中，已经提供了很多预设的模板，这里因为只关注当前使用的技术，所以其他模板并不详细说明，使用 &lt;code&gt;Vite&lt;/code&gt; 生成 &lt;code&gt;Vue3.0&lt;/code&gt; 项目模板，如果是使用 &lt;code&gt;JaveScript&lt;/code&gt; 进行开发，使用 &lt;code&gt;vue&lt;/code&gt; ，如果是使用 &lt;code&gt;TypeScript&lt;/code&gt; 进行开发，使用 &lt;code&gt;vue-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-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;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;npm&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;6.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&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;npm&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;init&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;vite&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;latest&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;my&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;app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;template&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;vue&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;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;npm&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&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;需要额外的双横线&lt;/span&gt;&lt;span class=&#34;err&#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;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;如果是使用JaveScript开发&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;，&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;使用vue&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;npm&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;init&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;vite&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;latest&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;my&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;app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;template&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;vue&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;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;如果是使用JaveScript开发&lt;/span&gt;&lt;span class=&#34;err&#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;ts&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;npm&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;init&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;vite&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;latest&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;my&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;app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;template&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;ts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/001.PNG&#34;&gt;&lt;/p&gt;
&lt;p&gt;打开chrome，就会显示项目模板的内容，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/002.PNG&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;22-chrome-91版本以上跨越问题&#34;&gt;2.2 Chrome 91版本以上跨越问题&lt;/h2&gt;
&lt;h1 id=&#34;第3章-vue30基础知识&#34;&gt;第3章 Vue3.0基础知识&lt;/h1&gt;
&lt;h2 id=&#34;31-router&#34;&gt;3.1 Router&lt;/h2&gt;
&lt;h2 id=&#34;32-comand&#34;&gt;3.2 Comand&lt;/h2&gt;
&lt;h2 id=&#34;33-porps&#34;&gt;3.3 Porps&lt;/h2&gt;
&lt;h2 id=&#34;34-emit&#34;&gt;3.4 Emit&lt;/h2&gt;
&lt;h2 id=&#34;35-vuex&#34;&gt;3.5 Vuex&lt;/h2&gt;
&lt;h3 id=&#34;351-computed&#34;&gt;3.5.1 computed&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;computed&lt;/code&gt;主要用于涉及到视图更新的处理，比如用户名username的更新，刷新后，右上角用户名没有赋值成功。在&lt;code&gt;App.vue&lt;/code&gt;中已经添加了&lt;code&gt;getUserInfo&lt;/code&gt;的网络请求，但是在右上角上赋值显示失败了。&lt;/p&gt;
&lt;p&gt;使用方式如下所示，并没有触发视图更新：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;const username = store.state.userInfo.username
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;触发视图更新：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;improt { useStore } from &amp;#39;vuex&amp;#39;
const store = useStore()
const username = computed(() =&amp;gt; {
    return store.state.userInfo.username
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;userInfo敲定刷新后的获取策略&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="第1章-简介">第1章 简介</h1>
<p>我们在学习新技术的时候，习惯于将官方文档先过一遍，将全部的知识点全部掌握之后，再进行项目实战，但是因为太多都是概念的知识，学习过程枯燥乏味，很少有人能坚持下来。</p>
<p>所以我在想，怎么改变这种现象？以我个人的经验来说，过多深究官方文档，反而将自己陷入知识点的海洋之中，抓不到重点，往往水过鸭背，因为学了没有真正应用，不久之后就会忘记，我的意思是，不用看什么官方文档，以终为始，不用管自己到底会不会，直接上手开发项目，根据当前的需求，去学习对应的知识点，比如现在你要生成一个 Vue3.0 项目，那么你可能只需要去学一下Vite对应的知识点就好了，不用去学Vue3.0中父子组件应该怎么传值？比如你要学习开发一个登陆页面，那你就需要去看Element-Plus应该怎么引入？如果你所学并不能为当下所用，那将毫无意义。</p>
<p>其实在你一步一步完成真实项目的过程中，就一直在学习Vue3.0的知识点了。</p>
<p>本书计划将 <code>Vue3.0</code> 的知识过一遍，所以一些 <code>Vue2.0</code> 就需要的环境配置就不再过多说明，只会提到 <code>Vue3.0</code> 开发环境配置相关的内容，用到的技术有 <code>Vue3.0+Vite+TypeScript+Element-Plus+Less </code>。</p>
<h1 id="第2章-开发环境配置">第2章 开发环境配置</h1>
<h2 id="21-新建项目">2.1 新建项目</h2>
<p>在 <a href="https://cn.vitejs.dev/">Vite官方文档</a> 中，已经提供了很多预设的模板，这里因为只关注当前使用的技术，所以其他模板并不详细说明，使用 <code>Vite</code> 生成 <code>Vue3.0</code> 项目模板，如果是使用 <code>JaveScript</code> 进行开发，使用 <code>vue</code> ，如果是使用 <code>TypeScript</code> 进行开发，使用 <code>vue-ts</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="err">#</span> <span class="nx">npm</span> <span class="mf">6.</span><span class="nx">x</span>
</span></span><span class="line"><span class="cl"><span class="nx">npm</span> <span class="nx">init</span> <span class="nx">vite</span><span class="err">@</span><span class="nx">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="nx">template</span> <span class="nx">vue</span>
</span></span><span class="line"><span class="cl"><span class="err">#</span> <span class="nx">npm</span> <span class="mi">7</span><span class="o">+</span><span class="p">,</span> <span class="nx">需要额外的双横线</span><span class="err">：</span>
</span></span><span class="line"><span class="cl"><span class="err">#</span> <span class="nx">如果是使用JaveScript开发</span><span class="err">，</span><span class="nx">使用vue</span>
</span></span><span class="line"><span class="cl"><span class="nx">npm</span> <span class="nx">init</span> <span class="nx">vite</span><span class="err">@</span><span class="nx">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></span><span class="line"><span class="cl"><span class="err">#</span> <span class="nx">如果是使用JaveScript开发</span><span class="err">，</span><span class="nx">使用vue</span><span class="o">-</span><span class="nx">ts</span>
</span></span><span class="line"><span class="cl"><span class="nx">npm</span> <span class="nx">init</span> <span class="nx">vite</span><span class="err">@</span><span class="nx">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><p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/001.PNG"></p>
<p>打开chrome，就会显示项目模板的内容，如下图所示：</p>
<p><img loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/002.PNG"></p>
<h2 id="22-chrome-91版本以上跨越问题">2.2 Chrome 91版本以上跨越问题</h2>
<h1 id="第3章-vue30基础知识">第3章 Vue3.0基础知识</h1>
<h2 id="31-router">3.1 Router</h2>
<h2 id="32-comand">3.2 Comand</h2>
<h2 id="33-porps">3.3 Porps</h2>
<h2 id="34-emit">3.4 Emit</h2>
<h2 id="35-vuex">3.5 Vuex</h2>
<h3 id="351-computed">3.5.1 computed</h3>
<p><code>computed</code>主要用于涉及到视图更新的处理，比如用户名username的更新，刷新后，右上角用户名没有赋值成功。在<code>App.vue</code>中已经添加了<code>getUserInfo</code>的网络请求，但是在右上角上赋值显示失败了。</p>
<p>使用方式如下所示，并没有触发视图更新：</p>
<pre tabindex="0"><code>const username = store.state.userInfo.username
</code></pre><p>触发视图更新：</p>
<pre tabindex="0"><code>improt { useStore } from &#39;vuex&#39;
const store = useStore()
const username = computed(() =&gt; {
    return store.state.userInfo.username
})
</code></pre><p>userInfo敲定刷新后的获取策略</p>
<ol>
<li>
<p>通过在App.vue中重新发起请求获取用户信息</p>
<p>问题：1.登录页面刷新因为没有token会报错，解决可以加上判断，但是代码很难看。</p>
<pre><code> 2.每个组件中都需要watch监听usrInfo，很繁琐。
</code></pre>
</li>
<li>
<p>登录后将用户信息保存在localStorage，刷新后通过vuex中获取</p>
<p>问题: 1.如果更新了用户信息,刷新后获取的还是旧的数据</p>
<pre><code> 2.在getters.ts中判断数据为空就重新发起网络请求，获取用户信息，但是因为异步的原因，数据并没有同步。
</code></pre>
</li>
<li>
<p>登录后触发commit，然后在mutations.ts中，将用户信息保存到localStorage，刷新后通过vuex获取。</p>
<p>问题: 1.需解决刷新后还是旧数据的问题，那就需要更新后，通过commit更新localStorage中的用户信息</p>
</li>
<li>
<p>最终确定以方式3实现：</p>
<p>使用方式：</p>
<pre tabindex="0"><code>
 import { useStore } from &#39;vuex&#39;

  let userInfo = store.getters.userInfo
</code></pre></li>
</ol>
<p>在ZHeaderArea.vue中的
let userInfo = computed(() =&gt; {
return store.state.userInfo
})</p>
<p>改为getter获取就报错</p>
<pre tabindex="0"><code>


### 3.5.2 watch

`watch`用于监听数据有变化触发，用于需要对数据进行操作时使用，比如个人中心，刷新后，使用`computed`方式`userInfo`没有成功获取，原因是`&lt;template&gt;`上并没有使用userInfo进行关联。

```tsx
     let userInfo = store.state.userInfo
     setUserInfoListValue(userInfo)
     watch(
         () =&gt; store.state.userInfo,
         (newValue, oldValue) =&gt; {
             userInfo = newValue
             setUserInfoListValue(userInfo)
         }
     )
     function setUserInfoListValue(info: any) {
         userInfoList.forEach((item: any) =&gt; {
             for (var key in info) {
                 if (item.prop === key) {
                     item.content = info[key] ? info[key] : &#39;--&#39;
                 }
             }
         })
     }
</code></pre><h2 id="35-viteconfigts">3.5 Vite.config.ts</h2>
<h3 id="351-如何设置路径别名">3.5.1 如何设置路径别名</h3>
<p>在项目中，因为组件或者ts文件引入，需要指定路径，如果文件层级很深，在开发中就会变得很繁琐，使用别名可以有效的解决这个问题。</p>
<p>第一步，需要在vite.config.ts文件中加上，如下所示：</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">path</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;path&#39;</span><span class="p">)</span>
</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="s1">&#39;@&#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;./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="p">......</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><p>第二步，需要在tsconfig.json文件中加上，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><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></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="s2">&#34;baseUrl&#34;</span><span class="o">:</span> <span class="s2">&#34;./&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;paths&#34;</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;@/*&#34;</span><span class="o">:</span><span class="p">[</span><span class="s2">&#34;./src/*&#34;</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>
<h1 id="第4章-搭建项目框架">第4章 搭建项目框架</h1>
<h2 id="41-container布局容器">4.1 Container布局容器</h2>
<h2 id="41-左侧菜单栏实现">4.1 左侧菜单栏实现</h2>
<ol>
<li>
<p>左侧菜单栏，实现过程中遇到了一个问题，那就是el-aside的宽度默认是300px，项目中需求是200px，这个不难，只需要在<el-aside>中设置width=&ldquo;200px&quot;就可以解决了，然后如果要实现展开和收缩，就需要设置<el-menu>，而它的宽度需要单独设置的 ，设置为200px，实现展开和收缩功能，收缩时宽度变为60px，但是<el-aside>还是200px，其实要实现联动，只需要动态设置width的值就好了，但是实现左侧菜单栏，我们通常是单独抽成组件来使用的，这样要联动就很麻烦，其实要实现也是可以的，使用props就好了，但我还是想着有没有更好的方法，有什么办法能够动态设置<el-aside>的宽度？</p>
<p>因为去掉<el-aside>的宽度属性发现，<el-menu>实现的效果是很理想的，后来发现只需要设置width为auto即可</p>
</li>
<li>
<p>左侧菜单栏，如何使用组件递归实现？</p>
</li>
<li>
<p>el-menu折叠时为何不显示二级菜单？</p>
<p>当菜单栏折叠时，发现首页的图标没有显示，实现的代码如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">el</span><span class="o">-</span><span class="nx">menu</span><span class="o">-</span><span class="nx">item</span> <span class="nx">v</span><span class="o">-</span><span class="k">if</span><span class="o">=</span><span class="s2">&#34;!item.childrens&#34;</span> <span class="o">:</span><span class="nx">index</span><span class="o">=</span><span class="s2">&#34;`${String(index)}`&#34;</span> <span class="o">:</span><span class="nx">route</span><span class="o">=</span><span class="s2">&#34;item.index&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="o">&lt;</span><span class="nx">template</span> <span class="err">#</span><span class="nx">title</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">		<span class="o">&lt;</span><span class="nx">div</span> <span class="kr">class</span><span class="o">=</span><span class="s2">&#34;zws-aside-menu-item&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">			<span class="o">&lt;</span><span class="nx">i</span> <span class="o">:</span><span class="kr">class</span><span class="o">=</span><span class="s2">&#34;`zws-aside-menu-item-iconSetting iconfont ${item.icon}`&#34;</span><span class="o">&gt;&lt;</span><span class="err">/i&gt;</span>
</span></span><span class="line"><span class="cl">			<span class="o">&lt;</span><span class="nx">span</span><span class="o">&gt;</span><span class="p">{{</span> <span class="nx">item</span><span class="p">.</span><span class="nx">title</span> <span class="p">}}</span><span class="o">&lt;</span><span class="err">/span&gt;</span>
</span></span><span class="line"><span class="cl">		<span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="o">&lt;</span><span class="err">/template&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="err">/el-menu-item&gt;</span>
</span></span></code></pre></div><p>之前的项目没有这个问题是因为不是使用collapse这个属性实现的，而是动态设置宽度，200和60切换达到的效果。查看官方文档的案例，发现这个写法，当折叠时，是显示图标的，如下所示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">el</span><span class="o">-</span><span class="nx">menu</span><span class="o">-</span><span class="nx">item</span> <span class="nx">index</span><span class="o">=</span><span class="s2">&#34;4&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="o">&lt;</span><span class="nx">i</span> <span class="kr">class</span><span class="o">=</span><span class="s2">&#34;el-icon-setting&#34;</span><span class="o">&gt;&lt;</span><span class="err">/i&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="o">&lt;</span><span class="nx">span</span> <span class="nx">slot</span><span class="o">=</span><span class="s2">&#34;title&#34;</span><span class="o">&gt;</span><span class="nx">导航四</span><span class="o">&lt;</span><span class="err">/span&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="err">/el-menu-item&gt;</span>
</span></span></code></pre></div><p>然后按照官网的写法，将<template>去掉就没再出现这个问题了。</p>
</li>
<li>
<p>点击左侧菜单栏，没有触发路由跳转？</p>
<p>原因是：在<el-menu>组件中忘记加上router了</p>
</li>
<li>
<p>路由跳转到新的页面，怎么让新的页面是在<el-main>组件中的？</p>
<p>需要设置嵌套路由，而且path设置时需要/，但是子路由path前面不用加/。</p>
</li>
<li>
<p>当<el-aside>的width设置为auto时，出现多余边框，如下图所示：</p>
<p><img alt="003" loading="lazy" src="https://dstweihao-1300388255.cos.ap-guangzhou.myqcloud.com/images/003.png"></p>
<p>但是如果把width设置为200px，是没有这个问题的，问题应该出在<el-menu>组件上面，当把它设置width为200px时，实际上<el-aside>的width是201px，这个1px到底是从哪里来的？</p>
</li>
<li></li>
<li></li>
<li></li>
</ol>
<h2 id="42-主题色切换">4.2 主题色切换</h2>
<h3 id="421-在项目中改变-sass-变量">4.2.1 在项目中改变 SASS 变量</h3>
<p>由于Element-Plus<code>处于开发状</code>态，所以官方文档里并没能做到实时更新，导致按照提供的方式，其实出现了很多问题，经过研究，当前版本，正确的配置方式为：</p>
<ol>
<li>
<p>在项目目录新建<code>element-variables.scss</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="cm">/* 改变主题色变量 */</span>
</span></span><span class="line"><span class="cl"><span class="nx">$</span><span class="o">--</span><span class="nx">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="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;base&#34;</span><span class="o">:</span> <span class="err">#</span><span class="mi">80</span><span class="nx">b33f</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="cm">/* 改变 icon 字体路径变量，必需（将~去掉，不然不显示图标） */</span>
</span></span><span class="line"><span class="cl"><span class="nx">$</span><span class="o">--</span><span class="nx">font</span><span class="o">-</span><span class="nx">path</span><span class="o">:</span> <span class="s2">&#34;element-plus/lib/theme-chalk/fonts&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="cm">/* 将~改为node_modules后，确实解决了路径引用报错的问题，但是项目每次刷新都很慢，需持续留意解决方案*/</span>
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="kr">import</span> <span class="s2">&#34;node_modules/element-plus/packages/theme-chalk/src/index.scss&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/* 一般以上就够满足需求了，其他设置*/</span>
</span></span><span class="line"><span class="cl"><span class="nx">$</span><span class="o">--</span><span class="nx">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="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;base&#34;</span><span class="o">:</span> <span class="err">#</span><span class="mi">003261</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="s2">&#34;success&#34;</span><span class="o">:</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;base&#34;</span><span class="o">:</span> <span class="err">#</span><span class="mi">21</span><span class="nx">ba45</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="s2">&#34;warning&#34;</span><span class="o">:</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;base&#34;</span><span class="o">:</span> <span class="err">#</span><span class="nx">f2711c</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="s2">&#34;danger&#34;</span><span class="o">:</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;base&#34;</span><span class="o">:</span> <span class="err">#</span><span class="nx">db2828</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="s2">&#34;error&#34;</span><span class="o">:</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;base&#34;</span><span class="o">:</span> <span class="err">#</span><span class="nx">db2828</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="s2">&#34;info&#34;</span><span class="o">:</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;base&#34;</span><span class="o">:</span> <span class="err">#</span><span class="mi">42</span><span class="nx">b8dd</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>main.ts</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">import</span> <span class="nx">App</span> <span class="nx">from</span> <span class="s1">&#39;./App.vue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">ElementPlus</span> <span class="nx">from</span> <span class="s1">&#39;element-plus&#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">createApp</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 class="kr">import</span> <span class="p">{</span> <span class="nx">router</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;./router/index&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="s1">&#39;./assets/iconfont/iconfont.css&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 引入 element-variables.scss 文件
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="s1">&#39;../element-variables.scss&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">createApp</span><span class="p">(</span><span class="nx">App</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="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">router</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">mount</span><span class="p">(</span><span class="s1">&#39;#app&#39;</span><span class="p">)</span>
</span></span></code></pre></div></li>
</ol>
<h3 id="422-命令行主题工具">4.2.2 命令行主题工具</h3>
<p>如果项目中没有使用SASS，推荐使用这个方式。</p>
<ol>
<li>
<p>在使用Elment-Plus时，打算切换主题色，安装官方文档实现，运行<code>et -i</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="nx">Run</span> <span class="sb">`npm audit`</span> <span class="k">for</span> <span class="nx">details</span><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="nx">weihao</span><span class="err">@</span><span class="nx">weihao</span><span class="o">-</span><span class="nx">mac</span><span class="o">-</span><span class="nx">mini</span> <span class="nx">vue3</span><span class="p">.</span><span class="mi">0</span> <span class="o">%</span> <span class="nx">et</span> <span class="o">-</span><span class="nx">i</span>
</span></span><span class="line"><span class="cl"><span class="nx">fs</span><span class="p">.</span><span class="nx">js</span><span class="o">:</span><span class="mi">45</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="o">=</span> <span class="nx">primordials</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="o">^</span>
</span></span><span class="line"><span class="cl"><span class="nx">ReferenceError</span><span class="o">:</span> <span class="nx">primordials</span> <span class="nx">is</span> <span class="nx">not</span> <span class="nx">defined</span>
</span></span><span class="line"><span class="cl">    <span class="nx">at</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">js</span><span class="o">:</span><span class="mi">45</span><span class="o">:</span><span class="mi">5</span>
</span></span><span class="line"><span class="cl">    <span class="nx">at</span> <span class="nx">req_</span> <span class="p">(</span><span class="err">/usr/local/lib/node_modules/element-theme/node_modules/natives/index.js:143:24)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">at</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">req</span> <span class="p">[</span><span class="nx">as</span> <span class="nx">require</span><span class="p">]</span> <span class="p">(</span><span class="err">/usr/local/lib/node_modules/element-</span>
</span></span></code></pre></div><p>这个原因是因为Node.js版本过高导致的，官方推荐最好小于12版本。</p>
</li>
</ol>
<h2 id="43-项目部署服务器">4.3 项目部署服务器</h2>
<p>项目部署服务器的时候，发现console里显示报错，没有加载到相关js等等问题，原因是在<code>vite.config.ts</code>文件中少了设置<code>base:'./'</code>,再次部署，加载资源文件没有显示报错，但是页面显示空白，这是因为<code>router/index.ts</code>文件中，指定的路由模式为<code>history: createWebHistory()</code>，需要改为<code>history: createWebHashHistory()</code>,这两种模式的差别可看一下文章：<a href="https://www.xieniao.com/news/content/7156.html">VUE3.0 createWebHistory和createWebHashHistory</a></p>
<h1 id="第5章-其他问题">第5章 其他问题</h1>
<ol>
<li>Vue3.0项目中引入.js文件，打包报错的问题</li>
</ol>
<p><a href="https://blog.csdn.net/Haveyounow/article/details/118819037?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&amp;depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link">https://blog.csdn.net/Haveyounow/article/details/118819037?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&amp;depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link</a></p>
<ol start="2">
<li>
<p>@mouseenter 和 @mouseleave事件闪烁问题</p>
<p>不是后来才了解到，只能父子元素形成，不可以兄弟元素，兄弟元素就会闪烁</p>
</li>
</ol>
<h1 id="本书待补充知识点记录">本书待补充知识点记录</h1>
<ul>
<li>
<p><input disabled="" type="checkbox"> vuex使用指南，pinia使用指南，其与vuex的区别在哪里？</p>
</li>
<li>
<p><input disabled="" type="checkbox"> vue项目，vscode中debug使用指南</p>
</li>
<li>
<p><input disabled="" type="checkbox"> 提供vue学习路线，包括js、html、css、vue、vite、element plus等等</p>
</li>
</ul>
]]></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>
