<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
<channel>
<title>橘纸柚的博客 - 一只咸鱼的自留地</title>
<link>https://lovemen.cc/</link>
<description>这里是橘纸柚的博客，一只正在挣扎着的咸鱼自留地，也可能是杂鱼。分享一些日常牢骚，和一些体验相关还有笔记和小记录。这是一个咕咕咕的个人博客，更新不勤快请见谅。</description>
<atom:link href="https://lovemen.cc/rss.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Tue, 07 Apr 2026 18:56:11 +0800</lastBuildDate>
<item>
<title>2025 年总结</title>
<link>https://lovemen.cc/moe2220.html</link>
<guid isPermaLink="false">https://lovemen.cc/moe2220.html</guid>
<pubDate>Sun, 15 Feb 2026 22:31:00 +0800</pubDate>
<dc:creator>橘纸柚</dc:creator>
<category><![CDATA[闲聊]]></category>
<description><![CDATA[咕咕咕还没农历新年，所以还不晚（嘴硬）
主要是2025年没什么好回忆的好事情...不知道如何写是好。
从辞职开始
2025年开始的第一件事就是辞职了。因为项目和难绷的事情最后还是选择了辞职，经过这四年的折腾对做开发这件事已经没什么心情了。真是干一行恨一行啊...]]></description>
<content:encoded><![CDATA[
<!--markdown-->咕咕咕还没农历新年，所以还不晚（嘴硬）
<p>主要是2025年没什么好回忆的好事情...不知道如何写是好。</p>
<h1>从辞职开始</h1>
<p>2025年开始的第一件事就是辞职了。因为项目和难绷的事情最后还是选择了辞职，经过这四年的折腾对做开发这件事已经没什么心情了。真是干一行恨一行啊。</p>
<h1>痛苦搬家</h1>
<p>递交辞职一个月后终于完成了交接，然后就是搬家了。好在我家就在隔壁市好搬...? 不得不说每次搬家都会对接线陷入怀疑人生，好多线啊，至今我都没吧搬家过来的东西装完，主要还是太懒了而且到现在也没写什么代码，本来想着要用的时候再装然后结果是电脑也懒得装起来。</p>
<h1>分手？</h1>
<p>我还是太内向了，和上一个对象其实没什么聊天，其实我到现在也不知道和对象要聊什么。然后对方觉得我不喜欢她...嘛过去了说也没什么了。</p>
<h1>旅行</h1>
<p>最近五年终于出了一次省啊...辞职了在自由职业到处摸鱼有了一些游玩时间。于是就在年底和Hikari和王小美去香港，诶正好赶上了<del>会封</del>汇丰的收取管理费末班车。值得说的就是我的出入境记录一直没出，只好跟着他们到处晃悠，晚上终于出入境记录有了我哭死，提交了两家银行的网申，<del>可算没白来</del>，现在卡都到了？不存在了我的BOCHK卡死活被退回但是账单又能寄到，我绷住了。
香港结束后去了广州，非常感谢千畔和葵野几位推油带着我和葵花在广州游玩广州菜真好吃啊！<del>结束那么久我脑子里还充满了“激情全运会，活力大湾区，魅力新广州”</del></p>
<h1>结语</h1>
<p>2025年是浑浑噩噩的一年吧？其实没做什么事情，现在也不知道干什么？辞职后去干其他事情还没找到干什么是好。</p>
]]></content:encoded>
<slash:comments>4</slash:comments>
<comments>https://lovemen.cc/moe2220.html#comments</comments>
</item>
<item>
<title>2024年总结</title>
<link>https://lovemen.cc/moe2197.html</link>
<guid isPermaLink="false">https://lovemen.cc/moe2197.html</guid>
<pubDate>Sat, 11 Jan 2025 15:14:00 +0800</pubDate>
<dc:creator>橘纸柚</dc:creator>
<category><![CDATA[闲聊]]></category>
<category><![CDATA[年终总结]]></category>
<description><![CDATA[拖延症是有点严重了，这新年第几天了都2024啊...回老家上班第二年了，过去这一年其实挺无聊的，基本上全是两点一线以至于我都有点懒得写。
回忆应该上个月就要开始回忆这一年了，但是工作充满了整个生活所以没有空回想。
于是在这好不容易得到的休息日赶快翻起了相册...]]></description>
<content:encoded><![CDATA[
<!--markdown-->拖延症是有点严重了，这新年第几天了都2024啊...回老家上班第二年了，过去这一年其实挺无聊的，基本上全是两点一线以至于我都有点懒得写。
<p>回忆应该上个月就要开始回忆这一年了，但是工作充满了整个生活所以没有空回想。
于是在这好不容易得到的休息日赶快翻起了相册开始一边回忆一边起草吧！</p>
<h1>年初的第一场雪</h1>
<p>这破地方居然下雪了！在记忆里上次这里大范围的下雪还是小学三年级还是四年级时候，下班后赶快驱车回家去到处闲逛，虽然2023年在杭州也下雪了，但是确实很喜欢白皑皑的雪天啊！不过今年2025年一月还没下，但愿今年还有。
<img src="https://cdn.sa.net/2025/02/27/vwg7HebLNxTXMIc.png" alt="1.png" /></p>
<h1>丽水</h1>
<p>去丽水还了一顿欠亲友的饭（大雾），然后带着他去吃了徐府牛，被吐槽太清淡了。笑死，有时间再补一顿。</p>
<h1>杭州</h1>
<p>时隔一年，好像是一年了...哦不对差几天我2023年3月12日跑的。网上认识了好久终于和葵花与Ho线下会面了！一路狂奔猛赶在了中午到了杭州，第二天去了城市阳台、宜家餐厅和葵花到处晃悠。
总体还是匆忙的，这就不得不夸奖一下南站的神经设计了我在这头这站台隔了一墙，但是得穿过整个车站才能安检入站。啊啊啊神经设计，承包我一周的运动量。不过又如工作狂的这一年里久违的休息了一下。
<img src="https://cdn.sa.net/2025/02/27/P3mhT5MwfUq8HSF.png" alt="2.png" /></p>
<h1>为 “女儿” 买 “买衣服”</h1>
<p>去年一年我的邮箱内充满了 Skeb 的邮件，过去一年居然不知道哪根筋抽了约了 50 张图两个账号总共花费 10 万日元，Skeb 不给我总结我都没注意到慢慢花掉了那么多。当然还有 bilibili 工坊和闲鱼约的图没算在里面...金币消失术啊这。OC 的网站倒是到现在还就只搭了个大概，UI 都还没画完，太咕咕咕了。</p>
<h1>贴贴！</h1>
<p>一年新面了 7 位网友。居然还能挤出来一点时间去面，可惜 podf 没抽到时间去面，希望还能有机会 XD</p>
<h1>相亲</h1>
<p>等等，我才几岁？我爸妈知道你很急但是你们先别急！不过确实相亲对象人挺好的，争取吧...虽然现在还不知道什么共同爱好，不过我确实也不是那种会主动去找女朋友的状态，不过这样也好，不会周末无聊了嘛。</p>
<h1>迁移</h1>
<p>因为鸡总失联多日加上微基主机变得不稳定，于是给家里的老机器做了下扩容将博客等站点都搬回了家里的机器上，所以现在速度可能会慢一些毕竟 H81 平台的电脑还被我关了超线程和锐频功能省电，并且还不止跑了博客和 API 服务，实在不行买台新电脑吧也确实该换新了已经是 10 年的老家伙了。</p>
<h1>新购入</h1>
<p>简单总结一下吧，就不去想那些零零散散的小物件了。啊 2023 年买的那些东西的博文还躺在草稿箱里呢，2024 年新买的这堆连草稿箱都没写进去。完了彻底鸽子了。</p>
<h2>iPhone 13 mini</h2>
<p>主力机从 Moto edge s 换成了 iPhone 13 mini，到手半小时内就被我手滑边框摔了一个坑。心痛，太痛了！</p>
<h2>Macbook Air</h2>
<p>本来一开始想买 15 寸的 Macbook Air 但是考虑到我笔记本都是外接一个屏幕用，带出门只是为了跑客户用于是就买了标准版。以及 M2 和 M3 的提升确实对我来说没什么于是选了 M2，然后非常幽默我赌 M4 得 2025 年春季才出我刚买了Macbook Air才两周不到，嚯开发布会了接着官网就砍掉了8G配置加量不加价，多花了1500买16G的小丑，诶背刺体制这不就是嘛。</p>
<h2>台式机</h2>
<p>从狐店长那买了台新的台式机，然后现在连着加班两个月了，就开机了一次剩下时间全在吃灰不过电子ED了确实那个点也没什么想玩的。</p>
<h2>自行车</h2>
<p>自行车感觉是今年买的比台式机还失败的一个物件，本想着骑车减肥但是看它现在吃灰的样子，减肥？减不了一点。</p>
<h1>结尾</h1>
<p>感谢你能把我这无趣的流水账看到这里。过去一年确实博客几乎荒废了，我现在确实不知道有什么可以分享的内容。
过去那 2024 年确实更加无趣了，更多时候都在两点一线。以及精神状态更加美丽，我现在不知道我为什么而存在。工作上，只能说我是真的干一行恨一行啊！已经开始想下一份工作做什么了，但是没什么头绪。
希望新的一年<del>能在工作上找到新的抓手</del>，诶没什么大要求能快乐就行对吧～</p>
]]></content:encoded>
<slash:comments>18</slash:comments>
<comments>https://lovemen.cc/moe2197.html#comments</comments>
<enclosure url="https://cdn.sa.net/2025/02/27/ZYI13Et847hakpu.jpg" length="0" type="image/jpeg" />
</item>
<item>
<title>ChromeOS Linux 容器基础配置</title>
<link>https://lovemen.cc/moe2155.html</link>
<guid isPermaLink="false">https://lovemen.cc/moe2155.html</guid>
<pubDate>Wed, 31 Jan 2024 18:59:00 +0800</pubDate>
<dc:creator>橘纸柚</dc:creator>
<category><![CDATA[笔记]]></category>
<category><![CDATA[ChromeOS]]></category>
<description><![CDATA[因为经常把 ChromeOS 搞崩总不能每次重置后东翻翻西翻翻找配置方法，所以还是整理了一下。
停止容器运行
有些情况下会导致 Linux 容器无响应，可以通过在 Chrome 的窗口内使用键盘快捷键 ctrl + alt + t 掉出 crosh 在然后...]]></description>
<content:encoded><![CDATA[
<!--markdown-->因为经常把 ChromeOS 搞崩总不能每次重置后东翻翻西翻翻找配置方法，所以还是整理了一下。
<h1>停止容器运行</h1>
<p>有些情况下会导致 Linux 容器无响应，可以通过在 Chrome 的窗口内使用键盘快捷键 <code>ctrl + alt + t</code> 掉出 crosh 在然后输入 <code>vmc stop termina</code> 即可停止 Termina VM 运行，然后就可以在终端中点击 Linux 容器来再次启动。</p>
<hr />
<h1>设置时区</h1>
<p>启动 Linux 容器后默认时区为 <code>America/New_York</code> 按照我的习惯喜欢先设置时区，输入以下命令即可进入 GUI 界面进行设置我一般设置为 <code>Asia/Shanghai</code>。</p>
<pre><code>sudo dpkg-reconfigure tzdata</code></pre>
<hr />
<h1>设置 Linux 容器环境为中文</h1>
<p>如果有需要的话首先得输入以下指令安装中文字体，不然可以看到一堆 "口"。</p>
<pre><code>sudo apt install fonts-wqy-microhei fonts-wqy-zenhei</code></pre>
<p>然后输入 <code>sudo dpkg-reconfigure locales</code> 更改语言环境，按住下键一直下拉选框，找到 <code>zh_CN.UTF-8 UTF-8</code> 将光标移至前方 <code>[ ]</code> 按下空格键勾选， <code>[ ]</code> 变为  <code>[*]</code> 即为勾选状态，然后回车后光标移至于 <code>zh_CN.UTF-8</code> 继续回车即可完成设置，需要重启 Linux 容器生效。</p>
<hr />
<h1>修改软件源</h1>
<p>我国内一般使用的是 TUNA 的软件源，具体可以查看 TUNA 的《<a href="https://mirrors.tuna.tsinghua.edu.cn/help/debian/">Debian 软件源</a>》文档，我就按照他们所说的 <code>deb.debian.org</code> 替换为 <code>mirrors.tuna.tsinghua.edu.cn</code>没有做更多的操作。
使用 <code>sudo vi /etc/apt/sources.list</code> 然后点击键盘 <code>i</code> 进入编辑可以直接替换掉现有的或者使用 <code>#</code> 注释现有的填入新的然后点击键盘的 <code>ESC</code> 输入 <code>:wq</code> 退出 vi 然后使用 <code>sudo apt update</code> 更新软件源。
你还可以更新完软件源后继续执行 <code>sudo apt upgrade</code> 更新已安装的应用程序和 <code>sudo apt dist-upgrade</code> 更新 Debain 本体。</p>
<hr />
<h1>安装中文输入法</h1>
<p>首先需要更新软件源与软件包 <code>sudo apt update &amp;&amp; sudo apt upgrade</code> 然后安装 Fcitx。</p>
<pre><code>sudo apt install fcitx fcitx-lib*</code></pre>
<p>完成安装后需要设置默认输入法，在终端输入 <code>im-config</code> 确定 / YES 大概两次到一个单选界面时选择 fcitx 然后继续大概两次确定 / YES 即可。
完成 Fcitx 的安装后接下来安装 Google 输入法。</p>
<p>sudo apt install fcitx-googlepinyin</p>
<p>完成 Google 输入法的安装后需要在终端输入 <code>fcitx &amp;&amp; fcitx-configtool</code> 点击右下角 "-" 减号删除全部输入法，然后点击右下角 "+" 加号加入 "键盘 - 英语 (美国)" 与 "Google 拼音"。
接下来需要配置配置语言输入环境变量，在终端输入:</p>
<pre><code>mkdir -p ~/.config/environment.d/
vi ~/.config/environment.d/fcitx.conf</code></pre>
<p>进入 vi 编辑器后按下键盘上的 <code>i</code> 加入以下内容</p>
<pre><code>GTK_IM_MODULE=fcitx
QT_IM_MODULE=fcitx
XMODIFIERS=@im=fcitx</code></pre>
<p>然后单击键盘的 <code>ESC</code> 输入 <code>:wq</code> 保存并退出，即完成了环境的配置。然后我们需要设置开机自启动。使用 <code>sudo vi ~/.sommelierrc</code> 进入 vi 编辑器点击键盘上的 <code>i</code> 进入编辑模式，添加一行 <code>/usr/bin/fcitx-autostart</code> 然后点击键盘的 <code>ESC</code> 输入 <code>:wq</code> 即可完成配置。
输入法配置结束后可以使用 <code>ctrl + 空格</code> 切换出 Google 输入法，如果无效可以重启 Linux 容器试试看。</p>
<hr />
<h1>钉钉</h1>
<p>如果您工作中离不开阿里的答辩，但是你会发现在钉钉官网下载的安装包（写本文时版本为 7.1.0.31120）安装后它读不到图标是默认的企鹅图标而且点击企鹅图标后是无反应的。让我们使用命令行 <code>bash /opt/apps/com.alibabainc.dingtalk/files/Elevator.sh</code> 启动它会看到日志</p>
<pre><code>debian
debian branch
preload_libs= ./libcef.so
Run Main is_gpu=0 is_zygote=0 is_render=0 is_crashpad_handler=0 cmd : ./com.alibabainc.dingtalk 
Load /opt/apps/com.alibabainc.dingtalk/files/7.1.0-Release.31120//dingtalk_dll.so failed! Err=libpulse-mainloop-glib.so.0: cannot open shared object file: No such file or directory</code></pre>
<p>可以看到报出了没有 <code>libpulse-mainloop-glib.so</code> 所以可以通过安装 libpulse 库的方式解决，在终端输入：</p>
<pre><code>sudo apt install libpulse-dev</code></pre>
<p>完成安装后即可成功启动钉钉，但是你会发现它窗口无法拖动，诶答辩终究是答辩，目前我是专门开了个桌面凑合着用。</p>
<h1>字体管理器</h1>
<p>因为我懒狗所以还是喜欢用 GUI 操作，所以还是会装个字体管理器来管理 ttf 和 otf 字体</p>
<pre><code>sudo apt install font-manager</code></pre>
<hr />
<h1>安装 Flatpak</h1>
<p>安装 Flatpak ：</p>
<pre><code>sudo apt-get install flatpak</code></pre>
<p>配置源：</p>
<pre><code>flatpak --user remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo</code></pre>
<p>配置镜像：</p>
<pre><code>flatpak --user remote-modify flathub --url=https://mirror.sjtu.edu.cn/flathub</code></pre>
]]></content:encoded>
<slash:comments>3</slash:comments>
<comments>https://lovemen.cc/moe2155.html#comments</comments>
</item>
<item>
<title>关于过去的2023</title>
<link>https://lovemen.cc/moe2136.html</link>
<guid isPermaLink="false">https://lovemen.cc/moe2136.html</guid>
<pubDate>Tue, 02 Jan 2024 20:57:00 +0800</pubDate>
<dc:creator>橘纸柚</dc:creator>
<category><![CDATA[闲聊]]></category>
<category><![CDATA[年度总结]]></category>
<description><![CDATA[哇！这的博客居然诈尸更新啦！2022 年的年度总结给咕咕咕没了（呆），趁着 2024 年才刚开始，赶快把 2023 年的年度总结给咕咕咕出来...（小声）
2023 跨年夜，后
跨年夜与砍老师和 Yuzu 一起吃了一顿萨，之后就回到了老家过年，年后又回到了...]]></description>
<content:encoded><![CDATA[
<!--markdown-->哇！这的博客居然诈尸更新啦！2022 年的年度总结给咕咕咕没了（呆），趁着 2024 年才刚开始，赶快把 2023 年的年度总结给咕咕咕出来...（小声）
<h1>2023 跨年夜，后</h1>
<p>跨年夜与砍老师和 Yuzu 一起吃了一顿萨，之后就回到了老家过年，年后又回到了杭州，看起了八股文准备找一份新工作，虽然中间还是有面就面 ～ 毕竟我不清楚以后还有没有机会见到，能见就见见。
<img src="https://cdn.sa.net/2025/03/03/imSKBsk8jHNZECf.png" alt="关于过去的2023-1.png" /></p>
<hr />
<h1>在杭找工作的三月</h1>
<p>今年年初试图在杭州找一份工作留在杭州，但是我太菜了，海投了 2000 家 BOSS 直聘变成了 BOSS 直拒，只有一家把底薪谈在 4000 工资的公司要了我。学历卷不过工作经验也卷不过于是就先问了问家里人准备回去，在哥的帮助的情况下在家那边找到了一家和杭州面试上的这家开的差不多，于是就干脆回去了。
<img src="https://cdn.sa.net/2025/03/03/lSQPI7x95UuYzhc.png" alt="关于过去的2023-2.png" /></p>
<hr />
<h1>回家后</h1>
<p>回家后继续陆陆续续的面试了几家公司，可能是我心太躁了，于是就和亲友一拍即合去了瑞安玩了几天。以及和许久未见的亲友们去聚了聚，一起吃了顿后看了《铃芽之旅》，感谢朋友的陪伴度过了不焦虑的几天。在家躺着摆了几天，终于收到了一家公司的 offer。也是属于运气好，他们公司正好有位要离职，我来顶上。
<img src="https://cdn.sa.net/2025/03/03/tNwFPEhydoc7peK.png" alt="关于过去的2023-3.png" /></p>
<hr />
<h1>试用期 &amp; 贴贴</h1>
<p>新的公司是外企作息，早九晚五有了大量的贴贴时间 ～ 借机抽空贴贴了不少之前没来得及贴贴的 ～ 可惜一直没能抽出找 DVD 大 I 人也不太敢打扰他（缩）
<img src="https://cdn.sa.net/2025/03/03/s5lMx8ye41XRUVS.png" alt="关于过去的2023-4.png" /></p>
<hr />
<h1>公司被收购啦！</h1>
<p>不知道是不是我有特殊的 buff 加成干一家倒一家/合并一家，一天的晨会，突然老板表示公司给收购了。然后就搬到了新的办公区，双休没了变成了单双休，早九晚五也没了变成了早八战士，上班需要打卡了。不过好在其他都没什么大变，适应过来也不算困难，就是啊新的办公场所边上全是美食荒漠啊，麦当劳都没有，可恶啊！</p>
<hr />
<h1>非常难要的押金</h1>
<p>以为公司太远了，所以干脆退房搬家。然后我可爱的房东阿姨，退个押金拖了我一个多月，最后在给他便宜了 300 的情况下，收到了余款...诶，就算我退房拍好了照片，录了视频，以为要没钱吃饭了，也经不起她拖知道我急了东扣点西扣点。这就是《人性的弱点》吧（乐）</p>
<hr />
<h1>圣诞快乐</h1>
<p>圣诞节被迫请假，因为要收到新房了，没有逾期没有烂尾这可能也是一份很好的圣诞礼物吧！悬着的心落下了一块？不还有验房一堆整改项和装修这个大坑！
今年的圣诞节，收到了三样礼物，还是有朋友惦记着好诶～
<img src="https://cdn.sa.net/2025/03/03/p2Wx3TcPzVuyHJU.png" alt="关于过去的2023-5.png" /></p>
<hr />
<h1>跨年饭</h1>
<p>12 月半个月都在吃汉堡王、麦当劳、肯德基，是时候吃点健康的食品了吧？
<img src="https://cdn.sa.net/2025/03/03/oV3eaO6ZIBriKqu.png" alt="关于过去的2023-6.png" /></p>
<hr />
<h1>尾巴</h1>
<p>今年一共面基了 6 次，感谢大家的抽空。收到了 3 份圣诞礼物，收到礼物很开心，谢谢几位小伙伴 ～ 及共收到了三张明信片，Fika 与 Steven Lynn 的明信片，以及一张意外的来自史莱姆寄出近一年突然中国邮政丢到我的信箱的明信片。
<img src="https://cdn.sa.net/2025/03/03/cARqB4usy7K3hZC.png" alt="关于过去的2023-7.png" /></p>
<hr />
<h1>新的开始？</h1>
<p>2023 年结束了，新年就是新的开始吧！让海风吹走去年的不幸与遗憾开始新的一年吧！新年快乐！新的一年也请多多指教！
<img src="https://cdn.sa.net/2025/03/03/Bv5NpeIW7KOZlCu.png" alt="关于过去的2023-end.png" />
虽然最后还是咕咕咕到了 1 月 2 日，那也算新年吧！（傲娇）</p>
]]></content:encoded>
<slash:comments>13</slash:comments>
<comments>https://lovemen.cc/moe2136.html#comments</comments>
<enclosure url="https://cdn.sa.net/2025/03/03/5ZFcpgbqDfHVauR.png" length="0" type="image/jpeg" />
</item>
<item>
<title>TypeScript 学习笔寄</title>
<link>https://lovemen.cc/moe2125.html</link>
<guid isPermaLink="false">https://lovemen.cc/moe2125.html</guid>
<pubDate>Fri, 10 Feb 2023 00:00:00 +0800</pubDate>
<dc:creator>橘纸柚</dc:creator>
<category><![CDATA[笔记]]></category>
<category><![CDATA[Typescript]]></category>
<category><![CDATA[TS]]></category>
<description><![CDATA[# 原始类型
TypeScript 拥有 JavaScript 的数据类型并且新增了更多类型
JavaScript 类型：number、string、boolean、null、undefined
TypeScript 类型：any、type、interfa...]]></description>
<content:encoded><![CDATA[
<!--markdown--># 原始类型
<p>TypeScript 拥有 JavaScript 的数据类型并且新增了更多类型
JavaScript 类型：<code>number</code>、<code>string</code>、<code>boolean</code>、<code>null</code>、<code>undefined</code>
TypeScript 类型：<code>any</code>、<code>type</code>、<code>interface</code> 等</p>
<h2>any 类型</h2>
<p><code>any</code> 是逃避 TypeScript 的类型检查，可以赋任何值，但是因此可能会导致 BUG 应该尽量避免使用
在已声明未赋值时就会自动推断为 <code>any</code></p>
<hr />
<h1>类型注解</h1>
<p>如 <code>let age:number = 18</code> 它的 <code>:number</code> 就是类型注解，它约定了这是什么类型的变量只能给它赋值这个类型，给它提供了约束让代码更清晰</p>
<hr />
<h1>数组类型</h1>
<p>TypeScript 中数组类型有两种写法 <code>类型[]</code> 与 <code>Array&lt;类型&gt;</code> 一般使用 <code>类型[]</code></p>
<pre><code class="language-TypeScript">// 使用 类型[]
let listA: number[] = [1,1,4,5]
// 使用 Array&lt;类型&gt;
let listB: Array&lt;string&gt; = ['您','您','您']</code></pre>
<hr />
<h1>联合类型</h1>
<p>定义一个可以接收多个类型的类型注释</p>
<pre><code class="language-TypeScript">// 对于数组
let nyaList: (number | string | boolean)[] = [114514, '您您您', true]
let neko: Array&lt;number | boolean&gt; = [191919, false]

// 对于简单数据类型
let timer: number | null = null

// 对于字面量
let gender: '男' | '女' | '非二元' = '非二元'</code></pre>
<hr />
<h1>类型别名和接口</h1>
<p>在同一类型多次使用并且写法复杂时使用</p>
<p>类型别名 <code>type</code> 支持所有的类型，而接口 <code>interface</code> 只支持对象类型
类型别名 <code>type</code> 不允许重复命名，而接口 <code>interface</code> 重复命名会合并
类型别名 <code>type</code> 不能重新打开（向内定义新的对象注解）接口 <code>interface</code> 可以通过两个相同命名合并实现</p>
<h2>类型别名</h2>
<p>类型别名，使用大驼峰命名，类似于变量，使用它和类型注释的写法一样 <code>type 别名 = 类型</code></p>
<pre><code class="language-TypeScript">// 数组类型别名
type CusArr = (number | string) []
let list: CusArr = [19, '您']

// 对象类型别名
type AddFnType = (num1: number, num2: number) =&gt; number
const addFn2 : AddFnType = (num1, num2) =&gt; {
  return num1 + num2
}</code></pre>
<h3>类型别名交叉</h3>
<p>当你一个新的类型别名 B 与一个类型别名 A 拥有相同的属性，可以使用类型别名交叉获取上个类型别名 A 的属性注解，实现的效果类似于 <code>interface</code> 的<code>extends</code></p>
<pre><code class="language-TypeScript">type Point2D = {
  x: number,
  y: number
}
// 从 Point2D 交叉
type Point3D = Point2D &amp; {
  z: number
}
const p: Point3D = {
  x: 100,
  y: 100,
  z: 100
}</code></pre>
<h2>接口</h2>
<p>接口和类型别名类似，也使用大驼峰命名，接口只能用于定义对象的类型注解，使用方法与类型别名相同，语法 <code>interface 名称 {}</code></p>
<pre><code class="language-TypeScript">interface Person {
  name: string,
  age: number,
  say: () =&gt; void
}
let p: Person = {
  name: 'PinocoP',
  age: 28,
  say() {
    console.log('nai');
  }
}</code></pre>
<h3>接口继承</h3>
<p>当你一个新的类型别名 B 与一个类型别名 A 拥有相同的属性，就可以使用 <code>extends</code> 进行接口继承，语法 <code>interface 名称</code>extends<code>需要继承的接口名称 {}</code></p>
<pre><code class="language-TypeScript">interface Person {
  name: string,
  age: number,
  say(): void
}
interface Stu extends Person {
  score: number
}
const nin: Stu = {
  name: 'JuziYou',
  age: 18,
  score: 69,
  say() {
    console.log('您');
  }
}</code></pre>
<hr />
<h1>函数类型</h1>
<h2>函数声明</h2>
<pre><code class="language-TypeScript">function 函数名(形参: 类型):返回值类型{
  ...
}</code></pre>
<h2>函数表达式</h2>
<pre><code>const 函数名 = (形参:类型):返回值类型 =&gt; {}</code></pre>
<h2>函数返回值</h2>
<p>如果函数没有返回值就是空 <code>void</code> ，<code>void</code> 类名注解可以省略
在 JavaScript 中如果没有 <code>return</code> 返回值是 <code>undefined</code> 而在 TypeScript 中 <code>void</code> 和 <code>undefined</code> 并不相同，如果在返回值类型定义了 <code>undefined</code> 那么就必须 <code>return undefined</code></p>
<h2>可选参数</h2>
<p>一个形参在可以传也可以不传的时候那就可以设置可选参数，在类型注释 ':' 前添加一个 '?' 即可，不传的情况下它的值是 <code>undefined</code>，可选参数不可以设置初始值，必传参数不能写在可选参数之后</p>
<pre><code class="language-TypeScript">// 函数声明
function 函数名(形参?: 类型, 形参:类型):返回值类型{
  ...
}

// 函数表达式
const 函数名 = (形参?:类型, 形参:类型):返回值类型 =&gt; {}</code></pre>
<hr />
<h1>对象类型</h1>
<p>对象类型有空对象和有属性的对象以及有属性和方法的对象（废话）
定义属性注解和可选属性和之前的那些方法差不多
对象类型在多个属性注解之间可以使用 <code>,</code> 也可以使用 <code>;</code> 甚至可以直接换行</p>
<pre><code class="language-TypeScript">// 空对象
let person1 = {} = {}

// 有 属性 的对象
let person2: { name: string} = {
  name: 'juziyou'
}

// 有属性有方法的对象
let person3: { name: string, say(): void} = {
  name: 'JuziYou',
  say(){}
}
// 在多个对象属性间可以用 `,` 也可以用 `;` 甚至可以直接换行
let person4: {
  name: string;
  age: number
} = {
  name: 'JuziYou',
  age: 18
}
let person5: {
  name: string
  age: number
} = {
  name: 'JuziYou',
  age: 18
}

// 给箭头函数定义
let person6: {
  name: string,
  say: () =&gt; void
} = {
  name: 'JuziYou',
  say: () =&gt; console.log('喵')

}

// 接收一个多属性可选
// 列如 axios 的 config 中接收 url 和 method 其 method 可选
const axios = (config: {url: string, method?:string}) =&gt; {}

// 使用类型别名
type Config = (config: {url: string, method?:string}) =&gt; {}
const axios2 = (config: Config) =&gt; {}</code></pre>
<hr />
<h1>类型推断</h1>
<p>在 TypeScript 中存在类型推断机制，在没有指定类型的情况下会自动推断类型</p>
<pre><code class="language-TypeScript">// let num: number
let num = 114514

// fn(num1: number, num2:number): number
function fn(num1: number, num2:number) {
  return num1 + num2
}</code></pre>
<hr />
<h1>字面量</h1>
<p>在 TypeScript 中 <code>let</code> 了一个字面量相当于 <code>const</code>了一个常量如 <code>let nya: 'JuziYou' = 'JuziYou'</code> 那么它就只能赋值为 <code>'JuziYou'</code>，<code>let</code> 的自动推断是赋予值的数据类型、<code>const</code> 的自动推断是赋予的值</p>
<pre><code class="language-TypeScript">// let neko: string
let neko = 'JuziYou'

// const nya: 'JuziYou'
const nya = 'JuziYou'</code></pre>
<hr />
<h1>断言</h1>
<p>当明确的知道数据类型就可以使用断言，<code>as</code> 断言它跟的类型是一个更加具体的类型</p>
<pre><code class="language-TypeScript">// 假设此时 #nya 是一个 &lt;a&gt; 标签
const link = document.getElementById('nya') as HTMLAnchorElement</code></pre>
<h2>非空断言</h2>
<p>在 <code>.</code> 前面加 <code>!</code> 来添加非空断言，告诉他一定有某个属性，比如 <code>nya!.neko</code> 就是告诉 TypeScript 在 <code>nya</code> 下一定有 <code>neko</code></p>
<hr />
<h1>泛型</h1>
<p>泛型是定义不确定是什么类型，使用的时候才知道，提高服用性和灵活性，一般使用大驼峰命名</p>
<h2>泛型别名</h2>
<p>在定义的别名后加上 <code>&lt;泛型参数&gt;</code>就是接收泛型，然后在下面的类型注解使用 <code>泛型参数</code>，然后在使用时在类型注解的类型别名后加上 <code>&lt;类型参数&gt;</code> 即可使用</p>
<pre><code class="language-TypeScript">type User = {
  name: string,
  age: number
}

type Goods = {
  id: number,
  name: string
}

type Data&lt;Type&gt; = {
  message: string,
  code: number,
  data: Type
}

// 假设是请求到用户信息
let user: Data&lt;User&gt; = {
  message: 'Okay',
  code: 200,
  data: {
    name: 'Mikan',
    age: 18
  }
}

// 假设是请求到商品信息
let goods: Data&lt;Goods&gt; = {
  message: 'Okay',
  code: 200,
  data: {
    name: '大猫猫抓板',
    id: 0
  }
}</code></pre>
<h2>泛型接口</h2>
<p>在定义的接口名后加上 <code>&lt;泛型参数&gt;</code>就是接收泛型，然后在下面的类型注解使用 <code>泛型参数</code>，然后在使用时在类型注解的接口名后加上 <code>&lt;类型参数&gt;</code> 即可使用</p>
<pre><code class="language-TypeScript">interface IDs&lt;Type&gt; {
  id: ()=&gt; Type,
  ids: ()=&gt; Type[]
}

// 假设获取一个 ID 列表
const idList: IDs&lt;number&gt; = {
  id(){
    return 114514
  },
  ids(){
    return [19,1919,191919]
  }
}</code></pre>
<h2>泛型函数</h2>
<p>在定义的函数名后加上<code>&lt;泛型参数&gt;</code>就是接收泛型，然后可以使用 <code>泛型参数</code> 在形参和返回值的类型注释中</p>
<pre><code class="language-TypeScript">function newToken&lt;Type&gt;(token: Type): Type{
  return token
}
let token: number = 191919
token = newToken&lt;number&gt;(114514)</code></pre>
<h2>泛型约束</h2>
<p>利用了接口 <code>interface</code> 的 <code>extends</code> 接口的继承原理，来约束传入的类型</p>
<p>例如必须有 <code>length</code></p>
<pre><code class="language-TypeScript">function getId&lt;T extends {length: number}&gt; (id:T):T {}</code></pre>
<hr />
<h1>自定义类型声明</h1>
<p>如果多个 <code>.ts</code> 文件都要用到同个类型，这时就可以创建 <code>.d.ts</code> 来共享该类型</p>
<h2>全局</h2>
<p>直接在 <code>.d.ts</code> 中不使用 <code>export</code> 按需暴露的将会生成全局自定义类型
如：在 <code>index.d.ts</code> 中</p>
<pre><code>interface Goods {
  name: string,
  price: number,
  brand: string
}</code></pre>
<h2>局部引入</h2>
<p>TypeScript 类型也可以使用 <code>import</code> 和 <code>export</code> 来实现按需导入和导出功能，只需要再使用该 <code>.d.ts</code> 的 <code>.ts</code> 文件中 <code>import</code> 导入即可使用</p>
<pre><code>export interface Goods {
  name: string,
  price: number,
  brand: string
}</code></pre>
<pre><code>import {Goods} from './ts/index'
}
const goods:Goods = {
  name: '猫猫猫抓板',
  price: 114514,
  brand: '猫猫'
}</code></pre>
<h2>给 JS 提供类型</h2>
<p>在导入 <code>.js</code> 文件时，TypeScript 会自动加载与 <code>.js</code> 同名的 <code>.d.ts</code> 文件，提供类型声明
<code>declare</code> 用于类型声明，为其他地方(比如，.js 文件)已存在的变量声明类型，而不是创建一个新的变量，在 <code>interface</code> 和 <code>type</code> 时不用加 <code>declare</code></p>
<p>/util/index.d.ts</p>
<pre><code>export declare const sum : (numA: number, numB:number) =&gt; number

interface Student {
  name: string,
  score: number
}

export declare const say: (stu: Student) =&gt; void</code></pre>
<p>/util/index.js</p>
<pre><code>export const sum = (numA, numB) =&gt; numA + numB
export const say = (stu) =&gt; console.log(stu.name, stu.score);</code></pre>
<p>index:</p>
<pre><code>import { sum, say } from './util'
sum(1,2)
say({name: 'Nya', score: 66})</code></pre>
<hr />
<h1>在 Vue 组合式 API 中使用</h1>
<p><a href="https://cn.vuejs.org/guide/typescript/composition-api.html">Vue官方文档</a></p>
<h2>Props</h2>
<h3>基本使用</h3>
<p>使用 <code>defineProps&lt;泛型&gt;()</code> 来来定义接收的数据类型</p>
<p><strong>示例:</strong></p>
<pre><code>const props = defineProps&lt;{money: number}&gt;()</code></pre>
<h3>定义默认值</h3>
<p>如果定义默认值需要使用 <code>withDefaults</code> 它第一个值接收一个函数写<code>defineProps</code>，第二个值写一个对象里面写接收的默认值</p>
<p><strong>示例：</strong></p>
<pre><code>// const props = withDefaults(defineProps&lt; 泛型 &gt;(), {
//   接收值: 默认值
// })

const props = withDefaults(defineProps&lt;{age: number, uname?: string}&gt;(), {
uname: 'JuziYou'
})</code></pre>
<h3>语法糖 ⚗️</h3>
<p><code>withDefaults</code> 看起来比较复杂，所以可以使用响应式语法糖，目前还是实验性功能所以需要<a href="https://cn.vuejs.org/guide/extras/reactivity-transform.html#explicit-opt-in">显式启用</a>它，然后通过 <code>const {接收值} = defineProps&lt;泛型&gt;()</code> 使用</p>
<p><strong>示例：</strong></p>
<pre><code>const {age, uname = 'JuziYou'} = defineProps&lt;{
  age: number,
  uname?: string
}&gt;()</code></pre>
<h2>Emit</h2>
<p>不知道怎么解释就直接写上算了（摆)</p>
<p>子组件：
<code>event</code> 和 <code>payload</code> 是自己定义的参数名 <code>event</code> 是触发事件的自定义事件名 <code>payload</code> 是传参</p>
<pre><code>const emit = defineEmits&lt;{
  (event: 'changeNya', payload:number):void
}&gt;()</code></pre>
<p>父组件：</p>
<pre><code>const changeNyaFn = (nya: number) =&gt; {
  console.log('Nya', nya);
}</code></pre>
<h2>ref</h2>
<p>通过 <code>ref&lt;泛型&gt;(需要响应式的数据)</code> 定义 ref</p>
<h2>简单数据类型</h2>
<p>定义简单数据类型 <code>ref&lt;泛型&gt;(需要响应式的数据)</code> 定义 ref</p>
<p><strong>示例：</strong></p>
<pre><code>const uname = ref&lt;string&gt;('JuziYou')</code></pre>
<h3>自动推导</h3>
<p>一般情况下 TypeScript 会自动推导它的数据类型所以可以 <code>ref(需要响应式的数据)</code> 这样写</p>
<p><strong>示例：</strong></p>
<pre><code>// const uname: Ref&lt;string&gt;
const uname = ref('JuziYou')</code></pre>
<h3>复杂数据类型</h3>
<p>如一个泛型为 Person 类型的数组</p>
<pre><code>type Person = {
  id: number,
  uname: string,
  address: string
}
const personList = ref&lt;Person[]&gt;([])
personList.value.push({
  id: 1,
  uname: 'JuziYou',
  address: 'Nya'
})</code></pre>
<h2>reactive</h2>
<p>使用 <code>reactive</code> 时推荐直接给变量指定类型</p>
<pre><code>type Car = {
  brand: string,
  price: number,
  color?: string
}

const car:Car = reactive({
  brand: '橘子',
  price: 114514
})
car.color = "橘色"</code></pre>
<h2>computed</h2>
<p><code>computed</code> 一般会自动推导数据类型，也可以使用泛型指定
自动推导：</p>
<pre><code>const nyaNum = ref(18)
// computed&lt;number&gt;
const nyaCount = computed(()=&gt; nyaNum.value ** 2)</code></pre>
<p>泛型指定：</p>
<pre><code>const nyaNum = ref(18)
const nyaCount = computed&lt;number&gt;(()=&gt; nyaNum.value ** 2)</code></pre>
<h2>事件</h2>
<p>事件对象使用 <code>Event</code> 类型注释，通过类型断言来解决可能是个 <code>null</code> 的问题
如：获取 <code>&lt;input type="text" @change="changFn"&gt;</code> 的 value</p>
<pre><code>const changFn = (event: Event) =&gt; {
  // 使用类型断言，断言 even.target 是一个 input
  console.log((event.target as HTMLInputElement).value)

}</code></pre>
<h2>ref 获取 DOM</h2>
<p><code>const ref的值 = ref&lt;类型 | null&gt;(null)</code> 来获取对应的 DOM
如：获取 <code>ipt</code> 再载入后默认聚焦</p>
<pre><code>&lt;script setup lang="ts"&gt;
const ipt = ref&lt;HTMLInputElement | null&gt;(null)
onMounted(()=&gt;{
  ipt.value?.focus()
})
&lt;/script&gt;

&lt;template&gt;
  &lt;input type="text" ref="ipt" value="Nya"&gt;
&lt;/template&gt;</code></pre>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://lovemen.cc/moe2125.html#comments</comments>
</item>
<item>
<title>Vue 学习笔寄</title>
<link>https://lovemen.cc/moe2078.html</link>
<guid isPermaLink="false">https://lovemen.cc/moe2078.html</guid>
<pubDate>Sun, 30 Oct 2022 15:16:00 +0800</pubDate>
<dc:creator>橘纸柚</dc:creator>
<category><![CDATA[笔记]]></category>
<category><![CDATA[JavaScript]]></category>
<category><![CDATA[Vue]]></category>
<description><![CDATA[# 基础内容
通过 data()提供数据
vue 中可以在 export default{}里通过 data()提供数据，data必须是一个函数，return一个对象
export default {
  data () {
    return {
  ...]]></description>
<content:encoded><![CDATA[
<!--markdown--># 基础内容
<h2>通过 <code>data()</code>提供数据</h2>
<p>vue 中可以在 <code>export default{}</code>里通过 <code>data()</code>提供数据，<code>data</code>必须是一个函数，<code>return</code>一个对象</p>
<pre><code class="language-JavaScript">export default {
  data () {
    return {
      uname: 'JuziYou',
      age: 18
    }
  }  
}</code></pre>
<hr />
<h2>使用插值表达式显示数据</h2>
<p>插值表达式使用两对大括号包裹，使用的数据需要在 <code>data()</code>、<code>methods</code>、<code>computed</code>等地方存在，可以使用表达式，但是不能使用在标签属性</p>
<pre><code class="language-JavaScript">{{ uname }}
{{ obj.uname }}
{{ obj.age &gt; 18 ? '成年' : '未成年' }}</code></pre>
<hr />
<h2><code>v-bind</code></h2>
<p>插值表达式不能使用在标签属性，需要使用 <code>v-bind</code>需要设置动态 html 属性上，简写为 <code>:</code></p>
<p>举例：</p>
<p>[tabs]
[tab name="简写"]</p>
<pre><code class="language-html">&lt;a :href="url"&gt;戳戳&lt;/a&gt;</code></pre>
<p>[/tab]
[tab name="完整"]</p>
<pre><code class="language-html">&lt;a v-bind:href="url"&gt;戳戳&lt;/a&gt;</code></pre>
<p>[/tab]</p>
<p>[/tabs]</p>
<hr />
<h2><code>v-on</code></h2>
<p><code>v-on</code>语法为 <code>v-on:事件名='需要执行的代码/函数名/函数名(实参)'</code>需要在 <code>methods</code>中提供事件处理函数，简写 <code>@</code></p>
<p>举例：</p>
<p>[tabs]
[tab name="简写"]</p>
<pre><code class="language-html">&lt;button @click='num = bum + 1'&gt;Click&lt;/button&gt;
&lt;button @click='functionA'&gt;Click&lt;/button&gt;
&lt;button @click='functionB('JuziYou')'&gt;Click&lt;/button&gt;</code></pre>
<p>[/tab]
[tab name="完整"]</p>
<pre><code class="language-html">&lt;button v-on:click='num = bum + 1'&gt;Click&lt;/button&gt;
&lt;button v-on:click='functionA'&gt;Click&lt;/button&gt;
&lt;button v-on:click='functionB('JuziYou')'&gt;Click&lt;/button&gt;</code></pre>
<p>[/tab]</p>
<p>[/tabs]</p>
<h2>事件修饰符</h2>
<p><code>.prevent</code>阻止默认行为
<code>.stop</code>阻止冒泡
<code>.once</code>程序运行期间只触发一次事件处理函数
<code>.native</code>在组件上调用事件</p>
<hr />
<h2><code>v-model</code></h2>
<p><code>v-model</code>是一个语法糖 <code>@input</code>和 <code>:value</code>组合到了一起，它吧属性和数据双向绑定到一起。双向绑定即数据变化视图同步变化，视图变化数据同步变化。
Vue3 中 <code>v-model</code> 是 <code>:modelValue</code> 和 <code>@update:modelValue</code> 的组合，<a href="https://cn.vuejs.org/guide/components/v-model.html">Vue3官方文档</a></p>
<p>语法：<code>v-model="数据变量"</code></p>
<pre><code class="language-HTML">&lt;button v-model="数据变量"&gt; 戳戳 &lt;/button&gt;</code></pre>
<p>在父子组件通信时，如果 <code>:value</code>传参给子组件 <code>$emit('input', 值)</code>可以使用 <code>v-model</code>代替</p>
<h3><code>v-model</code> 修饰符</h3>
<p><code>.number</code>和 <code>.parseFloat</code>转换为数字类型
<code>.trim</code>去除首尾空白（空格）
<code>.lazy</code>使用 <code>change</code>事件改变数据（默认为 <code>imput</code>事件改变数据）</p>
<hr />
<h2><code>v-text</code>和 <code>v-html</code></h2>
<p><code>v-text</code>和 <code>v-html</code>会更新 DOM 对象的 innerText 或者 innerHTML，并且会覆盖差值表达式 <code>v-text</code>不会识别 HTML 标签，<code>v-html</code>会识别 HTML 标签</p>
<p>语法：</p>
<pre><code class="language-HTML">&lt;p v-text="数据变量"&gt;&lt;/p&gt;
&lt;p v-html="数据变量"&gt;&lt;/p&gt;</code></pre>
<hr />
<h2><code>v-show</code>和 <code>v-if</code>及 <code>v-else</code></h2>
<p><code>v-show</code>和 <code>v-if</code>控制标签的显示或隐藏，<code>true</code>或 <code>false</code>
<code>v-show</code>使用 CSS 的 <code>display:none</code>来隐藏
<code>v-if</code>将会直接从 DOM 树上移除
频繁切换显示的情况下使用 <code>v-show</code>因为使用 <code>display:none</code>来切换显示隐藏不会频繁创建元素节省性能，<code>v-if</code>是惰性的在 <code>false</code>时不会创建元素节省初期渲染开销</p>
<p>语法：</p>
<pre><code class="language-HTML">&lt;p v-show="true"&gt;&lt;/p&gt;
&lt;p v-if="false"&gt;&lt;/p&gt;</code></pre>
<p><code>v-if</code>与 <code>v-else</code>和 <code>v-else-if</code>同时使用，方便通过变量控制一套标签出现或者隐藏</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h1 v-if="yukari&gt;= 60"&gt;紫老ffhfhewufuiefefrwgfuktyr&lt;/h1&gt;
    &lt;h1 v-else-if="yukari&gt;= 30"&gt;紫妈&lt;/h1&gt;
    &lt;h1 v-else&gt;紫&lt;/h1&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
    return {
      yukari: 16
    }
  }
}
&lt;/script&gt;</code></pre>
<hr />
<h2><code>v-for</code></h2>
<p><code>v-for</code> 常用于列表渲染，按照数据循环生成，可以遍历数组、对象、数字、可遍历解构的字符串
每一项唯一标识符作为 <code>:key="索引"</code>，可以最大限度的复用你的 DOM，<code>:key="索引"</code>的索引只能是数字或者字符串</p>
<p>语法：
<code>v-for="(值, 索引) in 目标" :key="索引"</code>
<code>v-for="值 in 目标" :key="值下的可用于索引的值"</code></p>
<p>[tabs]
[tab name="数组"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;ul&gt;
      &lt;li v-for="(item,index) in list" :key="index"&gt;
        {{ item }} &gt; {{ index }}
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
    return {
      list:['JuziYou','MikanpaperYuzu','橘纸柚']
    }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]</p>
<p>[tab name="对象"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;ul&gt;
      &lt;li v-for="(value, key) in preson" :key="key"&gt;
        {{ value }} · {{ key }}
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
    return {
      preson:{
        uname: '八云紫',
        skill: '操纵界线的能力',
        age: 18
      }
    }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="数组里的对象"]</p>
<pre><code class="language-HTML">&lt;template&gt;

&lt;div&gt;
    &lt;ul&gt;
      &lt;li v-for="(item,index) in personList" :key="index"&gt;
        &gt;&gt;&gt;{{item.uname}}
        &lt;p&gt;{{item.skill}}&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
    return {
      personList:[
        {uname:'博丽灵梦',home:'博丽神社'},
        {uname:'琪露诺',home:'雾之胡'},
        {uname:'蕾米莉亚',home:'红魔馆'},
        {uname:'帕秋莉',home:'红魔馆'}
      ]
    }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="数字（了解）"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;ul&gt;
      &lt;li v-for="(item,i) in 5" :key="i"&gt;
        {{item}} · {{i}}
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<hr />
<h2>数组的数据更新监测</h2>
<p>数组方法中能引起页面更新的方法有：
<code>push</code>、<code>pop</code>、<code>shift</code>、<code>unshift</code>、<code>splice</code>、<code>sort</code>、<code>reverse</code>
其他无法引起页面更新的方法可以通过赋值来完成更新
通过下标来更新值不会触发页面更新需要使用 <code>$set</code>来更新数组
语法：<code>this.$ste(要改变的对象, 要改变的位置, 要改变的值)</code></p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;ul&gt;
      &lt;li v-for="(item,index) in list" :key="index"&gt;{{item}}&lt;/li&gt;
    &lt;/ul&gt;
    &lt;button @click="changeFn"&gt;changeFn&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data() {
    return {
      list: ['博丽灵梦', '琪露诺', '八云紫']
    }
  },
  methods: 
    changeFn(){
      this.$set(this.list, 1, "魔理沙")
    }
  }
}
&lt;/script&gt;</code></pre>
<hr />
<h2>动态绑定 <code>class</code></h2>
<p>使用 <code>v-bind:class</code>设置动态属性一般使用简写 <code>:class</code>允许使用对象或者数组
<code>:class</code>不会影响到原有的 class 属性
使用对象动态绑定 <code>:class="{类名:布尔值}"</code>如果布尔值为 <code>true</code>就有这个类名,<code>false</code>则没有
使用数组动态绑定 <code>:class="数组"</code>标签会有数组里面的所有类名</p>
<p>[tabs]
[tab name="直接绑定"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;div :class="str"&gt;Nya&lt;/div&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
    return {
      str: 'green'
    }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="三元表达式"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;div :class="isRed ? 'red' : ''"&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
    return {
      isRed: true
    }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="对象"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;div :class="{yukari: isRed, suka: !isRed}"&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
    return {
      isRed: true
    }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="数组"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;div :class="arr"&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
    return {
      arr: ['show', 'mask', 'red', 'paper']
    }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]</p>
<p>[/tabs]</p>
<hr />
<h2>动态绑定 <code>style</code></h2>
<p>使用 <code>v-bind:style</code>设置动态属性一般使用简写 <code>:style</code>
语法 <code>:style="{样式名:样式值}"</code>样式名为 CSS 属性的驼峰命名法</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h1 :style="{ fontSize: '50px', color: fontColor}"&gt;黄色的&lt;/h1&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
    return{
      fontColor: 'yellow'
    }
  }
}
&lt;/script&gt;</code></pre>
<hr />
<h2><code>computed</code>计算属性</h2>
<p>计算属性必须在 <code>computed</code>节点中，多用于多个数据影响一个数据的场景，根据现有的数据区计算出新的数据并且有缓存，在数据不发生变化的情况下只会执行一次，数据有变化时会重新计算并缓存，写法是一个函数，一定需要返回值是最终值</p>
<p>示例翻转字符串：</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h1&gt;{{reverseStr}}&lt;/h1&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
    return{
      uname: 'MikanpaperYuzu'
    }
  },
  computed: {
    reverseStr(){
      return this.uname.split('').reverse().join('')
    }
  }
}
&lt;/script&gt;</code></pre>
<p>计算属性默认情况下只能获取不能修改，如果需要修改需要用到完整写法</p>
<p>完整写法示例：</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h1&gt;计算属性的完整写法&lt;/h1&gt;
    &lt;h1&gt;{{fullName}}&lt;/h1&gt;
    &lt;button @click="clickFn"&gt;点我&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
    return{
      firstName:'Juzi',
      lastName:'You'
    }
  },
  computed: {
    fullName: {
      get(){
        return this.firstName + '-' + this.lastName
      },
      set(val){
        this.firstName = val.split('-')[0]
        this.lastName = val.split('-')[1]
      }
    }
  },
  methods: {
    clickFn(){
      this.fullName = 'MikanPaper-Yuzu'
    }
  }
}
&lt;/script&gt;</code></pre>
<hr />
<h2><code>watch</code>属性监听</h2>
<p>属性监听必须写在 <code>watch</code>节点中，只要监听的属性值发生了变化就会执行，多用于一个属性影响多个属性的场景，没有缓存但是可以异步，简单写法无法监听复杂类型的写法，需要使用完整写法监听复杂数据类型</p>
<p>[tabs]
[tab name="简单写法"]</p>
<pre><code class="language-JavaScript">watch: {
  监听的属性 (变化后的值, 变化前的值) {
  }
}</code></pre>
<p>示例：</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h2&gt;{{ uname }}&lt;/h2&gt;
    &lt;button @click="uname = 'MikanpaperYuzu'"&gt;给我变&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
    return{
      uname: 'JuziYou'
    }
  },
  watch:{
    uname(newVal, oldVal){
      console.log('魔法少女 ' + oldVal + ' 变 ' + newVal);
    }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="完整写法"]
动态属性是一个对象的形式
<code>immediate: true</code>代表一进入页面立即执行
<code>deep: true</code>代表升读监听可以监听到复杂数据类型内部的变化
<code>handler(){}</code>每次变化时触发的函数</p>
<pre><code>watch: {
  接听的属性:{
    immediate: true, //代表一进入页面立即执行
    deep: true,      // 代表升读监听可以监听到复杂数据类型内部的变化
    handler(){       // handler 是每次变化时触发的函数
    }
  }
}</code></pre>
<p>示例：</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h2&gt;{{ obj.uname }}&lt;/h2&gt;
    &lt;button @click="mya"&gt;给我变&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
    return{
      obj: {
        uname : 'JuziYou'
      }
    }
  },
  watch: {
    obj:{
      immediate: true,
      deep: true,
      handler(){
        console.log("变了喵");
      }
    }
  },
  methods: {
    mya(){
      this.obj.uname = "MikanpaperYuzu"
    }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<hr />
<h1>组件基础</h1>
<h2>引入组件</h2>
<p>组件分为全局引入和局部引入，一般使用大驼峰命名法，除了驼峰, 如果使用小写还可以使用 <code>-</code>转换链接不同的单词，如一个注册组件名为 <code>&lt;JuziYou /&gt;</code>可以直接使用转换连接 <code>&lt;juzi-you /&gt;</code>也能解析到父组件。如果标签没有内容可以直接使用自结束标签</p>
<h3>局部引入</h3>
<p>局部引入将组件注册在当前 Vue 文件，只可以用在这个 Vue 文件中。
使用 <code>import 组件对象 from 'Vue文件路径'</code>引入组件
然后 <code>components: { 组件名: 组件对象 }</code>注册组件
示例：
[tabs]
[tab name="App.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div id="app"&gt;
    &lt;Pannel /&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import PannelLoc from './components/Pannel.vue'
export default {
  components: { Pannel: PannelLoc }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="components/Pannel.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h1&gt;Nya&lt;/h1&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<h3>全局引入</h3>
<p>全局引入在 <code>main.js</code>引入组件并使用，注册在全局整个项目中都可以使用
使用 <code>import 组件对象 from 'Vue文件路径'</code>引入组件
然后 <code>Vue.component("组件名", 组件对象)</code>注册组件</p>
<p>示例：
[tabs]
[tab name="main.js"]</p>
<pre><code class="language-JavaScript">import Vue from 'vue'
import App from './App.vue'

// 引入组件
import Pannel from "./components/Pannel";
// 全局注册
Vue.component('PannelGol', Pannel)

Vue.config.productionTip = false

new Vue({
  render: h =&gt; h(App),
}).$mount('#app')</code></pre>
<p>[/tab]
[tab name="components/Pannel.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h1&gt;Nya&lt;/h1&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<p>[/tab]
[tab name="App.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;PannelGol&gt;&lt;/PannelGol&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<hr />
<h2>组件样式 <code>scoped</code></h2>
<p>吧样式只应用于当前组件，给组件的 <code>&lt;style&gt;</code>加上 <code>scoped</code>会给这个组件的所有元素添加自定义属性，以及当前组件的 CSS 添加交集选择器，只有这个自定义属性的标签才能被样式选中</p>
<p>示例：
[tabs]
[tab name="App.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h1&gt;MikanpaperYuzu&lt;/h1&gt;
    &lt;ChildOne /&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import ChildOne from './components/ChildOne.vue'
export default {
  components: {
    ChildOne
  }
}
&lt;/script&gt;

&lt;style&gt;

&lt;/style&gt;</code></pre>
<p>[/tab]
[tab name="components/ChildOne.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h1&gt;JuziYou&lt;/h1&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {

}
&lt;/script&gt;
&lt;style scoped&gt;
h1{
  color: orange
}
&lt;/style&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<hr />
<h2>组件 <code>name</code>属性</h2>
<p>一般使用一些框架会用到，以保证框架的命名风格所以懒得写太清楚（（（
示例：</p>
<p>[tabs]
[tab name="App.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;JuziYou /&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import ChildCom from './components/ChildCom.vue'
export default {
  components:{
    [ChildCom.name]: ChildCom
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="components/ChildCom.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;p&gt;JuziYou&lt;/p&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  name:'JuziYou'
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<hr />
<h2>父向子通讯</h2>
<p>在父组件的子组件标签上添加自定义属性，然后在子组件使用 <code>props</code>接收
注: 子组件不能修改父组件传来的 <code>props</code></p>
<p>示例：</p>
<p>[tabs]
[tab name="App.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;MyProduct title="勾勾果" price="200" intro="蒙德产勾勾果" /&gt;
    &lt;MyProduct title="甜甜花" price="100" intro="蒙德产甜甜花" /&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
// 定义局部变量
import MyProduct from './components/MyProduct.vue'
export default {
  components: {
    MyProduct,
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="components/MyProduct.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h3&gt;标题: {{ title }}&lt;/h3&gt;
    &lt;p&gt;价格: {{ price }}元&lt;/p&gt;
    &lt;p&gt;{{ intro }}&lt;/p&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default
  props: ['title','price','intro']
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<hr />
<h2>子向父通讯</h2>
<p>在父组件的标签上设置自定义事件组件 <code>@事件名="方法名"</code>，然后在子组件中使用 <code>this.$emit(事件名, 传给父元素的值)</code>触发自定义事件，<code>$emit</code>第二个值之后为返回给父元素的值，在父亲元素接收的方法中对应形参</p>
<p>示例：
[tabs]
[tab name="App.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;MyProduct
        :title="list.title"
        :price="list.price"
        :intro="list.intro"
        @upMora="upFn"
    /&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
// 定义局部变量
import MyProduct from './components/MyProduct.vue'
export default {
  components: {
    MyProduct,
  }
  data() {
    return {
      list:{
        title: '勾勾果'
        price: '200'
        intro: '蒙德产勾勾果'
      }
    }
  },
  methods: {
    upFn(num){
      this.list.price = num
    }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="components/MyProduct.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h3&gt;标题: {{ title }}&lt;/h3&gt;
    &lt;p&gt;价格: {{ price }}元&lt;/p&gt;
    &lt;p&gt;{{ intro }}&lt;/p&gt;
    &lt;button @click="$emit('upMora', 1000)"&gt;价格改为1000元&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default
  props: ['title','price','intro']
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<h3><code>props</code>校验</h3>
<p>校验父模块向子模块传来的数据是否符合需求</p>
<p>[tabs]
[tab name="Key:Value"]
<code>key</code>是接收值名称，<code>value</code>是接收的类型</p>
<pre><code class="language-JavaScript">export default {
    props:{
        user:String
    }
}</code></pre>
<p>[/tab]
[tab name="Key:数组"]
如果需要多个类型，key 是接收者名称，<code>value</code>设置为接收的类型数组</p>
<pre><code class="language-JavaScript">export default {
    props:{
        age: [String, Number]
    }
}</code></pre>
<p>[/tab]
[tab name="必传参数"]
如果设置为必传参数将使用完整写法写为对象的形式，<code>type</code>表示接收的类型，<code>required: true</code>来打开必传</p>
<pre><code class="language-JavaScript">export default {
    props:{
        gender:{
          type: String,
          required: true
        }
    }
}</code></pre>
<p>[/tab]
[tab name="默认值"]
如果设置默认值将使用完整写法写为对象的形式，<code>type</code>表示接收的类型，<code>default: 值</code>来设置默认值</p>
<pre><code>export default {
    props:{
        salary:{
          type: String,
          default: 'JuziYou'
        }
    }
}</code></pre>
<p>[/tab]
[tab name="自定义校验规则"]
如果设置自定义校验规则将使用完整写法写为对象的形式，<code>type</code>表示接收的类型，使用 <code>validator(传过来的值){}</code>它 <code>return</code>出来的值 <code>true</code>和 <code>false</code>来校验通过或不通过，如果 <code>return</code>了 <code>false</code>将会在控制台打印错误</p>
<pre><code class="language-JavaScript">export default {
    props:{
        // 检测传入 list 是否 length 大于 3
        list: {
          type: Array,
          validator(val){
            if(val.length &gt;= 3){
              return true
            }
            return false
          }
        }
    }
}</code></pre>
<p>[/tab]
[/tabs]</p>
<h3><code>.sync</code>修饰符</h3>
<p>可以让繁琐的父子通讯变得简单在使用<code>.sync</code>修饰符后在子组价使用 update:自定义变量 来更改父组件变量绑定的值就可以完成父子组件的通讯，相当于在父组件的标签上添加了<code>@update:属性名=" 变量名 = $event"</code>，<code>$event</code> 是默认参数</p>
<p>[tabs]
[tab name="App.vue"]</p>
<pre><code class="language-JavaScript">&lt;template&gt;
  &lt;div&gt;
    &lt;SyncUpdate :text.sync="name"/&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import SyncUpdate from '@/components/sync-update.vue'
export default {
  components:{
    SyncUpdate
  },
  data () {
    return {
      name: 'Mikanpapre'
    }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="components/ChildB.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;div&gt;{{ text }}&lt;/div&gt;
    &lt;!-- 使用 update:自定义变量 来更改父组件变量绑定的值 --&gt;
    &lt;button @click="$emit('update:text', 'Nya')"&gt;戳戳&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  props: ['text']
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<h3><code>$parent</code></h3>
<p><code>$parent</code>可以在子组件获取到父组件的实例</p>
<hr />
<h2>事件总线 <code>EventBus</code></h2>
<p>如果两个子组件通过父组件进行通讯会非常复杂，通过一个空的 Vue 对象当作事件总线常用于跨组件通讯的通用方案，在组件 A 使用 <code>EventBus.$emit('事件名', 值)</code>触发事件，在组件 B 使用 <code>EventBus.$on('事件名', 函数体)</code>监听事件</p>
<p>[tabs]
[tab name="EventBus/index.js"]</p>
<p>使用 <code>import Vue from 'vue'</code>引入 Vue
使用 <code>export default new Vue()</code>对外暴露一个 Vue 实例</p>
<pre><code class="language-JavaScript">import Vue from 'vue'
export default new Vue()</code></pre>
<p>[/tab]
[tab name="components/ChildA.vue"]
组件 A 触发事件</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;div&gt;我是A
  &lt;button @click='clickfn'&gt;戳&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import EventBus from '../EventBus'
export default {
  methods:{
    clickfn(){
      EventBus.$emit('mikan')
    }
  } 
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="components/ChildB.vue"]
组件 B 监听事件，<code>created()</code>在事件创建时就执行</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;div&gt;我是B&lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import EventBus from '../EventBus'
export default {
    created(){
      EventBus.$on('mikan', ()=&gt;{
        console.log('喵');
      })
    }

}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="App.vue"]
在 <code>APP.vue</code>导入两个组件并使用</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h1&gt;EventBus&lt;/h1&gt;
    &lt;ChildA/&gt;
    &lt;ChildB/&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import ChildA from './components/ChildA.vue'
import ChildB from './components/ChildB.vue'
export default {
  components: {
    ChildA,
    ChildB
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<hr />
<h1><code>ref</code>和 <code>$refs</code></h1>
<p><code>ref</code>和 <code>$refs</code>通常用于获取元素 DOM 或组件示例，将会挂载到 <code>$refs</code>的组件对象内</p>
<h2>获取 DOM</h2>
<p>在需要获取的 DOM 元素上 <code>ref="值"</code>然后在 <code>$refs.值</code>使用</p>
<pre><code>&lt;template&gt;
  &lt;div&gt;
    &lt;div ref="juziyou"&gt;JuziYou&lt;/div&gt;
    &lt;button @click="clickFn"&gt;Click&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  methods:{
    clickFn(){
      console.log(this.$refs.juziyou)
    }
  }
}
&lt;/script&gt;</code></pre>
<h2>获取组件实例</h2>
<p>在需要获取的组件自定义标签上 <code>ref="值"</code>然后在 <code>$refs.值</code>使用</p>
<p>[tabs]
[tab name="App.vue"]</p>
<pre><code>&lt;template&gt;
  &lt;div&gt;
    &lt;ChildB ref="childRef"/&gt;
    &lt;button @click="childRefFn"&gt;Click&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import ChildB from './components/ChildB.vue'
export default {
  components:{
    ChildB
  },
  methods:{
    childRefFn(){
      console.log(this.$refs.childRef.uname)
      this.$refs.childRef.logName()
    }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="components/ChildB.vue"]</p>
<pre><code>&lt;template&gt;
  &lt;div&gt;
    ChildB
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data(){
      return{
          uname: 'JuziYou',
      }
  },
  methods:{
      logName(){
          console.log(this.uname)
      }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<hr />
<h1><code>$nextTick</code></h1>
<p>由于 Vue 更新 DOM 是异步的，会导致需要在 DOM 更新之后的代码会被先执行，所以需要使用 <code>$nextTick</code>
<code>$nextTick</code>接收一个函数作为参数，接收的函数将会在 DOM 更新后执行</p>
<p>如在点击按钮后显示输入框然后获取输入框的 DOM：</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;input type="text" ref="ipt" v-if="isShowInput"&gt;
    &lt;button @click="fn" v-else&gt;Click&lt;/button&gt;
  &lt;/div&gt;
 &lt;/template&gt;

&lt;script&gt;
export default {
  data () {
    return {
      isShowInput: false
    }
  },
  methods: {
    fn () {
      this.isShowInput = true
      this.$nextTick(()=&gt;{
        console.log(this.$refs.ipt);
      })
    }
  }
}
&lt;/script&gt;</code></pre>
<hr />
<h1><code>component</code>动态渲染组件</h1>
<p><code>component</code>是 Vue 内置的一个组件用于动态的渲染组件，<code>:is="值"</code>的值是什么就会渲染哪个子组件
[tabs]
[tab name="App.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;button @click="comName = 'ChildA'"&gt;ChildA&lt;/button&gt;
    &lt;button @click="comName = 'ChildB'"&gt;ChildB&lt;/button&gt;
    &lt;component :is="comName"&gt;&lt;/component&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import ChildA from './components/ChildA.vue'
import ChildB from './components/ChildB.vue'
export default {
  components:{
    ChildA,
    ChildB
  },
  data(){
    return{
      comName: 'ChildA'
    }
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="components/ChildA.vue"]</p>
<pre><code>&lt;template&gt;
  &lt;div&gt;
    &lt;h1&gt;ChildA&lt;/h1&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<p>[/tab]
[tab name="components/ChildB.vue"]</p>
<pre><code>&lt;template&gt;
  &lt;div&gt;
    &lt;h1&gt;ChildB&lt;/h1&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<hr />
<h1>自定义指令</h1>
<p>自定义指令分为全局和局部注册，在标签上 <code>v-自定义指令名</code>进行使用</p>
<p>常用的：
<code>inserted</code>方法绑定此指令的元素插入到 DOM 时执行
语法为 <code>inserted(形参){}</code>
<code>inserted(形参){}</code>第一个形参是绑定此指令的元素，第二个形参为当前自定义指令传入的值</p>
<p><code>update</code>方法绑定此指令的元素值发生变化时执行
语法为 <code>update(形参){}</code>
<code>update(形参){}</code>第一个形参是绑定此指令的元素，第二个形参为当前自定义指令传入的值</p>
<p>[tabs]
[tab name="全局注册"]
在 <code>main.js</code>内添加 <code>Vue.directive</code>进行全局注册
语法为 <code>Vue.directive('指令名',{方法})</code></p>
<p>示例：在 input 标签创建时自动落焦</p>
<pre><code>Vue.directive('focusglo', {
  inserted(el){
    el.focus()
  }
})</code></pre>
<p>[/tab]
[tab name="局部注册"]
在组件的 <code>export default</code>内使用 <code>directives{对象}</code>进行局部注册，注册的自定义指令只能在当前组件使用</p>
<p>示例：如 <code>color</code>的值发生变化时重新设置使用了此自定义指令的元素的颜色</p>
<pre><code class="language-JavaScript">export default {
  data () {
    return {
      color: 'orange'
    }
  }
  directives: {
    zy:{
      inserted(el,binding){
        el.style.color = binding.value
      },
      update(el,binding){
        el.style.color = binding.value
      }
    }
  }
}</code></pre>
<p>[/tab]
[/tabs]</p>
<hr />
<h1>插槽</h1>
<p>插槽插在父组件的两个起始标签和结束标签之间，默认会放到默认 <code>&lt;slot&gt;</code>插槽内
<code>&lt;template&gt;</code>中使用指令 <code>v-slot:插槽名</code>来使用指定的插槽，也可以用 <code>#插槽名来简写</code>，在子组件内的 <code>&lt;slot&gt;</code>通过 <code>name="插槽名"</code>变量的方式来设置插槽名
默认插槽可以使用 <code>&lt;template v-slot="变量名"&gt;&lt;/template &gt;"</code>来接收传过来的参数，具名插槽可以之间加上等号变量名来接收传过来的的参数 <code>&lt;template v-slot:插槽名="变量名"&gt;&lt;/template &gt;"</code>，在子组件内的 <code>&lt;slot&gt;</code>通过添加自定义变量名的方式来传参</p>
<p>[tabs]
[tab name="App.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;!-- 使用組件時在父組件的兩個標簽之間插入 --&gt;
    &lt;MyDialog&gt;
      &lt;img src="https://lovemen.cc/usr/hotlink-ok/avatar.jpg" alt=""&gt;
    &lt;/MyDialog&gt;
    &lt;MyDialog&gt;
      &lt;!-- &lt;template v-slot:footer&gt; 指定插入footer插槽 v-slot:插槽name --&gt;
      &lt;!-- 在具名插槽下直接加上等號就可以接收，可以在等號内直接解構賦值 --&gt;
      &lt;template v-slot:footer="{yes:okay,no}"&gt;
        &lt;button&gt;{{ okay }}&lt;/button&gt;
        &lt;button&gt;{{ no }}&lt;/button&gt;
      &lt;/template&gt;
        &lt;!-- 可以使用#簡寫 --&gt;
      &lt;template #header&gt;
        &lt;h3&gt;溫馨提示&lt;/h3&gt;
      &lt;/template&gt;
      &lt;!-- 默認插槽透過v-slot="變量名"接收傳過來的，將以對象形式呈現，只能在template内使用 --&gt;
      &lt;template v-slot="obj"&gt;
        {{obj}}
        &lt;p&gt;你好，買？&lt;/p&gt;
      &lt;/template&gt;
    &lt;/MyDialog&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import MyDialog from './components/MyDialog.vue'
export default {
  components:{
    MyDialog
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="components/MyDialog.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div class="my-dialog"&gt;
    &lt;div class="header"&gt;
      &lt;slot name="header"&gt;&lt;/slot&gt;
    &lt;/div&gt;
    &lt;div class="content"&gt;
      &lt;!-- slot表示此處有一個插槽 --&gt;
      &lt;!-- 作用域插槽：通過插槽設置自定義參數傳數據 --&gt;
      &lt;slot uname="MikanpapreYuzu" age="18"&gt;&lt;/slot&gt;
    &lt;/div&gt;
    &lt;div class="footer"&gt;
      &lt;!-- name給插槽起名 --&gt;
      &lt;slot name="footer" yes="好捏" no="打咩"&gt;&lt;/slot&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {

}
&lt;/script&gt;

&lt;style lang="less" scoped&gt;
.my-dialog {
  width: 400px;
  padding: 10px 20px;
  border: 3px solid #000;
  border-radius: 5px;
  margin: 10px;
}
&lt;/style&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<hr />
<h1>路由</h1>
<p>npm 默认获取的 <code>vue-router</code>版本为 4，在 Vue2 中需要 <code>vue-router</code>版本为 3 时才可以使用，所以在 Vue2 中需要 <code>@3</code>指定 <code>vue-router</code>安装版本</p>
<pre><code class="language-shell">npm i vue-router@3</code></pre>
<p>路由就是路径和组件间的关系，创建路由的方式有在 <code>main.js</code>创建路由和创建 <code>router</code>文件夹在 <code>index.js</code>中创建路由</p>
<h2>在 <code>main.js</code>创建路由</h2>
<p>先在 <code>main.js</code>内使用 <code>import VueRouter from 'vue-router'</code>引入 <code>vue-router</code>，然后使用 <code>Vue.use(VueRouter)</code>让 Vue 使用 <code>vue-router</code>插件 <code>const router = new VueRouter(对象)</code>创建一个路由实例，在对象内添加一个 <code>routes</code>数组，这个数组内每个对象都是一个匹配规则，<code>import RouterPage from '@/views/RouterPage'</code>引入组件，router 内的对象 <code>path</code>为设置路由的路径 <code>component</code>为设置路由指向的组件，最后在 <code>new Vue</code>内添加 const 出来的变量名关联到 Vue 实例，匹配到的组件会在 <code>&lt;router-view&gt;&lt;/router-view&gt;</code>渲染</p>
<p>[tabs]
[tab name="main.js"]</p>
<pre><code class="language-JavaScript">import Vue from 'vue'
import App from './App.vue'
import My from '@/views/My'
import Part from '@/views/Part'

// 5 引入组件
import RouterPage from '@/views/RouterPage'
// 1引入vue-router
import VueRouter from 'vue-router'
// 2让Vue使用vue-router插件
Vue.use(VueRouter)
// 3创建路由实例
const router = new VueRouter({
  // 6 routes 是一个数组，此数组里面的每一个对象都是一个匹配规则
  routes:[
    {
      // 7设置路由路径
      path:'/RouterPage',
      // 8 给路径指向组件
      component: RouterPage
    }
  ]
})

Vue.config.productionTip = false

//4 吧路由实例关联router到vue实例
new Vue({
  router,
  render: h =&gt; h(App),
}).$mount('#app')</code></pre>
<p>[/tab]
[tab name="views/RouterPage.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h1&gt;RouterPage&lt;/h1&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<p>[/tab]
[tab name="App.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;a href="#/RouterPage"&gt;&lt;/a&gt;
    &lt;div&gt;
      &lt;router-view&gt;&lt;/router-view&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<p>[/tab]</p>
<p>[/tabs]</p>
<h2>在 <code>router</code>文件夹中的 <code>index.js</code>创建路由</h2>
<p>在 <code>main.js</code>中创建路由不太好，应该每个模块干每个模块的事情
在 <code>src</code>中创建 <code>router</code>文件夹然后在文件夹中创建 <code>index.js</code>，首先在 <code>index.js</code>中使用 <code>import Vue from 'vue'</code>引入 Vue，然后使用 <code>import VueRouter from 'vue-router'</code>引入 <code>vue-router</code>，接着使用 <code>Vue.use(VueRouter)</code>让 Vue 使用 <code>vue-router</code>插件，使用 <code>const router = new VueRouter(对象)</code>创建一个路由实例，在对象内添加一个 <code>routes</code>数组，这个数组内每个对象都是一个匹配规则，<code>import RouterPage from '@/views/RouterPage'</code>引入组件，router 内的对象 <code>path</code>为设置路由的路径 <code>component</code>为设置路由指向的组件，<code>export default router</code>让 <code>index.js</code>对外暴露 <code>router</code>实例，最后在 <code>main.js</code>中使用 <code>import router from '@/router/index.js'</code>引入路由实例再在 <code>new Vue</code>中关联引入的实例 <code>router</code>到 Vue 实例，匹配到的组件会在 <code>&lt;router-view&gt;&lt;/router-view&gt;</code>渲染</p>
<p>[tabs]
[tab name="router/index.js"]</p>
<pre><code class="language-JavaScript">// 1 引入Vue
import Vue from 'vue'
// 5 引入组件
import RouterPage from '@/views/RouterPage'
// 2 引入vue-router
import VueRouter from 'vue-router'
// 3 让Vue使用vue-router插件
Vue.use(VueRouter)
// 4 创建路由实例
const router = new VueRouter({
  // 6 routes 是一个数组，此数组里面的每一个对象都是一个匹配规则
  routes:[
    {
      // 7设置路由路径
      path:'/RouterPage',
      // 8 给路径指向组件
      component: RouterPage,
    }
  ]
})

// 对外暴露路由实例对象
export default router</code></pre>
<p>[/tab]
[tab name="main.js"]</p>
<pre><code class="language-JavaScript">import Vue from 'vue'
import App from './App.vue'

// 引入路由实例
import router from '@/router/index.js'

Vue.config.productionTip = false

//4 吧路由实例关联router到vue实例
new Vue({
  router,
  render: h =&gt; h(App),
}).$mount('#app')</code></pre>
<p>[/tab]
[tab name="views/RouterPage.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;h1&gt;RouterPage&lt;/h1&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<p>[/tab]
[tab name="App.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;a href="#/RouterPage"&gt;&lt;/a&gt;
    &lt;div&gt;
      &lt;router-view&gt;&lt;/router-view&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<h3>查询字符串传参</h3>
<p>在 <code>to="path"</code>的 path 后面加 <code>?</code>查询字符串的方式传参，然后在组件内使用 <code>$route.query</code>接收参数会以一个对象的形式接收</p>
<p>比如 <code>&lt;router-link to="/part?uname=JuziYou&amp;ocname=MikanpaperYuzi"&gt;橘纸柚&lt;/router-link&gt;</code>，在组件内 <code>$route.query</code>将会收到一个对象 <code>{uname:'JuziYou', ocname'MikanpaperYuzi'}</code></p>
<h3>动态路由传参</h3>
<p>首先在对应的路径复制一份然后在 path 中的路由加上 <code>/:参数名</code>，然后在组件内使用 <code>$route.params</code>接收参数会以一个对象的形式接收</p>
<p>比如：
一个路由为 <code>/user</code>需要接收一个参数名为 <code>uname</code>（.....省略后面或者前面代码)</p>
<pre><code class="language-JavaScript">..... = new VueRouter({
  routes:[
  .....
  .....
    {
      path:'/user',
      redirect: 'User' 
    },
    {
      path:'/user/:uname',
      redirect: 'User' 
    },
  .....</code></pre>
<p>然后访问比如 <code>localhost:8080/#/user/juziyou</code>，在组件内使用 <code>$route.params</code>将会获取到一个对象 <code>{uname:'juziyou'}</code></p>
<h2>路由重定向以及默认页（404）</h2>
<p>在路由实例的 <code>routes</code>中起始位子添加一个匹配规则，匹配规则中 <code>redirect</code>为重定向的路径</p>
<p>如从 <code>/</code>重定向到 <code>/juziyou</code>（.....省略后面或者前面代码)</p>
<pre><code class="language-JavaScript">..... = new VueRouter({
  routes:[
    {
      path:'/',
      redirect: '/juziyou' 
    },
  .....</code></pre>
<p>默认页则在路由实例的 <code>routes</code>中的末尾添加一个 <code>path</code>为通配符 <code>*</code>的一个规则</p>
<p>如前面一个规则也没匹配上返回一个 <code>NotFund</code>页面（.....省略后面或者前面代码)</p>
<pre><code class="language-JavaScript">..... = new VueRouter({
  routes:[
  .....
  .....
    {
      path:'*',
      redirect: 'NotFund' 
    },
  .....</code></pre>
<h2>mode 与 base</h2>
<p><code>mode</code>写在路由的实例中有个常用的参数 <code>hash</code>和 <code>history</code>，<code>hash</code>会在 URL 中添加#号，<code>history</code>则不会但是需要后端配合因为会向服务器发送真实路径。
以及可以通过 <code>base</code> 设置基础地址，比如要访问 <code>/user</code> 页面在 <code>hash</code> 模式下是 <code>/#/user</code> 如果在 <code>history</code> 模式下设置了 <code>base</code> 为 <code>/juzi/</code> 地址就是 <code>/juzi/user</code></p>
<p>如修改 <code>mode</code>到 <code>history</code>（.....省略后面或者前面代码)</p>
<pre><code class="language-JavaScript">..... = new VueRouter({
  mode: 'history',
  base: '/juzi/'
  .....</code></pre>
<h2><code>router-link</code>声明式导航</h2>
<p>声明式导航 <code>router-link</code>是 <code>vue-router</code>提供的一个全局组件，使用 <code>to="path"</code>来跳转路由路径
会给选中的路由自动的加上 class 类名，其分为模糊匹配类名和精确匹配类名，可以在路由实例内通过 <code>linkActiveClas</code>修改模糊匹配类名以及通过 <code>linkExactActiveClass</code>修改精确匹配类名</p>
<p>如通过 <code>router-link</code>转到 path <code>/routerpage</code></p>
<pre><code class="language-html">&lt;router-link to="/routerpage"&gt;&lt;/router-link&gt;</code></pre>
<p>如需要修改精确匹配类名为:juzi，模糊匹配类名为:you 在路由实例内设置的方式（.....省略后面或者前面代码)</p>
<pre><code class="language-JavaScript">...... = new VueRouter({
  linkActiveClass:'you',
  linkExactActiveClass:'juzi',
  ......</code></pre>
<h2>编程式传参</h2>
<p>通过调用函数的方式使用方法 <code>$router.push</code>，使用 <code>path</code>无法使用 <code>params</code>传参所以推荐使用 <code>name</code>来进行跳转</p>
<h2>name</h2>
<p>在路由配置中添加 <code>name</code>属性，在编程式导航中如果需要使用 <code>params</code>就得用 <code>name</code>来跳转</p>
<h2>路由守卫</h2>
<p>路由守卫分为全局路由守卫、路由内独享守卫、组件内守卫</p>
<p><strong>全局路由守卫：</strong>对所有路由守卫生效</p>
<ul>
<li>beforeEach 路由前置守卫：token 判断</li>
<li>arterEach 路由后置守卫：进度条关闭</li>
</ul>
<p><strong>路由独享守卫：</strong>对某一条路由进行单向控制</p>
<ul>
<li>beforeEnter 路由独享守卫：写在路由配置项内，也有 <code>to</code> <code>from</code> <code>next</code> 只对某条路由规则生效</li>
</ul>
<p><strong>组件内守卫：</strong>针对组件内</p>
<ul>
<li>beforeRouterEnter 只要通过路由就会触发</li>
<li>beforeRouteUpdate: 再次复用了页面，比如主页跳到带 params 的主页，解决 created 只会触发一次的问题</li>
<li>beforeRouterLeave: 代表离开了页面</li>
</ul>
<h3>全局守卫</h3>
<p>所有的路由一旦匹配到规则在真正渲染解析前都会经过全局守卫，只有在全局守卫放行后才能真正渲染页面
在创建实例前先声明一个白名单变量或常量，吧路由(path)以字符串的形式储存在数组中，然后使用<code>router.beforeEach(回调函数)</code>创建路由守卫，在路由解析访问之前都会经过回调函数，回调函数中有三个形参<code>from</code>从哪里来的路由信息对象、<code>to</code>要到那里去的路由信息对象、<code>next</code>是否放行这是一个方法，如果<code>next()</code>表示放行去的页面、<code>next(路径)</code>则表示拦截到的页面，使用<code>whiteList.includes</code>来匹配是否处于白名单</p>
<p>如验证用户是否登录</p>
<pre><code class="language-JavaScript">// 设置白名单
const whiteList = ['/login', '/regisrer']
router.beforeEach((to, from, next) =&gt; {
  // 如果有token就放行
  if (this.token) {
    next()
  } else {
    // 如果没有token检查是不是去白名单页面
    if (whiteList.includes(to.path)) {
      // 如果是去白名单直接放行
      next()
    } else {
      // 如果不是去白名单跳转到登录
      next('/login')
    }
  }
})</code></pre>
<hr />
<h1>生命周期</h1>
<p>生命周期是 Vue 组件创建到销毁的过程
在特定的时间点执行特定的操作
分四大阶段，八个方法
<a href="https://cn.vuejs.org/v2/guide/instance.html#%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%9B%BE%E7%A4%BA">官方文档</a></p>
<h2>初始化</h2>
<p><code>beforeCreate</code>在组件创建之前会被调用，此状态下无法获取自定义的数据，比如 <code>data</code>中的数据
<code>created</code>会在初始化数据并当前实例代理了数据后执行，一般会在此生命周期钩子中请求服务器数据</p>
<h2>挂载</h2>
<p><code>beforeMount</code>无法获取到 DOM 元素因为这个时候还是虚拟 DOM
<code>mounted</code>中就可以获取到真实 DOM 了</p>
<h2>更新</h2>
<p><code>beforeUpdate</code>在页面使用中的数据发生变时虚拟 DOM 更新之前运行
<code>updated</code>在使用中的数据发生变化时虚拟 DOM 更新到页面后运行</p>
<h2>销毁</h2>
<p><code>beforeDestroy</code>在销毁前运行，一般用来解绑一些事件，比如说定时器
<code>destroyed</code>咋子销毁后运行</p>
<h2><code>keep-alive</code>缓存</h2>
<p><code>&lt;keep-alive&gt;</code>是 Vue 内置的全局组件可以吧组件缓存到内存中，使用<code>&lt;keep-alive&gt;</code>被缓存的组件有两个生命周期<code>activated</code>组件被激活<code>deactivated</code>组件被隐藏</p>
<hr />
<h1>vuex</h1>
<p>vuex 是 vue 的一个状态（数据）管理工具（也是插件），方便的解决多组件的共享状态，拥有响应式、操作简洁的优势
一般情况下多组件的数据共享会存在 vuex 中</p>
<h2>创建仓库</h2>
<p>一般为了维护项目的目录整洁会在<code>src</code>目录下新建<code>store</code>目录放置<code>index.js</code>
首先在创建 Vuex 实例然后再在<code>main.js</code>中导入挂载到 Vue 实例上
<code>Vuex.Store()</code>括号内是一个对象
[tabs]
[tab name="store/index.js"]</p>
<pre><code class="language-JavaScript">// 引入Vue
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 注册vuex插件
Vue.use(Vuex)
// 创建仓库实例
const store = new Vuex.Store()
// 导出仓库
export default store</code></pre>
<p>[/tab]
[tab name="main.js"]</p>
<pre><code class="language-JavaScript">import Vue from 'vue'
import App from './App.vue'
// 引入store
import store from '@/store'

Vue.config.productionTip = false

new Vue({
  // 挂载到 Vue 实例
  store,
  render: h =&gt; h(App)
}).$mount('#app')</code></pre>
<p>[/tab]
[/tabs]</p>
<h2>state</h2>
<p>state 提供唯一的公共数据源，所有的共享数据需要放到 state 中储存，可以在任何组件中使用<code>$store.state.键</code>来获取 state 中的数据也可以通过<code>mapState()</code>映射到<code>computed</code>中</p>
<p>[tabs]
[tab name="store/index.js"]</p>
<pre><code class="language-JavaScript">import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

const store = new Vuex.Store({
  // 设置 State
  state:{
    uname: 'JuziYou',
    age: 18
  }
})
export default store</code></pre>
<p>[/tab]
[tab name="App.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;!-- 直接使用 $store.state.uname 获取 uname 的值 --&gt;
    &lt;p&gt;{{ $store.state.uname }}&lt;/p&gt;
    &lt;!-- 直接使用映射计算属性得到的值 --&gt;
    &lt;p&gt;{{ age }}&lt;/p&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
// 引入 mapState 
import { mapState } from 'vuex'
export default {
  computed:{
    // mapState() 得到的是一个数组中对应的对象可以使用 ... 展开运算符展开到计算属性中
    ...mapState(['age'])
  }
}
&lt;/script&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<h2>mutation</h2>
<p>state 中的数据只能通过 mutation 修改，用于父组件需要修改仓库中的数据
在 vuex 实例中定义<code>mutation</code>，它是一个对象里面存储修改 state 的方法，每个方法的第一个形参是当前仓库的 state，第二个是传入的参数
可以通过<code>$store.commit('方法', 传参)</code>来调用 mutation 中的方法，传参只能传一个参数如果需要传多个使用复杂数据类型来完成，比如说对象
还可以通过辅助函数<code>mapMutations(数组)</code>的方式使用展开运算符映射到<code>methods</code>中，需要使用<code>this.方法</code>来调用，使用起来和<code>mapState()</code>很像</p>
<h2>actions</h2>
<p>actions 负责仓库内的异步操作，mutation 只能用于同步更新数据
在 vuex 实例中定义<code>actions</code>，它是一个对象里面存储异步的方法，每个方法的第一个形参拥有仓库实例的所有属性和方法，第二个是传入的参数传参只能传一个参数如果需要传多个使用复杂数据类型来完成，比如说对象
可以通过<code>$store.dispatch('方法', 传参)</code>来调用
也可以通过辅助函数<code>mapActions(数组)</code>来调用使用展开运算符映射到<code>methods</code></p>
<h2>getters</h2>
<p>getters 使用仓库 state 中现有的数据计算出新的数据
在 vuex 实例中定义<code>getters</code>，每个方法的第一个形参是当前仓库的 state，必须要有返回值
可以通过<code>$store.getters.方法</code>来调用
也可以通过辅助函数<code>mapGetters(数组)</code>的方式使用展开运算符映射到<code>computed</code>中</p>
<h2>module 模块</h2>
<p>如果使用单一的<code>index.js</code>项目大后应用会变得非常复杂相对臃肿
在<code>store</code>文件夹中创建一个用于存放模块的文件夹，<code>export default</code>向外暴露键<code>state</code>、<code>mutations</code>、<code>actions</code>、<code>getters</code>值就是它们所需要的值，访问模块中的数据可以直接通过<code>$store.state.模块名.数据键</code>来访问<code>mutations</code>、<code>actions</code>、<code>getters</code>默认情况下全局可以<code>调用，然后在</code>index.js<code>中引入模块并在</code>modules<code>中注册，组件的</code>state<code>以对象的形式挂载到</code>state` 下
[tabs]
[tab name="store/data.js"]</p>
<pre><code class="language-JavaScript">export default {
  state: {},
  mutations: {},
  actions: {},
  getters: {}
}</code></pre>
<p>[/tab]
[tab name="store/index.js"]</p>
<pre><code class="language-JavaScript">import Vue from 'vue'
import Vuex from 'vuex'
// 引入子模块
import data from '@/store/data'
Vue.use(Vuex)
const store = new Vuex.Store({
  // 使用modules来引入子模块
  // 会将挂载组件的state以对象的形式挂载到state下
  modules:{
    data
  },
})</code></pre>
<p>[/tab]
[/tabs]</p>
<h2>namespaced 命名空间</h2>
<p>开启命名空间后子模块的 mutations、actions、getters 就不会注册在仓库全局，在子模块的<code>export default</code>中添加<code>namespaced: true</code>，开启后<code>$store</code>访问模块内的方法需要<code>模块名/函数名</code>
辅助函数需要在数组前增加模块名如<code>mapState(模块名, 数组)</code>，然后通过<code>this.方法</code>来调用
辅助函数还可以通过加<code>/</code>的方式来使用（如<code>mapState(['模块名/方法名']</code>），在调用方法时得<code>this[模块名/方法名]()</code>来调用</p>
<pre><code class="language-JavaScript">export default {
  namespaced: true,
}</code></pre>
<h3><code>createNamespacedHelpers</code></h3>
<p><code>createNamespacedHelpers</code>辅助函数会返回一个对象里有<code>mapActions</code>、<code>mapGetters</code>、<code>mapMutations</code>、<code>mapState</code>通过解构赋值和重命名的方式来提取映射
[tabs]
[tab name="store/modules/datas.js"]</p>
<pre><code class="language-JavaScript">export default {
  namespaced: true,
  state: {
    uname: 'JuziYou'
  },
  mutations: {
    updateName (state, payload) {
      state.uname = payload
    }
  }
}</code></pre>
<p>[/tab]
[tab name="store/index.js"]</p>
<pre><code class="language-JavaScript">import Vue from 'vue'
import Vuex from 'vuex'
import datas from '@/store/modules/datas'
Vue.use(Vuex)
const store = new Vuex.Store({
  state: {
  },
  mutations: {
  },
  actions: {
  },
  getters: {
  },
  modules: {
    datas
  }
})

export default store</code></pre>
<p>[/tab]
[tab name="App.vue"]</p>
<pre><code class="language-HTML">&lt;template&gt;
  &lt;div&gt;
    &lt;div&gt;{{ $store.state.datas.uname }}&lt;/div&gt;
    &lt;button @click="updateUname"&gt;Mikanpapre&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import { createNamespacedHelpers } from 'vuex'
const { mapMutations: userMapMutations } = createNamespacedHelpers('datas')
export default {
  methods: {
    ...userMapMutations(['updateName']),
    updateUname () {
      this.updateName('Mikanpapre')
    }
  }
}</code></pre>
<p>[/tab]
[/tabs]</p>
<hr />
<h1>Vue3 内容</h1>
<p>相比 Vue2 它首次渲染更快、内存占用更少、diff 算法更快、打包体积更小、更好的支持 Typescript 拥有 Composition API 组合式 API，允许 <code>template</code> 存在多个根标签</p>
<h2>vite 构建工具</h2>
<p>vite 使用原生 ESModule 通过 script 标签动态导入，访问页面的时候加载到对应模块编译并响应，比 Webpack 查找依赖打包所有模块速度更快。在项目打包的时候还是得用打包工具 Rollup 打包成静态资源</p>
<p>运行创建项目：</p>
<pre><code class="language-shell"># 使用 npm
npm create vite@latest
# 使用 yarn
yarn create vite</code></pre>
<p>快速创建</p>
<pre><code class="language-shell"># 使用 npm
npm init vite-app 项目名称
# 使用 yarn
yarn create vite-app 项目名称</code></pre>
<hr />
<h2>Composition API</h2>
<p><a href="https://cn.vuejs.org/api/composition-api-setup.html">官方文档</a>
Vue2 通过 <code>data</code>、<code>methods</code>、<code>watch</code> 等配置项编写代码逻辑是选项式 API 写法
Vue3 吧所有逻辑卸载 <code>setup</code> 函数中，使用 <code>ref()</code>、<code>computed()</code> 等阻止代码是组合式 API 写法
组合式 API 可复用可维护</p>
<hr />
<h2><code>setup</code></h2>
<p><code>setup</code> 是组合式 API 的入口钩子，作为组合式 API 的起点，它在组件的生命周期 <code>beforeCreate</code> 之前执行，函数中的 <code>this</code> 不是组件实例而是 <code>undefined</code> 如果数据或者函数在 <code>template</code> 中使用需要 <code>return</code> 对象返回</p>
<pre><code class="language-JavaScript">export default {
  setup() {
    const uname = 'JuziYou'
    return { uname }
  }
}</code></pre>
<h3><code>setup</code> 语法糖</h3>
<p>Vue3.2 后在 <code>&lt;script&gt;</code> 标签上添加 <code>setup</code> 属性会可以省去默认暴露 <code>export default</code> 和 <code>return</code> 步骤会自动完成，的顶层变量都可以在模板使用数据、函数、组件
在 <code>setup</code> 语法糖中 <code>defineProps</code> 、 <code>defineEmits</code> 、 <code>defineExpose</code> 不需要再引入</p>
<h3><code>setup</code> 语法糖 <code>name</code> 问题</h3>
<p>因为使用了 <code>setup</code> 的语法糖后无法使用选项式 API 所以可以使用 <code>vite-plugin-vue-setup-extend</code> 插件来给 <code>&lt;script&gt;</code> 标签上添加属性 <code>name</code> 来解决这个问题，<code>&lt;script&gt;</code> 标签内有内容才能生效</p>
<p>安装插件：</p>
<pre><code class="language-shell">npm i vite-plugin-vue-setup-extend-plus -D</code></pre>
<p>在 <code>vite.config.ts</code> 使用插件</p>
<pre><code class="language-JavaScript">import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// 引入 vite-plugin-vue-setup-extend-plus
import vueSetupExtend from 'vite-plugin-vue-setup-extend-plus'

export default defineConfig({
  // plugins 中添加 vueSetupExtend() 使用插件
  plugins: [vue(), vueSetupExtend()],
})</code></pre>
<p>然后在 <code>&lt;script&gt;</code> 标签添加 <code>name</code> 属性</p>
<pre><code>&lt;!-- script 标签添加 name 属性 --&gt;
&lt;script setup lang="ts" name="Nya"&gt;
  console.log('script 标签内有内容才能生效');
&lt;/script&gt;

&lt;template&gt;
&lt;/template&gt;

&lt;style scoped&gt;

&lt;/style&gt;</code></pre>
<hr />
<h2><code>ref</code></h2>
<p>从 <code>vue</code> 中导出在 <code>setup</code> 钩子中使用一般传入一个简单数据类型或复杂数据类型，返回一个响应式数据，<code>template</code>外使用 <code>ref</code> 中的数据时需要 <code>.value</code> 调用，它可以定义任意数据的响应式</p>
<h3>获取 DOM</h3>
<p>从 <code>vue</code> 中导出在 <code>setup</code> 钩子中使用，<code>ref</code>会在<code>onMounted</code>生命周期后获取页面上绑定了与变量名相同 ref 属性的的 <code>DOM</code> 存在 <code>.value</code> 中，第一个参数是如果没有成功获取到 <code>DOM</code> 时的返回值</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;div ref="Nya"&gt;JuziYou&lt;/div&gt;
&lt;/template&gt;


&lt;script setup&gt;
  import { onBeforeMount, onMounted, ref } from 'vue'
  const Nya = ref(null)
  onBeforeMount(() =&gt; {
    console.log(Nya.value)
  })
  onMounted(() =&gt; {
    console.log(Nya.value)
  })
&lt;/script&gt;</code></pre>
<h3><code>defineExpose</code></h3>
<p>因为使用 <code>&lt;script setup&gt;</code> 的组件是默认关闭的，组件实例无法使用到顶层的数据和函数，需要配合 <code>defineExpose</code> 暴露给组件实例使用，暴露的响应式数据会自动解除响应式。
从 <code>vue</code> 中导出 <code>defineExpose</code>传入一个对象对象中写入需要导出的数据和函数</p>
<p>[tabs]
[tab name="components/MyCount.vue"]</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;h1&gt;{{ count }}&lt;/h1&gt;
&lt;/template&gt;

&lt;script setup&gt;
  import { ref, defineExpose } from 'vue'
  const count = ref(0)
  const countPlus = () =&gt; {
    count.value++
  }
  defineExpose({countPlus, count})
&lt;/script&gt;</code></pre>
<p>[/tab]
[tab name="App.vue"]</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;MyCount ref="count" /&gt;
  &lt;button @click="addCount"&gt;Count++&lt;/button&gt;
&lt;/template&gt;


&lt;script setup&gt;
  import { ref } from 'vue';
  import MyCount from './components/MyCount.vue';
  const count = ref(null)
  const addCount = () =&gt; {
    count.value.countPlus()
  }
&lt;/script&gt;</code></pre>
<p>[/tab]
[/tabs]</p>
<hr />
<h2><code>reactive</code></h2>
<p>从 <code>vue</code> 中导出在 <code>setup</code> 钩子中使用， <code>reactive</code> 一般用来定义对象类型的响应式数据不支持简单数据类型，<code>reactive</code> 定义的数据修改不用加 <code>.value</code> 调用，不可以直接对它重新赋值，如果涉及到重新赋值应该使用 <code>ref</code></p>
<hr />
<h2><code>toRefs</code></h2>
<p>对 <code>reactive</code> 的响应式数据解构或者展开会失去响应式，使用 <code>toRefs</code> 函数让数据保持响应式， <code>toRefs</code> 会吧对象的每一个属性包装成响应式</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;div&gt;{{ uname }} · {{ age }}&lt;/div&gt;
  &lt;button @click="age++"&gt;age++&lt;/button&gt;
&lt;/template&gt;


&lt;script setup&gt;
  import { reactive, toRefs } from 'vue'
  const person = reactive({
    uname: 'harry',
    age: 28
  })
  const {uname, age} = toRefs(person)
&lt;/script&gt;</code></pre>
<hr />
<h2><code>computed</code></h2>
<p>从 <code>vue</code> 中导出在 <code>setup</code> 钩子中使用，<code>computed</code> 计算函数接收一个函数返回一个计算好的数据，并且和 Vue2 一样有缓存</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;div&gt;{{ arr }}&lt;/div&gt;
  &lt;div&gt;{{ sum }}&lt;/div&gt;
  &lt;button @click="pushNum"&gt;Push&lt;/button&gt;
&lt;/template&gt;


&lt;script setup&gt;
  import { ref, computed } from 'vue'
  const arr = ref([1, 1, 4, 5, 1, 4])
  const sum = computed(() =&gt; arr.value.reduce((pre, item) =&gt; pre + item, 0))
  const pushNum = () =&gt; {
    arr.value.push(1)
  }
&lt;/script&gt;</code></pre>
<h2><code>watch</code></h2>
<p>从 <code>vue</code> 中导出在 <code>setup</code> 钩子中使用，第三个值是配置项可以省略</p>
<h3>单个数据监听</h3>
<p>第一个参数是它接听的数据，第二个参数是函数数据发生变化执行的函数，函数中第一个接收值是新值第二个是旧值</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;div&gt;{{ count }}&lt;/div&gt;
  &lt;button @click="numPlus"&gt;Plus&lt;/button&gt;
&lt;/template&gt;


&lt;script setup&gt;
  import { ref, watch } from 'vue'
  const count = ref(1)
  const numPlus = () =&gt; {
    count.value++
  }
  watch(count, (newVal, lodVal) =&gt; {
    console.log(newVal, lodVal);
  })
&lt;/script&gt;</code></pre>
<h3>多个数据监听</h3>
<p>在 Vue3 中 <code>watch</code> 支持一次监听多个数据，只需要第一个参数传入一个数组。第二个参数是函数数据发生变化执行的函数，函数中第一个接收值是新值第二个是旧值，返回值会是数组的形式</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;div&gt;{{ count }} · {{ uname }}&lt;/div&gt;
  &lt;button @click="numPlus"&gt;Plus&lt;/button&gt;
  &lt;button @click="newName"&gt;NewName&lt;/button&gt;
&lt;/template&gt;


&lt;script setup&gt;
  import { ref, watch } from 'vue'
  const count = ref(1)
  const uname = ref('JuziYou')
  const numPlus = () =&gt; {
    count.value++
  }
  const newName = () =&gt; {
    uname.value = prompt('NewName')
  }
  watch([count, uname], (newVal, lodVal) =&gt; {
    console.log(newVal, lodVal);
  })
&lt;/script&gt;</code></pre>
<h3>监听对象的单个属性</h3>
<p>只需要第一个参数传入一个对象返回需要监听的属性。第二个参数是函数数据发生变化执行的函数，函数中第一个接收值是新值第二个是旧值</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;div&gt;{{ user }}&lt;/div&gt;
  &lt;button @click="newName"&gt;NewName&lt;/button&gt;
  &lt;button @click="likePlus"&gt;LikePlus&lt;/button&gt;
&lt;/template&gt;


&lt;script setup&gt;
  import { watch , reactive } from 'vue'
  const user = reactive({
    uname: 'JuziYou',
    like: 0
  })
  const newName = () =&gt; {
    user.uname = prompt('NewName')
  }
  const likePlus = () =&gt; {
    user.like++
  }
  watch(()=&gt;user.uname, (newVal, lodVal) =&gt; {
    console.log(newVal, lodVal);
  })
&lt;/script&gt;</code></pre>
<h3>深度监听</h3>
<p>和 Vue2 相同如果监听的是一个对象中的对象，发生变化后并不会触发，需要开启深度监听，在传入的第三个参数是配置项，在配置项中添加 <code>deep: true</code> 参数</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;div&gt;{{ user }}&lt;/div&gt;
  &lt;button @click="likePlus"&gt;LikePlus&lt;/button&gt;
&lt;/template&gt;


&lt;script setup&gt;
  import { watch , reactive } from 'vue'
  const user = reactive({
    uname: 'JuziYou',
    info: {
      like: 0
    }
  })
  const likePlus = () =&gt; {
    user.info.like++
  }
  watch(()=&gt;user.info, (newVal, lodVal) =&gt; {
    console.log(newVal, lodVal);
  }, {
    deep: true
  })
&lt;/script&gt;</code></pre>
<h3>直接监听响应式对象</h3>
<p>如果直接监听一个响应式对象时会自动启用深度监听</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;div&gt;{{ user }}&lt;/div&gt;
  &lt;button @click="likePlus"&gt;LikePlus&lt;/button&gt;
&lt;/template&gt;


&lt;script setup&gt;
  import { watch , reactive } from 'vue'
  const user = reactive({
    uname: 'JuziYou',
    info: {
      like: 0
    }
  })
  const likePlus = () =&gt; {
    user.info.like++
  }
  watch(user, (newVal, lodVal) =&gt; {
    console.log(newVal, lodVal);
  })
&lt;/script&gt;</code></pre>
<hr />
<h2>生命周期</h2>
<p>Vue3 的组合式 API 中与 Vue2 生命周期相比基本相同多了 on 打头 <code>beforeCreate</code> 与 <code>created</code> 不再需要直接写入 <code>setup</code> 中即可，<code>beforeDestroyed</code> 和 <code>destroyed</code> 变成了 <code>onBeforeUnmount</code> 和 <code>onUnmounted</code>
Vue3 中组合式 API 的生命周期函数可以在 <code>setup</code> 中多次调用，谁写在前面执行谁</p>
<hr />
<h2>组件通讯</h2>
<p><a href="https://cn.vuejs.org/api/sfc-script-setup.html#defineprops-defineemits">官网文档</a></p>
<h3>父向子通讯</h3>
<p>与 Vue2 基本相同，不同在子组件在 <code>setup</code> 钩子中使用 <code>defineProps</code> 传入一个对象来接收父组件传来的值，如果需要在 script 中使用就接收返回值，如果不需要只在 template 中使用就不用接收</p>
<h3>子向父通讯</h3>
<p>与 Vue2 基本相同，不同在子组件在 <code>setup</code> 钩子中使用 <code>defineEmits</code> 传入的第一个值是一个数组里面每一项是要触发的父元素绑定的自定义事件名然后接收它的返回值，然后调用接收返回值的常量第一项是父元素绑定的自定义事件名第二项是传参</p>
<h3>跨级组件通讯</h3>
<p>通过通过 <code>provide</code> 和 <code>inject</code> 函数实习便捷的跨级组件通讯，遵循谁提供由谁修改的原则
<code>provide()</code> 提供给后代的组件依赖或者数据，接收两个属性，第一个值为字符串第二个值为函数或要传递的数据
<code>inject()</code> 接收 <code>provide()</code> 提供给后代的组件依赖或者数据， 第一个值为 <code>provide()</code> 的第一个值（字符串）
详见<a href="https://cn.vuejs.org/api/composition-api-dependency-injection.html">官方文档</a></p>
<h2>v-model</h2>
<p>Vue3 中 <code>v-model</code> 是 <code>:modelValue</code> 和 <code>@update:modelValue</code> 的组合，<a href="https://cn.vuejs.org/guide/components/v-model.html">Vue3官方文档</a>
Vue3 中 <code>v-model:name</code> 和 <code>.sync</code> 相同，相当于绑定了 <code>:name</code> 和 <code>@update:name</code></p>
<hr />
<h1>Pinia</h1>
<p>Pinia 与 Vuex 一样是一个为 Vue 提供状态管理的工具，它与 Vue3 一样支持 <code>选项式API</code> 与 <code>组合式API</code>，它也支持 Vue2 和 Devtools 和 TypeScript
可以创建多个全局仓库，不像 Vuex 一个仓库中嵌套模块解构复杂，而且数据管理比 Vuex 更简单只需要写提供数据和修改数据的逻辑即可，不需要像 Vuex 那样记忆大量 API
<code>storeToRefs</code> 可以解决在解构仓库里的数据后失去响应式的问题</p>
<p>[tabs]
[tab name="main.js"]</p>
<pre><code class="language-JavaScript">import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
// 1 引入 createPinia
import { createPinia } from 'pinia'

// 2 调用 createPinia()
const pinia = createPinia()

const app = createApp(App)
// 3 注册 createPinia()
app.use(pinia)
app.mount('#app')</code></pre>
<p>[/tab]
[tab name="App.vue"]</p>
<pre><code class="language-html">&lt;script setup&gt;
  // 10 引入 storeToRefs
  import { storeToRefs } from 'pinia'
  // 7 引入存储仓库的js文件中的存储
  import { useCountStore } from './store'
  // 8 使用一个变量存储调用按需引入的存储的返回值
  const store = useCountStore()
  // 11 storeToRefs 解决解构仓库里的数据失去响应式的问题
  const { count } = storeToRefs(store)
&lt;/script&gt;

&lt;template&gt;
  &lt;!-- 9 使用它 --&gt;
  &lt;div&gt;{{ store.count }}&lt;/div&gt;
  &lt;div&gt;{{ store.squCount }}&lt;/div&gt;
  &lt;div&gt;{{ count }}&lt;/div&gt;
  &lt;button @click="store.addCont"&gt;count++&lt;/button&gt;
  &lt;button @click="store.asyncAddCount"&gt;asycCount++&lt;/button&gt;
  &lt;button @click="store.payloadCount(10)"&gt;asycCount+10&lt;/button&gt;
&lt;/template&gt;</code></pre>
<p>[/tab]
[tab name="store/index.js"]</p>
<pre><code class="language-JavaScript">// 4 引入 defineStore 来创建存储库
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'

// 5 defineStore 接收两个参数第一个是名字第二个是函数，函数中 return 出来一个对象里面是你的数据
export const useCountStore = defineStore('count', ()=&gt;{
  // 5.1 定义响应式数据,相当于定义vuex中的state
  const count = ref(0)
  // 5.2 相当于定义了vuex中的getters
  const squCount = computed(()=&gt; Math.pow(count.value, 2))
  // 5.3 定义修改响应式数据的方法,相当于定义vuex中的mutations
  const addCont = () =&gt; {
    count.value++
  }
  // 5.4 定义修改响应式数据异步加的方法,相当于定义vuex中的actions
  const asyncAddCount = () =&gt; {
    setTimeout(()=&gt;{
      count.value++
    }, 1000)
  }
  // 5.5 接收参数
  const payloadCount = (num = 1) =&gt; {
    count.value += num
  }
  // 6 对外暴露它们
  return { count, squCount, addCont, asyncAddCount, payloadCount }
})</code></pre>
<p>[/tab]
[/tabs]</p>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://lovemen.cc/moe2078.html#comments</comments>
</item>
<item>
<title>JavaScript 学习笔寄</title>
<link>https://lovemen.cc/moe2069.html</link>
<guid isPermaLink="false">https://lovemen.cc/moe2069.html</guid>
<pubDate>Tue, 27 Sep 2022 19:49:00 +0800</pubDate>
<dc:creator>橘纸柚</dc:creator>
<category><![CDATA[笔记]]></category>
<category><![CDATA[JavaScript]]></category>
<description><![CDATA[[hint]随缘更新目前是想单页更新根据后面内容来吧~[/hint]
只是自己的学习笔记只写了点自己觉得比较重要的内容，因为原本输出的就算 Markdown 所以就博客也发一份了，因为是学了哪一些记了哪一些可能会比较混乱，有错别字请见谅
[file url...]]></description>
<content:encoded><![CDATA[
<!--markdown-->[hint]随缘更新目前是想单页更新根据后面内容来吧~[/hint]
<p>只是自己的学习笔记只写了点自己觉得比较重要的内容，因为原本输出的就算 Markdown 所以就博客也发一份了，因为是学了哪一些记了哪一些可能会比较混乱，有错别字请见谅</p>
<p>[file url="<a href="https://file.lovemen.cc/NoteBook/JavaScript%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0.md&quot;]下载原始文件（不一定同步）[/file">https://file.lovemen.cc/NoteBook/JavaScript%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0.md"]下载原始文件（不一定同步）[/file</a>]</p>
<hr />
<h1>事件</h1>
<h2>添加或解绑</h2>
<p>使用 <code>addEventListener()</code>添加事件，使用 <code>removeEventListener()</code>解绑事件</p>
<pre><code class="language-JavaScript">const btn = document.querySelector('#button')
function fn(){
    console.log('Hello')
}
btn.addEventListener('click', fn()) // 绑定事件
btn.removeEventListener('click', fn()) // 解绑事件</code></pre>
<h2>事件名称</h2>
<table>
<thead>
<tr>
<th>事件名称</th>
<th>触发方式</th>
</tr>
</thead>
<tbody>
<tr>
<td>click</td>
<td>鼠标点击</td>
</tr>
<tr>
<td>mouseenter</td>
<td>鼠标经过（存在冒泡）</td>
</tr>
<tr>
<td>mouseleave</td>
<td>鼠标离开（存在冒泡）</td>
</tr>
<tr>
<td>mouseover</td>
<td>鼠标进入（不存在冒泡）</td>
</tr>
<tr>
<td>mouseout</td>
<td>鼠标离开（不存在冒泡）</td>
</tr>
<tr>
<td>focus</td>
<td>获得焦点</td>
</tr>
<tr>
<td>blur</td>
<td>失去焦点</td>
</tr>
<tr>
<td>Keydown</td>
<td>键盘按下触发</td>
</tr>
<tr>
<td>Keyup</td>
<td>键盘抬起触发</td>
</tr>
<tr>
<td>input</td>
<td>用户输入触发</td>
</tr>
<tr>
<td>change</td>
<td>输入框内容改变触发</td>
</tr>
<tr>
<td>load</td>
<td>加载事件，接听整个页面</td>
</tr>
<tr>
<td>DOMContentLoaded</td>
<td>加载事件，无需等待CSS、图像等资源加载完成</td>
</tr>
<tr>
<td>resize</td>
<td>在窗口发生改变时会触发次事件</td>
</tr>
</tbody>
</table>
<h3>scroll 事件</h3>
<p>需要给 window 或者 document 添加此事件，<code>scrollLeft</code>和 <code>scrollTop</code>获取被卷去的大小，是可读写的。<code>document.documentElement HTML</code>返回对象 HTML 的元素，<code>scrollTo()</code>方法可以使用 <code>元素.scrollTo(x, y)</code>来吧页面滚动到指定位置。</p>
<h3>resize 事件</h3>
<p>在窗口发生改变时会触发次事件</p>
<h2>阻止默认行为</h2>
<p>使用 <code>preventDefault()</code>方法来阻止默认行为</p>
<p>如：阻止表单提交的默认行为</p>
<pre><code class="language-JavaScript">document.querySelector('form').addEventListener('submit', function (event) {
    event.preventDefault()
})</code></pre>
<hr />
<h1>日期对象</h1>
<table>
<thead>
<tr>
<th>方法</th>
<th>作用</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>getFullYear()</td>
<td>获得年份</td>
<td>获取四位年份</td>
</tr>
<tr>
<td>getMonth()</td>
<td>获得月份</td>
<td>取值为 0 ~ 11</td>
</tr>
<tr>
<td>getDate()</td>
<td>获取月份中的每一天</td>
<td>不同月份取值也不相同</td>
</tr>
<tr>
<td>getDay()</td>
<td>获取星期</td>
<td>取值为 0 ~ 6</td>
</tr>
<tr>
<td>getHours()</td>
<td>获取小时</td>
<td>取值为 0 ~ 23</td>
</tr>
<tr>
<td>getMinutes()</td>
<td>获取分钟</td>
<td>取值为 0 ~ 59</td>
</tr>
<tr>
<td>getSeconds()</td>
<td>获取秒</td>
<td>取值为 0 ~ 59</td>
</tr>
</tbody>
</table>
<h2>获取时间戳</h2>
<p>时间戳是 1970 年 01 月 01 日 00 时 00 分 00 秒起至现在的毫秒数，通常使用将来的时间戳减去现在的时间戳来就行倒计时</p>
<p>使用 getTime() 方法</p>
<pre><code>const date = new Date()
console.log(date.getTime())</code></pre>
<p>简写 +new Date()</p>
<pre><code>console.log(+new Date())</code></pre>
<p>使用 Date.now()</p>
<pre><code>console.log(Date.now())</code></pre>
<hr />
<h1>节点</h1>
<p>节点关系和节点查找</p>
<h2>父子节点</h2>
<p><code>子元素.parentNode</code>返回最近的一级父级节点，如果找不回返回 <code>null</code>
<code>父元素.childNodes</code>返回所有的子节点，保活文本注释等
<code>父元素.children</code>⭕ 仅获取所有子元素的节点，并且会返回一个伪数组
<code>元素.nextElementSibling</code>获取下一个兄弟节点
<code>元素.previousElementSibling</code>获取上一个兄弟节点</p>
<h2>创建/追加/克隆/删除节点</h2>
<p>使用 <code>document.createElement('标签名')</code>创建一个节点
如:</p>
<pre><code class="language-JavaScript">const divNya = document.createElement('div')</code></pre>
<p>吧节点插入到父元素最后 <code>父元素.appendChild(要插入的元素)</code>
吧节点插入到父元素之前 <code>父元素.insertBefore(要插入的元素，在哪个元素前面)</code>
<code>元素.cloneNode(布尔值)</code>会克隆出来一个和原标签一样的元素，括号内写布尔值，<code>true</code>时会克隆后代节点，<code>false</code>克隆时不包含后代节点这是默认值
<code>父元素.removeChild(要删除的元素)</code>删除不需要的节点，和 CSS 中 <code>display:none</code>的区别是前者为删除后者为隐藏</p>
<hr />
<h1>本地存储</h1>
<p>本地存储有 <code>localStorage</code>和 <code>sessionStorage</code>会以键值对的方式存储，可以在浏览器的 DevTools 的 Application 查看
<code>localStorage</code>能永久的存储在用户电脑本地，关闭页面也不会被删除
<code>sessionStorage</code>在页面关闭时数据将会被删除
<code>.setItem(key, value)</code>存储数据
<code>localStorage.getItem(key)</code>获取数据
<code>localStorage.removeItem(key)</code>删除数据</p>
<h2>JSON</h2>
<p><code>JSON.parse(JSON字符串)</code>吧 JSON 字符串转换为对象
<code>JSON.stringify(复杂数据类型)</code>吧复杂数据类型转换为字符串
<code>JSON.parse(JSON.stringify(复杂数据类型))</code>可以完成不含函数的深拷贝，但是有性能问题</p>
<hr />
<h1>location 对象</h1>
<p>location 对象拆分保存了 URL 地址的各个部分
<code>location.href</code>获取当前的 URL 地址，如果赋值将会跳转到赋值的 URL 地址
<code>location.search</code>获取地址中的参数 <code>?</code>后面的部分
<code>location.hash</code>获取地址中的哈希值 <code>#</code>后面的参数
<code>location.reload</code>刷新页面</p>
<hr />
<h1>history 对象</h1>
<p>history 对象主要用于前进、后退、历史记录等，实际中用的少
<code>history.back()</code> 后退页面
<code>history.forward()</code> 前进页面
<code>history.go(参数)</code>可以前进或者后退页面正数前进负数后退</p>
<hr />
<h1>局部作用域和全局作用域</h1>
<p>作用域规定了变量能够备份访问的范围</p>
<h2>局部作用域</h2>
<p>只能在函数内部访问不能在外部直接访问，函数执行完毕后一般会被释放</p>
<h2>块级作用域</h2>
<p>在 <code>{}</code>包裹的代码块中可以使用，外部有可能无法访问，<strong><code>var</code>不能产生块级作用域</strong></p>
<h2>全局作用域</h2>
<p>全局作用域中声明变量其他任何作用域都可以被访问</p>
<hr />
<h1>作用域链</h1>
<p>由作用域串联提供查找变量的机制，就近原则从内往外一级一级查找变量</p>
<pre><code class="language-JavaScript">let a = 1
function nya(){
    let a = 2
    console.log(a); // 就近原则 nya() 中存在变量名'a'打印 2
}
nya()</code></pre>
<hr />
<h1>闭包 ⭕</h1>
<p>私有化数据，让外部也能访问内部变量，但会有内存泄漏
通过 <code>return</code>一个函数 <code>function</code>可以是匿名函数不起变量名</p>
<pre><code class="language-JavaScript">function nya() {
    let num = 1
    return function() {
        console.log(num);
    }
}
const nyaw = nya()
nyaw() //控制台打印 1</code></pre>
<hr />
<h1>变量提升</h1>
<p><code>var</code>和 <code>function</code>有变量提升会预解析提升，<code>var</code>只提升变量名不赋值，<code>function</code>提升整个函数，<code>function</code>的优先级比 <code>var</code>高如果同时 <code>function</code>和 <code>var</code>定义一个相同的变量名 <code>function</code>会将 <code>var</code>覆盖</p>
<hr />
<h1>函数中的参数</h1>
<h2>动态参数</h2>
<p>动态参数 <code>arguments</code>是函数内部内置的伪数组，可以通过 <code>for</code>循环递归，在箭头函数中无法使用</p>
<pre><code class="language-JavaScript">function nya(){
    console.log(arguments)
}
nya(1,2,3)
// Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]</code></pre>
<h2>剩余参数</h2>
<p>剩余参数使用三个英文句号加变量名 <code>…变量</code>来传参，是真数组，需要写在最后一个参数中，可以在箭头函数中使用，开发中提倡使用</p>
<pre><code class="language-JavaScript">function nya(...nyaw){
    console.log(nyaw)
}
nya(1,2,3)
// [1, 2, 3]</code></pre>
<hr />
<h1>展开运算符</h1>
<p>和剩余参数一样使用三个英文句号加变量名 <code>…变量</code> 可以展开为数组可以用于 <code>Math.max</code>等需要数值的地方</p>
<pre><code class="language-JavaScript">let arr = [1,2,3,4,5]
console.log (...arr) // 1 2 3 4 5</code></pre>
<hr />
<h1>This</h1>
<p><code>this</code> 指向函数的调用者，和函数的定义方式关系不大，箭头函数要另算应为箭头函数没有自己的 <code>this</code> 指向</p>
<ul>
<li>函数直接调用，<code>this</code> 会被指向 <code>window</code>，因为函数全局定义默认挂载在 <code>window</code> 所以相当于直接通过 <code>window</code> 来调用</li>
<li>函数添加给哪个对象调用 <code>this</code> 就会指向哪个对象，除了 <code>bind</code> 创建的修改 <code>this</code> 指向后的函数</li>
<li>通过 <code>new</code> 执行函数此时函数会被当做构造函数处理，<code>this</code> 会被指向示例对象</li>
<li>函数通过 <code>call</code> 调用 ，<code>call</code> 的第一个参数是 <code>this</code> 指向，<code>call</code> 的剩余参数为函数的实参</li>
<li>函数通过 <code>apply</code> 调用，<code>apply</code> 的第一个参数是 <code>this</code> 指向，<code>apply</code> 和 <code>call</code> 不同的是第二个参数为数组，数组的每一项是调用函数的实参</li>
<li>函数通过 <code>bind</code> 调用会获得一个改变 <code>this</code> 指向后的函数需要接收它然后再执行， <code>bind</code> 的第一个参数是 <code>this</code> 指向，第二个参数和 <code>apply</code> 相同是数组，通过 <code>bind</code> 创建的函数它的 <code>this</code> 指向会被永久改变，不会被指向调用者</li>
<li>箭头函数没有 <code>this</code> 指向，箭头函数中的 <code>this</code> 指向实际是上下文中的 <code>this</code></li>
</ul>
<hr />
<h1>箭头函数 ⭕</h1>
<p>可以用来替换匿名函数，箭头函数的语法比函数更加简洁，箭头函数中没 <code>this</code>将会往上级查找</p>
<ol>
<li>只有一个参数时可以省略小括号</li>
<li>只有一行代码时可以省略大括号以及无需写 <code>return</code></li>
<li>如果只有一行省略大括号的情况下返回对象或者数组时需要英文括号包裹</li>
<li>箭头函数中没有 <code>arguments</code>但是有剩余参数，使用三个英文句号加变量名 <code>…变量名</code></li>
<li>箭头函数中没有自己的 <code>this</code>会沿用上一层的 <code>this</code></li>
</ol>
<hr />
<h1>解构赋值 ⭕</h1>
<p>快速批量赋值给变量的简洁语法</p>
<h2>数组解构</h2>
<p>遵循一一对应原则，变量如果大于单元数量时，会返回 undefined。可以直接在[]内赋值，可以使用剩余参数吧多余的数组内的单元返回赋值给变量名</p>
<h3>基本语法</h3>
<p>将会把左侧的数组中的单元赋值给右侧的 <code>[]</code>变量名</p>
<pre><code class="language-JavaScript">let [a, b, c] = [114,514,1919] // a = 114 b=514 c=1919</code></pre>
<h3>多级</h3>
<p>根据一一对应原则如下</p>
<pre><code class="language-JavaScript">let [a, b, [c]] = [114,514[1919]] //a = 114 b=514 c=1919</code></pre>
<h3>数组交换</h3>
<p>开头必须加分号结束符</p>
<pre><code class="language-JavaScript">let a = 1
let b = 2
;[b,a]=[a,b]
console.log(a,b); // 2 1</code></pre>
<h2>对象解构</h2>
<p>对象中找不到变量名一致的属性名时返回 <code>undefined</code></p>
<h3>基本语法</h3>
<p>吧左侧对象中的属性名赋值给右侧 <code>{}</code>的变量名</p>
<pre><code class="language-JavaScript">let {userName} = {userName:'橘纸柚'}</code></pre>
<h3>多级</h3>
<p>多级对象中嵌套和数组解构差不多使用冒号':'来连接</p>
<pre><code class="language-JavaScript">let {userName,site:{blog}} = {
    userName: '橘纸柚',
    site: {
        blog: 'lovemen.cc'
    }
}</code></pre>
<h3>更名</h3>
<p>如果数组中的变量名已经被占用可以使用英文冒号进行更名</p>
<pre><code class="language-JavaScript">let {userName:MyName,site:{blog:BlogUrl}} = {
    userName: '橘纸柚',
    site: {
        blog: 'lovemen.cc'
    }
}</code></pre>
<hr />
<h1>逻辑短路</h1>
<p>如果左边短路右边的代码就不执行</p>
<p><code>&amp;&amp;</code>左边为 false 就短路
<code>||</code>左边为 true 就短路</p>
<hr />
<h1>创建对象的三种方法</h1>
<h2>字面量</h2>
<p>通过字面量来创建对象，这是最常用的方法</p>
<pre><code class="language-JavaScript">const obj = {uname: '橘纸柚'}</code></pre>
<hr />
<h2>new Object()</h2>
<p>通过 <code>new Object()</code>来创建函数，通过字面量创建时也会经过 <code>new Object()</code></p>
<pre><code class="language-JavaScript">const obj = new Object({uname:'橘纸柚'})</code></pre>
<hr />
<h2>构造函数 ⭕</h2>
<p>构造函数是一种特殊的函数，主要用来初始化对象，可以理解为是一个对象的模板可以用来创建多个类似的对象。JavaScript 实现面向对象需要借助于构造函数，直接创建方法存在浪费内存的问题。</p>
<h3>声明构造函数</h3>
<p>构造函数推荐驼峰命名法首字母开头大写用于与普通函数的区分，构造函数里的 <code>this</code>指向实例对象。推荐键的取名和形参相同。</p>
<pre><code class="language-JavaScript">function Nya(uname,age){
    this.uname = uname;
    this.age = age;
}</code></pre>
<h3>使用</h3>
<p>称之为实例化对象，构造函数通常和 <code>new</code>一起使用，实参的使用方法和普通函数一样没有传入实参则 <code>undefined</code></p>
<pre><code class="language-JavaScript">function Nya(uname,age){
    this.uname = uname;
    this.age = age;
}
const juzi = new Nya('JuziYou',18)</code></pre>
<h3>成员</h3>
<p>实例对象的成员称为实例成员，只有实例对象可以使用
构造函数的成员称为静态成员，只有构造函数可以使用</p>
<pre><code class="language-JavaScript">function Nya(uname,age){
    this.uname = uname;
    this.age = age;
}
const juzi = new Nya('JuziYou',18)
Nya.baka = 'YES'
console.log(juzi.baka) // undefined
console.log(Nya.baka) // YES
console.log(Nya.uname) // undefined</code></pre>
<h3>原型对象 ⭕</h3>
<p><code>prototype</code>是每一个构造函数都有的一个属性指向了一个对象称为原型对象，在原型中构造函数和实例中的 this 指向实例化对象。原型是所有当前构造函数 <code>new</code>出来的对象的方法，可以吧那些不变的方法都放在里面节省内存</p>
<pre><code class="language-JavaScript">function Nya(uname,age){
    this.uname = uname;
    this.age = age;
}
Nya.prototype.say = function(){
    console.log('Nya!');
}
const juzi = new Nya('JuziYou',18)
juzi.say() // 将会在控制台打印 Nya!</code></pre>
<hr />
<h1>内置构造函数</h1>
<p>其中的 <code>Boolean</code>、<code>String</code>、<code>Number</code>既是包装类型又是方法</p>
<h2>Object</h2>
<p><code>Object</code>是内置构造函数通常用于创建对象，不过推荐使用字面量来创建对象</p>
<p><strong>PS:</strong> <code>Object.prototype.toString.call(对象)</code> 可以获取一个对象的数据类型</p>
<h3>for(let key in obj){}</h3>
<p><code>for(let key in obj){}</code>用于遍历对象，'let key'的'key'为成员的键值，'obj'是目标数组</p>
<h3>Object.keys</h3>
<p><code>Object.keys(obj)</code>将会返回一个真数组</p>
<pre><code class="language-JavaScript">const nya = {
    name: 'JuziYou',
    age: 18
}
console.log(Object.keys(nya)); // ['name', 'age']</code></pre>
<h3>Object.values</h3>
<p><code>Object.values(obj)</code>将会返回一个真数组</p>
<pre><code class="language-JavaScript">const nya = {
    name: 'JuziYou',
    age: 18
}
console.log(Object.values(nya)); // ['JuziYou', 18]</code></pre>
<h3>Object.assign</h3>
<p><code>Object.assign(obj,{key:value})</code>常用于数组拷贝也可以用于成员的添加</p>
<pre><code class="language-JavaScript">const nya = {
    name: 'JuziYou',
}
const nya2 = {
    age: 18
}
console.log(Object.assign(nya,nya2)); // {name: 'JuziYou', age: 18}
console.log(Object.assign(nya,nya2,{baka:'YES'})); // {name: 'JuziYou', age: 18, baka:'YES'}</code></pre>
<h3>Object.create</h3>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create">MDN文档</a>
根据现有的对象 A 来创建一个 <code>prototype</code> 为对象 B 的对象，新对象 A 的 <code>prototype</code> 拥有所有对象 A 的属性和方法，一般只用一个参数就是传入对象 A</p>
<pre><code class="language-JavaScript">// 示例 一个对象需要数组的 prototype
const newObj = Object.create(Array.prototype)</code></pre>
<h3>Object.setPrototypeOf</h3>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf">MDN文档</a>
用于修改对象的 <code>prototype</code> 指向，第一个参数是需要修改的对象，第二个参数为指向的 <code>prototype</code></p>
<pre><code class="language-JavaScript">// 示例 一个对象 prototype 需要指向到数组的 prototype
const obj = {}
Object.setPrototypeOf(obj, Array.prototype)</code></pre>
<h2>Array</h2>
<p><code>Array</code>是内置的构造函数用于创建数组，不过推荐使用字面量创建数组</p>
<table>
<thead>
<tr>
<th>方法</th>
<th>作用</th>
</tr>
</thead>
<tbody>
<tr>
<td>.push()</td>
<td>向数组尾部添加一个单元</td>
</tr>
<tr>
<td>.unshit()</td>
<td>向数组头部添加一个单元</td>
</tr>
<tr>
<td>.pop()</td>
<td>删除数组最后一个单元</td>
</tr>
<tr>
<td>.shift()</td>
<td>删除数组第一个单元</td>
</tr>
<tr>
<td>.splice(索引开始值, 删除单元数,追加单元)</td>
<td>从索引开始值的位置删除n个单元数</td>
</tr>
<tr>
<td>.reverse()</td>
<td>吧数组排序颠倒</td>
</tr>
</tbody>
</table>
<h3>Array.from()</h3>
<p><code>Array.from()</code>可以将为数组转换为数组，转换对象必须带 <code>length</code>。<code>length</code>如果小于数量将会略去后面的，如果多余数量将会写入 <code>undefined</code></p>
<h3>Array.isArray</h3>
<p>判断一个对象是否为数组，返回一个布尔值</p>
<pre><code class="language-JavaScript">Array.isArray([]) // true
Array.isArray({}) // false</code></pre>
<h3>reduce</h3>
<p><code>reduce</code>返回函数累计处理的结果通常用于求和等</p>
<p>索引号和原数组为可选变量。起始值如果不写将会使用数组的第 0 个值并且从第二个值开始遍历</p>
<pre><code class="language-JavaScript">arr.reduce(function(累计值prev, 当前元素item, 索引号index, 原数组original){}, 起始值)</code></pre>
<h3>forEach</h3>
<p><code>forEach</code>用于遍历数组，不会返回，通常用于遍历、输出、打印值。索引号和原数组为可选变量</p>
<pre><code class="language-JavaScript">arr.forEach(function(当前元素item, 索引号index, 原数组original){})</code></pre>
<h3>filter</h3>
<p><code>filter</code>用于遍历筛选数组，<code>return</code>会返回值可以声明一个变量接收。索引号和原数组为可选变量</p>
<pre><code class="language-JavaScript">arr.filter(function(当前元素item, 索引号index, 原数组original){})</code></pre>
<h3>map</h3>
<p><code>map</code>用于迭代数组，经常用于处理数据，<code>return</code>会返回值可以声明一个变量接收。索引号和原数组为可选变量</p>
<pre><code class="language-JavaScript">arr.map(function(当前元素item, 索引号index, 原数组original){})</code></pre>
<h3>join</h3>
<p><code>join</code>用于吧数组转化为字符串。索引号和原数组为可选变量</p>
<pre><code class="language-JavaScript">let arr = [1,2,3,4,5]
console.log(arr.join('')) // 12345
console.log(arr.join('/')) // 1/2/3/4/5</code></pre>
<h3>find</h3>
<p><code>find</code>将会查找符合条件的第一个元素，如果找不到将会返回 <code>undefined</code>。比如数组 <code>[1,1,4,5,1,4]</code>查找 <code>4</code>将会循环到下标 3 的 4 后结束，查找 <code>9</code>将会返回 undefined</p>
<pre><code class="language-JavaScript">arr.find(function(元素值、元素的索引，原数组){})</code></pre>
<h3>some</h3>
<p><code>some</code>将会检查数组中是否有任意一个符合条件返回布尔值，不符合将会返回 <code>false</code>符号将会返回 <code>true</code>。</p>
<pre><code class="language-JavaScript">arr.some(function(元素值，元素的索引，原数组){})</code></pre>
<h3>every</h3>
<p><code>every</code>将会查找数组是否都符合条件返回布尔值，不符合将会返回 <code>false</code>符号将会返回 <code>true</code>。</p>
<pre><code class="language-JavaScript">arr.every(function(元素值，元素的索引，原数组){})</code></pre>
<h3>sort</h3>
<p><code>sort</code>比对重排数组，返回后会直接重排数组</p>
<p>比如：<code>a</code>和 <code>b</code>为对比的两个值</p>
<pre><code class="language-JavaScript">arr.every(function(a,b){return a - b})</code></pre>
<h3>at</h3>
<p><code>at</code> 接收一个整数为参数可以是正整数也可以是负整数，正整数与下标获取相同，负整数从 <code>-1</code> 开始从数组中最后一个元素开始</p>
<pre><code class="language-JavaScript">const arr = [1,2,3,4,5]
console.log(arr.at(0)) // 1
console.log(arr.at(-1)) // 5</code></pre>
<h2>String</h2>
<ol>
<li><code>length</code>获取字符串的长度，如 <code>'JuziYou'.length</code>将会得到 <code>7</code></li>
<li><code>split(分隔符)</code>将会吧字符串转换为数组，如 <code>'Neko_Nya'.split('_')</code>将会得到数组 <code>['Neko','Nya']</code>,如果分隔符为空字符串 <code>''</code>将会吧每个字符转换为数组，如 <code>'橘纸柚'.split('')</code>将会得到数组 <code>['橘','纸','柚']</code></li>
<li><code>substring(起始索引,结束索引)</code>用于字符截取，如 <code>'123456'.substring(2,4)</code>将会截取字符串 <code>34</code>。如果只有一个参数将会截取起始索引之后的全部字符如 <code>'123456'.substring(2)</code>将会得到字符串 <code>3456</code></li>
<li><code>startsWith(检测字符串,检测位置索引号)</code>用于检测是否为某串字符开头，检测位置索引号为可选项将会从此索引号开始检测忽略之前的，将会返回布尔值。</li>
<li><code>includes(搜索字符串,检测位置索引号)</code>判断一个字符串是否包含在另一个字符串中，检测位置索引号为可选项，将会返回布尔值</li>
</ol>
<h2>Number</h2>
<p><code>toFixed(保留字符串位数)</code>设置保留小数位的长度，如设置为 <code>2</code>将会保留两位，四舍五入</p>
<hr />
<h1>Ajax</h1>
<h2>常见状态码</h2>
<table>
<thead>
<tr>
<th>状态码</th>
<th>描述</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>200</td>
<td>OK</td>
<td>请求成功</td>
</tr>
<tr>
<td>201</td>
<td>Created</td>
<td>资源在服务器端已成功创建</td>
</tr>
<tr>
<td>400</td>
<td>Bad Request</td>
<td>客户端请求方式或者参数错误</td>
</tr>
<tr>
<td>401</td>
<td>Unauthorized</td>
<td>客户端身份认证不通过</td>
</tr>
<tr>
<td>404</td>
<td>Not Found</td>
<td>客户端请求的资源不存在</td>
</tr>
<tr>
<td>500</td>
<td>Internal Server Error</td>
<td>服务器内部错误</td>
</tr>
</tbody>
</table>
<h2>Axios</h2>
<p>Axios 是一个基于 promise 的网络请求库，可以方便的完成 ajax 请求
官方文档地址：<a href="https://axios-http.com/zh/docs/intro">https://axios-http.com/zh/docs/intro</a></p>
<h3>基地址</h3>
<p><code>axios.defaults.baseURL</code>设置基地址</p>
<pre><code class="language-JavaScript">axios.defaults.baseURL = 'https://api.uuz.bid'</code></pre>
<h3>常用写法</h3>
<p><code>method</code>设置请求方式如 <code>GET</code>、<code>POST</code>
<code>url</code>设置请求地址如果设置了基地址直接写地址即可如 <code>/api/nya</code>/<code>api/nya</code>
<code>method</code>为 <code>GET</code>时使用 <code>params</code>写请求参数
<code>method</code>为 <code>POST</code>时使用 <code>data</code>写请求参数
<code>headers</code>设置请求头</p>
<p>如：</p>
<pre><code class="language-JavaScript">axios({
    method:'GET', // 发送GET请求
    url:'/userdata', // 请求地址（设置了基地址）
    params:{
      uname: userName // 发送载荷
    },
    headers: {
      Authorization: token // 服务器需要Authorization请求头验证token
    }
}).then(res=&gt;{
    console.log(res.data); // 没有错误
}).catch(err=&gt;{
    console.log(err); // 有错误
})</code></pre>
<h2>XMLHttpRequest()</h2>
<p>这是原生的 Ajax 方式，不过实际中都用请求库比较多所以就简单记一下
MDN 传送门：<a href="https://developer.mozilla.org/zh-CN/docs/Glossary/AJAX">https://developer.mozilla.org/zh-CN/docs/Glossary/AJAX</a></p>
<pre><code>const xhr = new XMLHttpRequest() // NEW 一个 XMLHttpRequest()
xhr.open('GET','https://api.uuz.bid/random/?json=y') // GET请求数据
xhr.onload = function(){ //准备接受数据
    console.log(xhr.responseText); //打印返回的数据
}
xhr.send() //发送请求</code></pre>
<hr />
<h1>Promise</h1>
<p><code>Promise</code>是一个构造函数，可以通过 <code>new</code>创建一个 <code>Promise</code>实例对象，代表一个异步的操作</p>
<h2>语法</h2>
<p><code>Promise</code>构造函数包含一个参数带有两个回调值 <code>resolve</code>（解析）和 <code>reject</code>（拒绝）
如果正常则调用 <code>resolve</code>，否则调用 <code>reject</code></p>
<pre><code class="language-JavaScript">const np = new Promise((resolve, reject) =&gt; {})</code></pre>
<p><code>.then()</code>方法用来预先指定成功和失败的回调函数，失败的回调函数为可选
<code>return</code>的返回值可以是<code>Promise</code>对象也可以是具体的值，但是都会被处理成<code>Promise</code>方便后面的链式调用
形参<code>resolve()</code>和<code>reject()</code>的传参将会传到<code>.then()</code>里的函数内
<code>.catch()</code>捕获错误，参数为一个函数回调值<code>err</code>（错误）</p>
<p>如：</p>
<pre><code class="language-JavaScript">const np = new Promise((resolve, reject) =&gt; {
    resolve('juzi')
}).then(
    res=&gt;{
        console.log(res) // 控制台打印juzi
        return 'Nya'
    }
).then(
    res=&gt;{
    console.log(res) // 控制台打印Nya
}
).catch(err=&gt;{
    console.log(err)
})</code></pre>
<h2>中断 Promise 链</h2>
<p>直接 <code>return new Promise(()=&gt;{})</code>返回一个初始的 Promise 实例</p>
<h2>Promise.all()</h2>
<p>回并行发起 <code>Promise</code> 异步操作，全部的操作结束后才会下一步的 <code>.then()</code></p>
<pre><code class="language-javascript">const promiseAll = [
   axios({method: 'GET',url: 'XXXXXX'}),
   axios({method: 'GET',url: 'XXXXXX'}),
   axios({method: 'GET',url: 'XXXXXX'})
]
Promise.all(promiseAll).then(res =&gt; {
    console.log(res)
}).catch(err =&gt; {
    console.log(err)
})</code></pre>
<h2>Promise.allSettled</h2>
<p>和 <code>Promise.all</code> 差不多，只不过它无论成功失败都会返回一个成功状态的 <code>Promise</code></p>
<h2>Promise.race()</h2>
<p>回并行发起 <code>Promise</code> 异步操作，只要有任意一个返回了值就立即进入下一步 <code>.then()</code></p>
<pre><code class="language-javascript">const promiseAll = [
   axios({method: 'GET',url: 'XXXXXX'}),
   axios({method: 'GET',url: 'XXXXXX'}),
   axios({method: 'GET',url: 'XXXXXX'})
]
Promise.race(promiseAll).then(res =&gt; {
    console.log(res)
}).catch(err =&gt; {
    console.log(err)
})</code></pre>
<h2>Promise.any</h2>
<p>和 <code>Promise.all</code> 差不多，它可以获取到异步处理成功最快的那一个</p>
<hr />
<h1>async await</h1>
<p><code>async</code> <code>await</code> 相当于是 Generator 的语法糖，它可以解决回调地狱问题，写起来也比 <code>Promise</code>更清楚，<code>await</code>必须在 <code>async</code>的函数内，错误需要使用 <code>try</code> <code>catch</code> 来获取</p>
<ul>
<li><code>async</code> 相当于修饰  <code>await</code> 就近的函数，被 <code>async</code> 修饰的函数会变成一个 <code>Promise</code>，如果内部 <code>return</code> 一个数据也会被 <code>Promise</code> 包装 <code>resolve</code></li>
<li><code>await</code> 一般用于修饰 <code>Promise</code> 如果不是就会吧后面的内容包装为 <code>Promise</code> 的 <code>resolve</code>，下面的代码相当于放在了 <code>.then</code> 的成功回调中，所以 <code>await</code> 相当于微任务</li>
</ul>
<pre><code class="language-JavaScript">// 比如await从API里取用户数据并打印
(async () =&gt; {
    const userData = await axios({
        method: 'GET',
        url: '/user',
        params: {
            user: 'JuziYou'
        }
    })
    try {
        console.log(userData.data)
    } catch (err) {
        console.log(err.response.data.message)
    }
})()</code></pre>
<hr />
<h2>Generator</h2>
<p>Generator 是 ES6 的，作用是将函数暂停交出控制权，是一种异步的解决方案  <code>async</code> <code>await</code> 相当于是它的语法糖，只要在函数声明和函数名中间加 <code>*</code> 那就是一个 Generator 函数，会在函数内的 <code>yield</code> 暂停它的返回值是外面调用 <code>.next()</code> 传入的值， <code>yield</code> 后跟随的值会被传出去到 <code>.next()</code> 返回值的 <code>value</code>，需要一个常量接收函数返回的 Generator 实例，然后使用 <code>常量名.next()</code> 就会向下执行，可以通过返回值的 <code>done</code> 确认是否完成</p>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://lovemen.cc/moe2069.html#comments</comments>
</item>
<item>
<title>犹如暑假工的一份工作</title>
<link>https://lovemen.cc/moe2062.html</link>
<guid isPermaLink="false">https://lovemen.cc/moe2062.html</guid>
<pubDate>Fri, 05 Aug 2022 12:32:00 +0800</pubDate>
<dc:creator>橘纸柚</dc:creator>
<category><![CDATA[闲聊]]></category>
<description><![CDATA[因为我想躺所以没和同学一样去杭州去上海闯闯。我就毕业后马上回家先咸鱼躺了半个月，也搞笑我想去哪里，哪里就有疫情又不敢去，毕业旅行也没完成。
第一份工作啊，真的没什么好找的，我住的这破地方虽然叫 “中国电器之都” 也没什么愿意招没有实际操作经验的电商部的公司...]]></description>
<content:encoded><![CDATA[
<!--markdown-->因为我想躺所以没和同学一样去杭州去上海闯闯。我就毕业后马上回家先咸鱼躺了半个月，也搞笑我想去哪里，哪里就有疫情又不敢去，毕业旅行也没完成。
<p>第一份工作啊，真的没什么好找的，我住的这破地方虽然叫 “中国电器之都” 也没什么愿意招没有实际操作经验的电商部的公司。可能是吴总看我学习经历写温州大学吧所以要了，然后就第一份工作月薪 3200 没提成的死工资，这可能就是导致后来发生变化的主要原因吧。
公司离我家就 6KM 远天天开着我的小电驴上下班而且技术部只要客户不催几乎没有加班八点上班六点下班，摸一摸一天也就过去了，挺咸。虽然他们也算是个互联网企业，但是我所在的技术部其实工作节奏平时都挺佛系的，所以可以经常看到我在水推水群，只要不碰上有坑的客户一切都好说。同事也很好天天有说有笑的。
我的工牌上印着 “前端设计师” 前端设计到哪里去了呢？平时更多客户资料我整理录入，名片、工牌、海报、宣传物料也是我设计打印机、电脑也是我修，部分页面 HTML 和 CSS 也是我写，我觉得应该给我改成 “全干工程师” 更适合。标题 banner 背景图就是我的夹带私货~
最后不过不得不吐槽一下您乐还自己开了个和温州人才网单独运行的人才网让我找工作转了不少弯路。
为什么要离职呢，就是因为我父上大人觉得就 3200 的死工资太少了，然我继续去学习几个月，我说不过他然后就从咯。总之变化总比计划快，挺对不起吴总的，两个月前跟他说 “干到年底没问题” 没想到变化那么快才两个月多点刚转正就提了离职。</p>
]]></content:encoded>
<slash:comments>4</slash:comments>
<comments>https://lovemen.cc/moe2062.html#comments</comments>
<enclosure url="https://cdn.sa.net/2025/03/03/78k2UwJxW6hly59.jpg" length="0" type="image/jpeg" />
</item>
<item>
<title>畢業</title>
<link>https://lovemen.cc/moe2034.html</link>
<guid isPermaLink="false">https://lovemen.cc/moe2034.html</guid>
<pubDate>Sun, 22 May 2022 00:02:00 +0800</pubDate>
<dc:creator>橘纸柚</dc:creator>
<category><![CDATA[闲聊]]></category>
<category><![CDATA[毕业]]></category>
<description><![CDATA[我们可能是目前最悲的一届了吧，校招？没有...毕业典礼？没有...最后一门考试前一天收拾完宿舍。第二天来到已经被整理的干干净净的那好似熟悉的教室开始考试，早上就考了一门，一切就像是一场期末考。
然而本应很快结束的毕业照拍摄因为摄影师给堵在校外进不来需要等，...]]></description>
<content:encoded><![CDATA[
<!--markdown-->我们可能是目前最悲的一届了吧，校招？没有...毕业典礼？没有...最后一门考试前一天收拾完宿舍。第二天来到已经被整理的干干净净的那好似熟悉的教室开始考试，早上就考了一门，一切就像是一场期末考。
<p>然而本应很快结束的毕业照拍摄因为摄影师给堵在校外进不来需要等，于是我开始打听起了约车小面和中面选哪一个，因为博主有很多东西要带回家，父母也没空上来接，好在家比较近就二十千米所以直接跟车貌似也是划算的选择。突然时间还多于是我就开始了整活，套上了早上从宿舍带来了假发，和同学相互迫害，拍下了在这读了几年大学第一次和女同学的主动合照。
在两个小时后摄影师终于来了，给我们拍了一张集体照。然后学校给了我们一个毕业礼物，终于可以回到寝室收拾回家了。
走出教室预约了十二点的中面，骑上电瓶车赶快回去搬行李，因为疫情防控不让开进寝室需要提前搬到宿舍区门口，赶快回去提前搬出来等车来。
到了宿舍区先去小卖部买了一包燕麦酥和元气森林补一下早饭，回到宿舍楼交钥匙退押金，室友和同学帮忙吧我要带回去的一堆行李和两辆电瓶车一起运出了宿舍区，我应该是全班第一个走的吧，回到寝室呆了十多分钟就跑了。
早点...也好，浪费了两年的时光呢，那也去不了甚至最后一学期连学校都出不了，本想着大学最后这两年应该没什么课，确实没什么课，好好玩玩，玩什么那也玩不了，也就在寝室天天摸摸鱼划划水也没做什么事浪费过去了。交到了很多网友想毕业了就可以见面呢，不过目前的状况毕业了也见不了欸。
总之结束了，无趣的校园生活，来也匆匆去也匆匆。</p>
]]></content:encoded>
<slash:comments>12</slash:comments>
<comments>https://lovemen.cc/moe2034.html#comments</comments>
<enclosure url="https://cdn.sa.net/2025/03/03/Sr97YlayhmFuVJs.jpg" length="0" type="image/jpeg" />
</item>
<item>
<title>关于我双十一搬砖那件事</title>
<link>https://lovemen.cc/moe2005.html</link>
<guid isPermaLink="false">https://lovemen.cc/moe2005.html</guid>
<pubDate>Sun, 21 Nov 2021 22:03:00 +0800</pubDate>
<dc:creator>橘纸柚</dc:creator>
<category><![CDATA[闲聊]]></category>
<description><![CDATA[时间过得真快明年就毕业了呢！所以大学毕业前必做的一件事实习也来了呢！
首先我吐槽下这破学校，如果是自己找工作就给我二十几天你让我去哪里找这相关工作？只好老老实实跟着学校的安排，就很 GaN。
10/28
中午收拾了一下学校的寝室，带着我的鲨鲨冲锋！下午来到...]]></description>
<content:encoded><![CDATA[
<!--markdown-->时间过得真快明年就毕业了呢！所以大学毕业前必做的一件事实习也来了呢！
<p>首先我吐槽下这破学校，如果是自己找工作就给我二十几天你让我去哪里找这相关工作？只好老老实实跟着学校的安排，就很 GaN。</p>
<h2>10/28</h2>
<p>中午收拾了一下学校的寝室，带着我的鲨鲨冲锋！下午来到了公司第一印象还好，打扫完寝室发现宿舍有给厨房，没有吧学校宿舍里的锅带过来失算了。
然后晚饭去了食堂，哦我的上帝这菜煮的太糟糕了！您司食堂的盐和辣椒好似不要钱，这菜真是又咸又辣，点了两盘靠北就那一盘金瓜我还能勉强吃吃。
最后补给了一点点零食摸了一会儿鱼这一天结束了~
<img src="https://cdn.sa.net/2025/03/03/K8mkFxrPvHhDpfE.jpg" alt="10月28日" /></p>
<h2>10/29</h2>
<p>您司早饭其实还行比晚饭午饭清淡多了呢~
然后去了会议室做了入职登记，下午去了仓库电商仓主管和我们说了接下来要做什么，总结就是好好搬砖嘛~
然后参观了一下自动化还没做完的电商仓。</p>
<h2>10/30~31</h2>
<p>上岗培训，搬砖嘛这还需要什么培训，挺轻松的没什么好说就那样。然后我感冒了，靠北哦还没怎么上班就先花了一百多看感冒，这边的医院也真滴坑。陪我一起去看病的同学也说这医院视钱如命。给我开了一堆药然后我只买了平时我感冒常吃的药，如果药店可以买感冒药就没这点破事了。</p>
<h2>11/01~02</h2>
<p>双十一第一波来啦！相比前两天培训，强度一下子就上来咯。虽然公司给包饭吧，但是这食堂的菜盐跟不要钱一样，狗看了都摇摇头。A 区和 F 区那箱子堆得比我还高还得爪巴爪巴才能拿到，一直干到了十一点才下班，和朋友去十足坑的十足买了便当。十月二号也差不多，不过明天就调到退货仓去摸了所以今天没什么干劲明天继续努力。
<img src="https://cdn.sa.net/2025/03/03/pPMN8kdqH1Yl6o3.jpg" alt="双十一第一天" /></p>
<h2>11/03~08</h2>
<p>我来到了退货仓，哦一下子强度又下来了。耍了一早上美工刀拆快递，不过玩刀一时爽不要乱飞啊！退货仓这边的食堂很棒味道刚刚好，还有下午茶时间给的还是小饼干可乐雪碧还有一次是 KFC，我还能玩一小会儿 Switch 哦这可太行了。晚上回到寝室就我和另外一个室友其他同学都在发货仓加班，退货仓唯独加班两次还只加班两个小时到点立马下班不管还有没有未处理。
<img src="https://cdn.sa.net/2025/03/03/yFQBsprExqvTUom.jpg" alt="快乐退货仓" /></p>
<h2>11/09~10</h2>
<p>经过了退货仓 5 天的修身养性（大雾）双十一当天还是要回到发货仓的。所以九号和十号我调休，虽然说退货仓强度没那么高，但是还是累的，所以我申请休息了两天，在公司边上逛逛，就这样愉快的摸了两天。公司边上的猫猫真可爱！
<img src="https://cdn.sa.net/2025/03/03/FsON31bJHxdCcZt.jpg" alt="摸鱼休息" /></p>
<h2>11/11</h2>
<p>这可能是我作息最不规律的一天，因为我调班成了夜班，当然不是那个夜班这里的夜班是指 0 点到 8 点然后 20 点到 23 点反正加班是跑不了的（毕竟发货仓）。不过红牛管够，虽然这种饮料喝完后我喉咙超级难受我也不太想喝就是了只拿了一瓶然后买了瓶咖啡，早饭哇那个包子吃完我胃难受到下班，太油了。不过今天发货仓的饭菜还不错，辅导员给我们送了一些华莱士（草）。而且今天有可爱的工贸学院的同学在我滴天哪货乱拿，经常我要拿货的地方空着我货呢？？？加班结束后买了瓶健力宝和一包三明治。
<img src="https://cdn.sa.net/2025/03/03/TMSjFsftW7kLQBU.jpg" alt="夜班人" /></p>
<h2>11/12~14</h2>
<p>双十一结束后第一天我给调到了流水线看机器有没有出 BUG 按急停了等师傅过来“debug（物理）”。然后第二天我就去继续分拣货物，一直干到了 14 号也没什么意思就这样吧
<img src="https://cdn.sa.net/2025/03/03/CMwhxJiD8ejaOYV.jpg" alt="摸摸摸" /></p>
<h2>11/15</h2>
<p>今天不上班，终于可以滚蛋了，整理了一早上的寝室内务。中午去退货仓食堂吧饭卡里的钱全刷完，然后去发货仓的食堂吧那边饭卡的钱全刷完，刷了不少饮料带走。下午三点到了学校，还好机智的我吧电瓶车停在了教室里不用慢慢拎着行李回去，到了寝室后整理学校的寝室，然后电脑给室友震刀了我在床上躺鱼。
<img src="https://cdn.sa.net/2025/03/03/315Q8ngYWurtDmK.jpg" alt="Back Home" /></p>
<h2>最后吐槽</h2>
<p>我天天搬砖什么还得天天写实习日志和一篇大的实习总结？您让我怎么写？“日志：搬砖，反思：累”？还要拍 Vlog？我都那么累那么忙了每天生活基本重复的拍什么，还一天一个？我能给你剪一个总的就不错了欸！
我他喵硬挤出来也不够只好加一堆狗屁不通文章生成器的内容塞在里面...（大雾）
还有作业我服了，我上班累死了，回来还得写两篇期中作业小论文，有毒吧？我 Switch 都不想碰了还让我写论文您？</p>
<p>抱歉咕咕了那么久本来想在实习总结大会结束后再发的，但是学校一直拖，我好不容易肝好的总结结果三四周了还不用交。本想阴阳怪气的，但是没意义算了吧。然后贵司都把我们工资调低了说给我们算完就发都快一个月了您司居然工资还没发，草（双语）</p>
]]></content:encoded>
<slash:comments>6</slash:comments>
<comments>https://lovemen.cc/moe2005.html#comments</comments>
<enclosure url="https://cdn.sa.net/2025/03/03/QNtIZSVr7Hdmp4F.jpg" length="0" type="image/jpeg" />
</item>
</channel>
</rss>
