<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0"><channel><title>無.Flac's Blog</title><link>https://w-flac.org.cn</link><atom:link href="https://w-flac.org.cn/rss.xml" rel="self" type="application/rss+xml"/><description>無.Flac's Blog</description><generator>Halo v2.22.13</generator><language>zh-cn</language><image><url>https://w-flac.org.cn/upload/icon.jpg</url><title>無.Flac's Blog</title><link>https://w-flac.org.cn</link></image><lastBuildDate>Mon, 16 Mar 2026 16:45:18 GMT</lastBuildDate><item><title><![CDATA[NOVUS主题开发日志]]></title><link>https://w-flac.org.cn/2025/theme-novus</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=NOVUS%E4%B8%BB%E9%A2%98%E5%BC%80%E5%8F%91%E6%97%A5%E5%BF%97&amp;url=/2025/theme-novus" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">MEGO主题暂时告一段落，剩下的只是维护更新啦，接下来我将开发不同类型的主题以丰富Halo生态环境，接下来到来的是一款基于企业主题，命名为NOVUS。</p>
</blockquote>
<h2 style="" id="%E4%BB%8B%E7%BB%8D">介绍</h2>
<p style="">NOVUS，一个专为 Halo 而生的服务型企业主题。以简洁大气的视觉语言，快速构建「公司介绍、服务展示、资讯发布、客户对接」四大核心场景；模块化布局+可视化设置，让用户在瞬息万变的市场环境中，零代码上线专业站点，轻松传递品牌价值，赢得客户信任。</p>
<h2 style="" id="%E6%9E%84%E6%83%B3">构想</h2>
<h4 style="" id="%E9%A1%B6%E9%83%A8%E9%80%9A%E7%9F%A5%EF%BC%9D%E6%B5%81%E9%87%8F%E6%94%B6%E5%89%B2%E6%9C%BA">顶部通知＝流量收割机</h4>
<p style="">横幅一挂，活动、白皮书、直播随时上线；后台 5 秒改字，手机端自动适配。用户点「X」仅当前页面隐藏，刷新后再次露出，短期强提醒不丢失。</p>
<h4 style="" id="%E5%AF%BC%E8%88%AA%E8%8F%9C%E5%8D%95%EF%BC%9D%E5%B7%A6%E4%BE%A7%E9%A2%86%E8%B7%AF%E3%80%81%E5%8F%B3%E4%BE%A7%E8%A1%8C%E5%8A%A8">导航菜单＝左侧领路、右侧行动</h4>
<p style="">左侧 Logo 与一级菜单并排，右侧登录/注册/搜索一键开关，图标文字双模式。Hero 大图全程无遮挡。</p>
<h4 style="" id="hero-%E6%A8%A1%E5%9D%97%EF%BC%9D%E8%87%AA%E5%8A%A8%E8%BD%AE%E6%92%AD%E5%A4%A7%E7%89%87%E4%BB%93">Hero 模块＝自动轮播大片仓</h4>
<p style="">Banner 设定秒级间隔即自动循环；无文字遮挡，只有纯净视觉。每张图可独立跳转，30 秒完成“年度故事连播”，访客一眼沉浸，品牌气场直接拉满。</p>
<p style=""></p>
<p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fnov.jpeg&amp;size=m" alt="nov.jpeg" width="100%" height="100%" style="display: inline-block"></p>
<p style="text-align: center">未完待续…</p>
<p style=""></p>]]></description><guid isPermaLink="false">/2025/theme-novus</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fpng%2520%281%29.avif&amp;size=m" type="image/jpeg" length="473846"/><category>日志</category><pubDate>Mon, 27 Oct 2025 06:16:24 GMT</pubDate></item><item><title><![CDATA[Mac系统开发环境配置]]></title><link>https://w-flac.org.cn/2025/mac-development-setup</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=Mac%E7%B3%BB%E7%BB%9F%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE&amp;url=/2025/mac-development-setup" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">本文将针对 Mac 上进行常见的 Homebrew、Node.js、Git 等的基本安装与环境配置。</p>
</blockquote>
<h3 style="" id="%E4%B8%80%E3%80%81homebrew">一、Homebrew</h3>
<p style="">打开终端，执行以下命令来安装 Homebrew：</p>
<pre><code class="language-auto">/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"</code></pre>
<blockquote>
 <p style="">友情提示：根据命令安装即可，镜像加速推介选择 <code>中科大国内源</code> 。</p>
</blockquote>
<p style="">检查 Homebrew 是否成功安装：</p>
<pre><code>brew --version</code></pre>
<h3 style="" id="%E4%BA%8C%E3%80%81node.js">二、Node.js</h3>
<h4 style="" id="-%3E%E5%AE%89%E8%A3%85">-&gt;安装</h4>
<p style="">使用 Homebrew 安装 <code>Node.js</code>：</p>
<pre><code>brew install node
</code></pre>
<p style="">安装完成后，验证安装是否成功：</p>
<pre><code>node -v
npm -v</code></pre>
<p style="">如果需要使用 pnpm（比 npm 更快速的包管理工具），可以使用以下命令安装：</p>
<pre><code>brew install pnpm</code></pre>
<h4 style="" id="-%3E%E9%85%8D%E7%BD%AE">-&gt;配置</h4>
<p style="">淘宝镜像源</p>
<pre><code># NPM
npm config set registry https://registry.npmmirror.com/

# PNPM
pnpm config set registry https://registry.npmmirror.com/

## 还原
npm config set registry https://registry.npmjs.org/
pnpm config set registry https://registry.npmjs.org/</code></pre>
<p style="">配置代理</p>
<pre><code># NPM
npm config set proxy http://127.0.0.1:10000
npm config set https-proxy http://127.0.0.1:10000

npm config delete proxy
npm config delete https-proxy

# PNPM
pnpm config set proxy http://127.0.0.1:10000
pnpm config set https-proxy https://127.0.0.1:10000

pnpm config delete proxy
pnpm config delete https-proxy</code></pre>
<h3 style="" id="%E4%B8%89%E3%80%81git">三、Git</h3>
<h4 style="" id="-%3E%E5%AE%89%E8%A3%85-1">-&gt;安装</h4>
<p style="">使用 Homebrew 安装 <code>Git</code>：</p>
<pre><code>brew install git</code></pre>
<p style="">配置 <code>Git</code> 用户名和邮箱：</p>
<pre><code>git config --global user.name "Your Name"
git config --global user.email "youremail@example.com"
</code></pre>
<p style="">验证安装：</p>
<pre><code>git --version</code></pre>
<h4 style="" id="-%3E%E9%85%8D%E7%BD%AE-1">-&gt;配置</h4>
<pre><code># 配置全局代理
git config --global http.proxy http://127.0.0.1:10000
git config --global https.proxy http://127.0.0.1:10000

# 配置 Github 代理
git config --global http.https://github.com/.proxy http://127.0.0.1:10000 # 配置 Github 代理
git config --global https.https://github.com/.proxy http://127.0.0.1:10000 # 配置 Github 代理

# 删除代理配置
git config --global --unset http.proxy 
git config --global --unset https.proxy </code></pre>
<hr>
<h3 style="" id="%E5%9B%9B%E3%80%81%E5%85%B6%E4%BB%96">四、其他</h3>
<p style="">新环境开发环境构建时， <code>pnpm</code> 默认会忽略一些构建脚本，除非你明确批准它们。</p>
<blockquote>
 <p style="">Ignored build scripts: @tailwindcss/oxide, esbuild.
  <br>
  Run "pnpm approve-builds" to pick which dependencies should be allowed to run scripts.</p>
</blockquote>
<pre><code># 按照提示选择即可
pnpm approve-builds</code></pre>
<h3 style="" id="%E4%BA%94%E3%80%81%E6%80%BB%E7%BB%93"><strong>五、总结</strong></h3>
<p style="">配置 Mac 开发环境时，使用 <code>Homebrew</code> 可以大大简化安装和管理工具的过程。通过安装和配置这些常用开发工具，你可以快速开始你的开发工作。记得根据自己的项目需求调整工具和环境设置，并定期更新工具和依赖库。</p>]]></description><guid isPermaLink="false">/2025/mac-development-setup</guid><dc:creator>無.Flac</dc:creator><category>日志</category><pubDate>Fri, 10 Oct 2025 15:54:41 GMT</pubDate></item><item><title><![CDATA[Hello,VUE 3!]]></title><link>https://w-flac.org.cn/2025/hello-vue-3</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=Hello%2CVUE%203%21&amp;url=/2025/hello-vue-3" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">Vue 3 是一款轻量、高效、易用的前端框架，提供现代化的开发体验和强大的生态，用于快速构建交互式网页应用。</p>
</blockquote>
<h2 style="" id="%E5%88%9B%E5%BB%BAvue%E5%B7%A5%E7%A8%8B">创建VUE工程</h2>
<blockquote>
 <p style="">点击查看<a href="https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create">官方文档</a></p>
</blockquote>
<pre><code class="language-bash">## 1.创建命令
npm create vue@latest

## 2.具体配置
## 配置项目名称
√ Project name: vue3_test
## 是否添加TypeScript支持
√ Add TypeScript?  Yes
## 是否添加JSX支持
√ Add JSX Support?  No
## 是否添加路由环境
√ Add Vue Router for Single Page Application development?  No
## 是否添加pinia环境
√ Add Pinia for state management?  No
## 是否添加单元测试
√ Add Vitest for Unit Testing?  No
## 是否添加端到端测试方案
√ Add an End-to-End Testing Solution? » No
## 是否添加ESLint语法检查
√ Add ESLint for code quality?  Yes
## 是否添加Prettiert代码格式化
√ Add Prettier for code formatting?  No
</code></pre>
<h3 style="" id="%E5%88%9D%E8%AF%86vue">初识VUE</h3>
<blockquote>
 <p style="">Vue3向下兼容Vue2语法，且Vue3中的模版可以没有根标签</p>
</blockquote>
<pre><code class="language-vue">&lt;template&gt;
  &lt;div class="person"&gt;
    &lt;h2&gt;姓名：{{name}}&lt;/h2&gt;
    &lt;h2&gt;年龄：{{age}}&lt;/h2&gt;
    &lt;button @click="changeName"&gt;修改名字&lt;/button&gt;
    &lt;button @click="changeAge"&gt;年龄+1&lt;/button&gt;
    &lt;button @click="showTel"&gt;点我查看联系方式&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script lang="ts"&gt;
  export default {
    name:'App',
    data() {
      return {
        name:'张三',
        age:18,
        tel:'13888888888'
      }
    },
    methods:{
      changeName(){
        this.name = 'zhang-san'
      },
      changeAge(){
        this.age += 1
      },
      showTel(){
        alert(this.tel)
      }
    },
  }
&lt;/script&gt;</code></pre>
<h2 style="" id="vue3%E6%A0%B8%E5%BF%83%E8%AF%AD%E6%B3%95">VUE3核心语法</h2>
<h3 style="" id="optionsapi-%E4%B8%8E-compositionapi"><strong>OptionsAPI 与 CompositionAPI</strong></h3>
<ul>
 <li>
  <p style=""><code>Vue2</code>的<code>API</code>设计是<code>Options</code>（配置）风格的。</p>
 </li>
 <li>
  <p style=""><code>Vue3</code>的<code>API</code>设计是<code>Composition</code>（组合）风格的。</p>
 </li>
</ul>
<h4 style="" id="options-api-%E7%9A%84%E5%BC%8A%E7%AB%AF"><strong>Options API 的弊端</strong></h4>
<p style=""><code>Options</code>类型的&nbsp;<code>API</code>，数据、方法、计算属性等，是分散在：<code>data</code>、<code>methods</code>、<code>computed</code>中的，若想新增或者修改一个需求，就需要分别修改：<code>data</code>、<code>methods</code>、<code>computed</code>，不便于维护和复用。</p>
<div class="columns" cols="2" style="display: flex;width: 100%;gap: 1em;">
 <div class="column" index="0" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2F1696662197101-55d2b251-f6e5-47f4-b3f1-d8531bbf9279.gif&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
 </div>
 <div class="column" index="1" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style="text-align: center"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2F1696662200734-1bad8249-d7a2-423e-a3c3-ab4c110628be.gif&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
 </div>
</div>
<h4 style="" id="composition-api-%E7%9A%84%E4%BC%98%E5%8A%BF"><strong>Composition API 的优势</strong></h4>
<p style="">可以用函数的方式，更加优雅的组织代码，让相关功能的代码更加有序的组织在一起。</p>
<div class="columns" cols="2" style="display: flex;width: 100%;gap: 1em;">
 <div class="column" index="0" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2F1696662249851-db6403a1-acb5-481a-88e0-e1e34d2ef53a.gif&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
 </div>
 <div class="column" index="1" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2F1696662256560-7239b9f9-a770-43c1-9386-6cc12ef1e9c0.gif&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
 </div>
</div>
<p style="text-align: center">以上四张动图原创作者：大帅老猿</p>
<h3 style="" id="setup%E5%87%BD%E6%95%B0">Setup函数</h3>
<h4 style="" id="%E6%A6%82%E8%BF%B0">概述</h4>
<p style=""><code>setup</code><span style="font-size: 16px">是</span><code>Vue3</code><span style="font-size: 16px">中一个新的配置项，值是一个函数，它是&nbsp;</span><code>Composition API</code><span style="font-size: 16px">&nbsp;</span><strong>“表演的舞台<em>”</em></strong><span style="font-size: 16px">，组件中所用到的：数据、方法、计算属性、监视......等等，均配置在</span><code>setup</code><span style="font-size: 16px">中。</span></p>
<p style="">特点如下：</p>
<ul>
 <li>
  <p style=""><code>setup</code>函数返回的对象中的内容，可直接在模板中使用。</p>
 </li>
 <li>
  <p style=""><code>setup</code>中访问<code>this</code>是<code>undefined</code>。</p>
 </li>
 <li>
  <p style=""><code>setup</code>函数会在<code>beforeCreate</code>之前调用，它是“领先”所有钩子执行的。</p>
 </li>
</ul>
<pre><code class="language-vue">&lt;template&gt;
  &lt;div class="person"&gt;
    &lt;h2&gt;姓名：{{name}}&lt;/h2&gt;
    &lt;h2&gt;年龄：{{age}}&lt;/h2&gt;
    &lt;button @click="changeName"&gt;修改名字&lt;/button&gt;
    &lt;button @click="changeAge"&gt;年龄+1&lt;/button&gt;
    &lt;button @click="showTel"&gt;点我查看联系方式&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script lang="ts"&gt;
  export default {
    name:'Person',
    setup(){
      // 数据，原来写在data中（注意：此时的name、age、tel数据都不是响应式数据）
      let name = '张三'
      let age = 18
      let tel = '13888888888'

      // 方法，原来写在methods中
      function changeName(){
        name = 'zhang-san' //注意：此时这么修改name页面是不变化的
        console.log(name)
      }
      function changeAge(){
        age += 1 //注意：此时这么修改age页面是不变化的
        console.log(age)
      }
      function showTel(){
        alert(tel)
      }

      // 返回一个对象，对象中的内容，模板中可以直接使用
      return {name,age,tel,changeName,changeAge,showTel}
    }
  }
&lt;/script&gt;</code></pre>
<h4 style="" id="setup-%E8%BF%94%E5%9B%9E%E5%80%BC">setup 返回值</h4>
<ul>
 <li>
  <p style="">若返回一个<strong>对象</strong>：则对象中的：属性、方法等，在模板中均可以直接使用**（重点关注）**</p>
 </li>
 <li>
  <p style="">若返回一个<strong>函数</strong>：则可以自定义渲染内容，代码如下：</p>
 </li>
</ul>
<pre><code class="language-vue">setup(){
  return ()=&gt; '你好啊！'
}</code></pre>
<h4 style="" id="%E4%B8%8E-options-api-%E7%9A%84%E5%85%B3%E7%B3%BB"><strong>与 Options API 的关系</strong></h4>
<ul>
 <li>
  <p style=""><code>Vue2</code>&nbsp;的配置（<code>data</code>、<code>methos</code>......）中<strong>可以访问到</strong>&nbsp;<code>setup</code>中的属性、方法。</p>
 </li>
 <li>
  <p style="">但在<code>setup</code>中<strong>不能访问到</strong><code>Vue2</code>的配置（<code>data</code>、<code>methos</code>......）。</p>
 </li>
 <li>
  <p style="">如果与<code>Vue2</code>冲突，则<code>setup</code>优先。</p>
 </li>
</ul>
<h4 style="" id="setup-%E8%AF%AD%E6%B3%95%E7%B3%96"><strong>setup 语法糖</strong></h4>
<p style=""><code>setup</code><span style="font-size: 16px">函数有一个语法糖，这个语法糖，可以让我们把</span><code>setup</code><span style="font-size: 16px">独立出去，代码如下：</span></p>
<pre><code class="language-vue">&lt;template&gt;
  &lt;div class="person"&gt;
    &lt;h2&gt;姓名：{{name}}&lt;/h2&gt;
    &lt;h2&gt;年龄：{{age}}&lt;/h2&gt;
    &lt;button @click="changName"&gt;修改名字&lt;/button&gt;
    &lt;button @click="changAge"&gt;年龄+1&lt;/button&gt;
    &lt;button @click="showTel"&gt;点我查看联系方式&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script lang="ts"&gt;
  export default {
    name:'Person',
  }
&lt;/script&gt;

&lt;!-- 下面的写法是setup语法糖 --&gt;
&lt;script setup lang="ts"&gt;
  console.log(this) //undefined
  
  // 数据（注意：此时的name、age、tel都不是响应式数据）
  let name = '张三'
  let age = 18
  let tel = '13888888888'

  // 方法
  function changName(){
    name = '李四'//注意：此时这么修改name页面是不变化的
  }
  function changAge(){
    console.log(age)
    age += 1 //注意：此时这么修改age页面是不变化的
  }
  function showTel(){
    alert(tel)
  }
&lt;/script&gt;</code></pre>
<blockquote>
 <p style="">扩展：在Vue 3.3 之后内置提供的一个编译宏（macro）。它的作用类似于 <code>defineProps</code>、<code>defineEmits</code> 这些宏，主要用于在 <code>&lt;script setup&gt;</code> 语法糖里设置组件的选项，比如 <code>name</code>、<code>inheritAttrs</code> 等。</p>
</blockquote>
<pre><code class="language-vue">&lt;script setup lang="ts"&gt;
import { defineOptions } from "vue";

defineOptions({
  name: "Person",
  inheritAttrs: false,
});
&lt;/script&gt;</code></pre>
<p style="">上面等价于传统写法：</p>
<pre><code class="language-vue">&lt;script lang="ts"&gt;
export default {
  name: "Person",
  inheritAttrs: false,
}
&lt;/script&gt;</code></pre>
<h3 style="" id="ref-%E5%88%9B%E5%BB%BA%EF%BC%9A%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%93%8D%E5%BA%94%E5%BC%8F">ref 创建：基本类型的响应式</h3>
<ul>
 <li>
  <p style=""><strong>作用：</strong>定义响应式变量。</p>
 </li>
 <li>
  <p style=""><strong>语法：</strong><code>let xxx = ref(初始值)</code>。</p>
 </li>
 <li>
  <p style=""><strong>返回值：</strong>一个<code>RefImpl</code>的实例对象，简称<code>ref对象</code>或<code>ref</code>，<code>ref</code>对象的<code>value</code><strong>属性是响应式的</strong>。</p>
 </li>
 <li>
  <p style=""><strong>注意点：</strong></p>
  <ul>
   <li>
    <p style=""><code>JS</code>中操作数据需要：<code>xxx.value</code>，但模板中不需要<code>.value</code>，直接使用即可。</p>
   </li>
   <li>
    <p style="">对于<code>let name = ref('张三')</code>来说，<code>name</code>不是响应式的，<code>name.value</code>是响应式的。</p>
   </li>
  </ul>
 </li>
</ul>
<pre><code class="language-vue">&lt;template&gt;
  &lt;div class="person"&gt;
    &lt;h2&gt;姓名：{{name}}&lt;/h2&gt;
    &lt;h2&gt;年龄：{{age}}&lt;/h2&gt;
    &lt;button @click="changeName"&gt;修改名字&lt;/button&gt;
    &lt;button @click="changeAge"&gt;年龄+1&lt;/button&gt;
    &lt;button @click="showTel"&gt;点我查看联系方式&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script setup lang="ts"&gt;
  import {ref} from 'vue'
  import { defineOptions } from "vue";
  defineOptions({
    name: "Person",
  });
  // name和age是一个RefImpl的实例对象，简称ref对象，它们的value属性是响应式的。
  let name = ref('张三')
  let age = ref(18)
  // tel就是一个普通的字符串，不是响应式的
  let tel = '13888888888'

  function changeName(){
    // JS中操作ref对象时候需要.value
    name.value = '李四'
    console.log(name.value)

    // 注意：name不是响应式的，name.value是响应式的，所以如下代码并不会引起页面的更新。
    // name = ref('zhang-san')
  }
  function changeAge(){
    // JS中操作ref对象时候需要.value
    age.value += 1 
    console.log(age.value)
  }
  function showTel(){
    alert(tel)
  }
&lt;/script&gt;</code></pre>
<h3 style="" id="reactive-%E5%88%9B%E5%BB%BA%EF%BC%9A%E5%AF%B9%E8%B1%A1%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%93%8D%E5%BA%94%E5%BC%8F%E6%95%B0%E6%8D%AE"><strong>reactive 创建：对象类型的响应式数据</strong></h3>
<ul>
 <li>
  <p style=""><strong>作用：定义一个响应式对象</strong>（基本类型不要用它，要用<code>ref</code>，否则报错）</p>
 </li>
 <li>
  <p style=""><strong>语法：</strong><code>let 响应式对象= reactive(源对象)</code>。</p>
 </li>
 <li>
  <p style=""><strong>返回值：</strong>一个<code>Proxy</code>的实例对象，简称：响应式对象。</p>
 </li>
 <li>
  <p style=""><strong>注意点：</strong><code>reactive</code>定义的响应式数据是“深层次”的。</p>
 </li>
</ul>
<pre><code class="language-vue">&lt;template&gt;
  &lt;div class="person"&gt;
    &lt;h2&gt;汽车信息：一台{{ car.brand }}汽车，价值{{ car.price }}万&lt;/h2&gt;
    &lt;h2&gt;游戏列表：&lt;/h2&gt;
    &lt;ul&gt;
      &lt;li v-for="g in games" :key="g.id"&gt;{{ g.name }}&lt;/li&gt;
    &lt;/ul&gt;
    &lt;h2&gt;测试：{{obj.a.b.c.d}}&lt;/h2&gt;
    &lt;button @click="changeCarPrice"&gt;修改汽车价格&lt;/button&gt;
    &lt;button @click="changeFirstGame"&gt;修改第一游戏&lt;/button&gt;
    &lt;button @click="test"&gt;测试&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script lang="ts" setup&gt;
import { reactive } from 'vue'

// 数据
let car = reactive({ brand: '奔驰', price: 100 })
let games = reactive([
  { id: 'ahsgdyfa01', name: '英雄联盟' },
  { id: 'ahsgdyfa02', name: '王者荣耀' },
  { id: 'ahsgdyfa03', name: '原神' }
])
let obj = reactive({
  a:{
    b:{
      c:{
        d:666
      }
    }
  }
})

function changeCarPrice() {
  car.price += 10
}
function changeFirstGame() {
  games[0].name = '流星蝴蝶剑'
}
function test(){
  obj.a.b.c.d = 999
}
&lt;/script&gt;</code></pre>
<h3 style="" id="ref-%E5%88%9B%E5%BB%BA%EF%BC%9A%E5%AF%B9%E8%B1%A1%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%93%8D%E5%BA%94%E5%BC%8F%E6%95%B0%E6%8D%AE"><strong>ref 创建：对象类型的响应式数据</strong></h3>
<ul>
 <li>
  <p style="">其实<code>ref</code>接收的数据可以是：<strong>基本类型</strong>、<strong>对象类型</strong>。</p>
 </li>
 <li>
  <p style="">若<code>ref</code>接收的是对象类型，内部其实也是调用了<code>reactive</code>函数。</p>
 </li>
</ul>
<pre><code class="language-vue">&lt;template&gt;
  &lt;div class="person"&gt;
    &lt;h2&gt;汽车信息：一台{{ car.brand }}汽车，价值{{ car.price }}万&lt;/h2&gt;
    &lt;h2&gt;游戏列表：&lt;/h2&gt;
    &lt;ul&gt;
      &lt;li v-for="g in games" :key="g.id"&gt;{{ g.name }}&lt;/li&gt;
    &lt;/ul&gt;
    &lt;h2&gt;测试：{{obj.a.b.c.d}}&lt;/h2&gt;
    &lt;button @click="changeCarPrice"&gt;修改汽车价格&lt;/button&gt;
    &lt;button @click="changeFirstGame"&gt;修改第一游戏&lt;/button&gt;
    &lt;button @click="test"&gt;测试&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script lang="ts" setup&gt;
import { ref } from 'vue'

// 数据
let car = ref({ brand: '奔驰', price: 100 })
let games = ref([
  { id: 'ahsgdyfa01', name: '英雄联盟' },
  { id: 'ahsgdyfa02', name: '王者荣耀' },
  { id: 'ahsgdyfa03', name: '原神' }
])
let obj = ref({
  a:{
    b:{
      c:{
        d:666
      }
    }
  }
})

console.log(car)

function changeCarPrice() {
  car.value.price += 10
}
function changeFirstGame() {
  games.value[0].name = '流星蝴蝶剑'
}
function test(){
  obj.value.a.b.c.d = 999
}
&lt;/script&gt;</code></pre>
<h3 style="" id="ref-%E5%AF%B9%E6%AF%94-reactive"><strong>ref 对比 reactive</strong></h3>
<p style="">宏观角度看：</p>
<blockquote>
 <ol>
  <li>
   <p style=""><code>ref</code>用来定义：<strong>基本类型数据</strong>、<strong>对象类型数据</strong>；</p>
  </li>
  <li>
   <p style=""><code>reactive</code>用来定义：<strong>对象类型数据</strong>。</p>
  </li>
 </ol>
</blockquote>
<ul>
 <li>
  <p style="">区别：</p>
 </li>
</ul>
<blockquote>
 <ol>
  <li>
   <p style=""><code>ref</code>创建的变量必须使用<code>.value</code>（可以使用<code>Vue (Official)</code>插件自动添加<code>.value</code>）。</p>
   <p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2F%25E8%2587%25AA%25E5%258A%25A8%25E8%25A1%25A5%25E5%2585%2585value.png&amp;size=m" alt="自动补充value.png" width="50%" height="auto" style="display: inline-block"></p>
  </li>
  <li>
   <p style=""><code>reactive</code>重新分配一个新对象，会<strong>失去</strong>响应式（可以使用<code>Object.assign</code>去整体替换）。</p>
  </li>
 </ol>
</blockquote>
<ul>
 <li>
  <p style="">使用原则：</p>
 </li>
</ul>
<blockquote>
 <ol>
  <li>
   <p style="">若需要一个基本类型的响应式数据，必须使用<code>ref</code>。</p>
  </li>
  <li>
   <p style="">若需要一个响应式对象，层级不深，<code>ref</code>、<code>reactive</code>都可以。</p>
  </li>
  <li>
   <p style="">若需要一个响应式对象，且层级较深，推荐使用<code>reactive</code>。</p>
  </li>
 </ol>
</blockquote>
<p style=""></p>]]></description><guid isPermaLink="false">/2025/hello-vue-3</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2FVue3.jpeg&amp;size=m" type="image/jpeg" length="49365"/><category>VUE</category><pubDate>Wed, 24 Sep 2025 11:43:56 GMT</pubDate></item><item><title><![CDATA[配置Halo-Umami插件]]></title><link>https://w-flac.org.cn/2025/umami</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=%E9%85%8D%E7%BD%AEHalo-Umami%E6%8F%92%E4%BB%B6&amp;url=/2025/umami" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">在网站运营中，数据分析是优化用户体验和内容策略的重要环节。对于使用 Halo 搭建网站的用户而言，应用市场提供了丰富的插件选择，其中 <a href="https://www.halo.run/store/apps/app-KfOps" target="_self" rel="">Umami 插件</a> 因其轻量化、开源和隐私友好而备受关注。</p>
</blockquote>
<h2 style="" id="%E4%BB%80%E4%B9%88%E6%98%AF-umami%EF%BC%9F">什么是 Umami？</h2>
<p style="">Umami 是一款开源的网页统计工具，致力于提供简洁、直观的数据分析体验。与传统分析工具相比，Umami 不依赖第三方服务，不收集用户个人信息，非常适合注重隐私和性能的站长使用。其核心特点包括：</p>
<ul>
 <li>
  <p style="">轻量高效：数据收集和展示快速，几乎不影响网站性能。</p>
 </li>
 <li>
  <p style="">隐私保护：默认不收集个人身份信息，符合 GDPR 等隐私法规。</p>
 </li>
 <li>
  <p style="">可自托管：无需依赖第三方平台，所有数据均由自己掌控。</p>
 </li>
 <li>
  <p style="">界面简洁：统计面板直观明了，即使非技术用户也能快速上手。</p>
 </li>
</ul>
<hr>
<h2 style="" id="%E5%9C%A8halo%E4%B8%AD%E4%BD%BF%E7%94%A8-umami-%E6%8F%92%E4%BB%B6">在Halo中使用 Umami 插件</h2>
<h3 style="" id="%E2%91%A0%E5%AE%89%E8%A3%85-umami-%E6%8F%92%E4%BB%B6">①安装 Umami 插件</h3>
<p style="">打开 Halo 应用市场，搜索 “Umami”，安装完成后，插件会出现在 Halo 的插件管理列表中。</p>
<p style=""></p>
<h3 style="" id="%E2%91%A1%E9%85%8D%E7%BD%AE-umami-%E5%AE%9E%E4%BE%8B">②配置 Umami 实例</h3>
<p style="">注意：<span fontsize="" color="rgb(153, 27, 27)" style="color: rgb(153, 27, 27)"><strong>本文不涉及 Umami 自托管实例的安装和配置，</strong></span>仅介绍在 Halo 中使用 Umami 插件进行网站统计的操作方法。如需部署自托管实例，请参考 Umami 官方文档。</p>
<p style=""></p>
<h3 style="" id="%E2%91%A2%E5%A4%9A%E7%AB%99%E7%82%B9%E9%85%8D%E7%BD%AE-umami-%E6%8F%92%E4%BB%B6">③多站点配置 Umami 插件</h3>
<p style="">在使用 Umami 插件的过程中，我遇到了一些跨域（CORS）和内容安全策略（CSP）的问题。由于我管理多个 Halo 网站，需要让每个站点都能正常访问 Umami，因此我对 Nginx 做了一些定制配置，具体如下：</p>
<h4 style="" id="%3E%3E-cors-%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AE"><strong> &gt;&gt; CORS 动态配置</strong></h4>
<p style="">使用 <code>map</code> 根据请求的 <code>Origin</code> 动态返回允许的域名，保证不同站点都能正确跨域访问 Umami。</p>
<pre><code class="language-nginx">map $http_origin $cors_origin {

    default "";

    "https://xxx.domain.com"   "https://xxx.domain.com";

    "https://yyy.domain.com"  "https://yyy.domain.com";

}</code></pre>
<p style=""><code>$cors_origin</code> 是前面 <code>map</code> 定义的变量，根据请求的来源动态返回允许的域名。<code>always</code> 表示无论响应状态码是多少，头信息都添加。</p>
<pre><code class="language-nginx">add_header Access-Control-Allow-Origin $cors_origin always; </code></pre>
<h4 style="" id="%3E%3E-csp-%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE"><strong>&gt;&gt; </strong>CSP 相关配置</h4>
<p style="">防止网页被未知来源的站点使用 <code>&lt;iframe&gt;</code> 嵌入你的网页，提高安全性。</p>
<p style=""><code>'self'</code>：允许本域名嵌入；<code>https://xxx.domain.com</code> 和 <code>https://yyy.domain.com</code>：允许指定的域名嵌入</p>
<pre><code class="language-nginx">add_header Content-Security-Policy "frame-ancestors 'self' https://xxx.domain.com https://yyy.domain.com" always;</code></pre>
<h4 style="" id="%3E%3E-nginx%E8%AF%A6%E7%BB%86%E9%85%8D%E7%BD%AE---%E5%8D%95%E4%B8%80%E7%AB%99%E7%82%B9"><strong>&gt;&gt; </strong>Nginx详细配置 - 单一站点</h4>
<p style="">直接复制标注代码到nginx配置即可，<code>1panel</code>的<code>openresty</code>同理。</p>
<pre><code class="language-nginx">server {
    listen 80 ; 
    listen 443 ssl ; 
    server_name umami.domain.com;  // 此处设置你的umami站点
    ....

    // 复制以下配置，此处和Umami插件配置一样
    add_header Access-Control-Allow-Origin 'https://halo.domain.com'; //此处需改为你的Halo站点
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; 
    add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; 
    if ($request_method = 'OPTIONS' ) {
        return 204; 
    }

    // 复制以下配置，此处设置哪些站点可嵌入 &lt;iframe&gt;
    add_header Content-Security-Policy 'frame-ancestors halo.domain.com'; // 此处需改为你的Halo站点

    
    location / {
        proxy_set_header Host $host; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
        proxy_set_header X-Forwarded-Host $server_name; 
        ...

        // 复制以下配置，此处和Umami插件配置一样
        proxy_hide_header 'Access-Control-Allow-Origin'; 
        proxy_hide_header 'Content-Security-Policy'; 
    }
    http2 on; 
    if ($scheme = http) {
        return 301 https://$host$request_uri; 
    }
     ... 
}</code></pre>
<h4 style="" id="%3E%3E-nginx%E8%AF%A6%E7%BB%86%E9%85%8D%E7%BD%AE---%E5%A4%9A%E7%AB%99%E7%82%B9"><strong>&gt;&gt; </strong>Nginx详细配置 - 多站点</h4>
<p style="">直接复制标注代码到nginx配置即可，<code>1panel</code>的<code>openresty</code>同理。</p>
<pre><code class="language-nginx">// 此处调用map方法以实现多站点访问
map $http_origin $cors_origin {
    default "";
    "https://xxx.domain.com"   "https://xxx.domain.com";
    "https://yyy.domain.com"   "https://yyy.domain.com";
}

server {
    listen 80 ; 
    listen 443 ssl ; 
    server_name umami.domain.com;  // 此处设置你的umami站点
    ....

    // 复制以下配置，此处和Umami插件配置一样
    add_header Access-Control-Allow-Origin $cors_origin always; 
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; 
    add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; 
    if ($request_method = 'OPTIONS' ) {
        return 204; 
    }

    // 复制以下配置，此处设置哪些站点可嵌入 &lt;iframe&gt;
    add_header Content-Security-Policy "frame-ancestors 'self' https://xxx.domain.com https://yyy.domain.com" always;

    
    location / {
        proxy_set_header Host $host; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
        proxy_set_header X-Forwarded-Host $server_name; 
        ...

        // 复制以下配置，此处和Umami插件配置一样
        proxy_hide_header 'Access-Control-Allow-Origin'; 
        proxy_hide_header 'Content-Security-Policy'; 
    }
    http2 on; 
    if ($scheme = http) {
        return 301 https://$host$request_uri; 
    }
     ... 
}</code></pre>
<p style=""></p>]]></description><guid isPermaLink="false">/2025/umami</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fumami.png&amp;size=m" type="image/jpeg" length="18164"/><category>日志</category><pubDate>Tue, 23 Sep 2025 12:32:00 GMT</pubDate></item><item><title><![CDATA[MEGO主题开发文章]]></title><link>https://w-flac.org.cn/2025/mego-update</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=MEGO%E4%B8%BB%E9%A2%98%E5%BC%80%E5%8F%91%E6%96%87%E7%AB%A0&amp;url=/2025/mego-update" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">时隔很久很久...</p>
 <p style="">MEGO是我第一款为Halo写的主题，那时刚刚学完HTML+CSS（甚至连JS都还没学完），最近着手对MEGO主题进行了全面的改版与升级，使用Tailwind框架，对多端的响应式有了更好的适配。</p>
</blockquote>
<h3 style="" id="%E4%B8%80%E3%80%81hero%E5%B1%95%E7%A4%BA%E6%9D%BF%E5%9D%97">一、HERO展示板块</h3>
<p style="">在查看原始预览时，发现布局杂乱不堪且缺少主次关系，过多的配色让人眼花缭乱，过多的圆角让整个主题丑陋无比，让人都不想用，请看下图！</p>
<p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=https%3A%2F%2Fw-flac.org.cn%2Fupload%2Fimage-iiMn.png&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
<p style="text-align: center"><span style="font-size: 10px">原主题展示板块</span></p>
<p style="text-align: left">针对以上的问题，我们需要大刀阔斧让一切变得简洁，菜单栏使用三栏布局，左侧站点信息与简介，中间菜单信息，右侧主题配色的切换。Hero的背景均可自定义（我尝试过用API更换背景，每一次刷新都是新的也很炫酷）。</p>
<ul>
 <li>
  <p style="text-align: left">在白天模式下，Hero板块下的全局背景会有阴影，以便提升视觉观感。</p>
 </li>
</ul>
<p style="text-align: left"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-gcIn.png&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
<p style="text-align: center"><span style="font-size: 10px">新主题展示板块-暗黑</span></p>
<ul>
 <li>
  <p style="text-align: left">在暗黑模式下，Hero的全局背景将变得更加轻薄，以适应夜晚模式下对配色的对比。</p>
 </li>
</ul>
<p style="text-align: center"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-QArn.png&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
<p style="text-align: center"><span style="font-size: 10px">新主题展示板块-暗黑</span></p>
<hr>
<h3 style="text-align: left" id="%E4%BA%8C%E3%80%81%E7%A7%BB%E5%8A%A8%E7%AB%AF%E8%8F%9C%E5%8D%95%E5%B8%83%E5%B1%80">二、移动端菜单布局</h3>
<p style="text-align: left">在原始版本中，是通过向下展开的方式展开菜单，动画惨绝人寰让人不忍直视。每一次点击展开的时候会使界面有卡顿，且依然无主题模式切换，我们需要对他进行改革。</p>
<p style="text-align: center"><span style="font-size: 10px"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-LCvz.png&amp;size=m" alt="image-LCvz.png" width="991px" height="518px" style="display: inline-block"></span></p>
<p style="text-align: center"><span style="font-size: 10px">原主题移动端菜单</span></p>
<p style="text-align: left">在新版中，我们依然对Header使用双栏布局，右侧是站点信息，左侧是主题模式切换以及菜单按钮，在右侧菜单的下部分空白区域，我正在构思是否新的方案。</p>
<ul>
 <li>
  <p style="text-align: left">移动端添加滑入滑出的动画，并对展开的菜单时的页面背景设置了蒙版，从而让菜单更加醒目。</p>
 </li>
</ul>
<div class="columns" cols="2" style="display: flex;width: 100%;gap: 1em;">
 <div class="column" index="0" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2FDocument-08-31-2025_01_46_AM.jpg&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
  <p style="text-align: center"><span style="font-size: 10px">新移动端菜单-白天</span></p>
 </div>
 <div class="column" index="1" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style="text-align: center"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2FDocument-08-31-2025_01_45_AM.jpg&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
  <p style="text-align: center"><span style="font-size: 10px">新移动端菜单-暗黑</span></p>
 </div>
</div>
<h3 style="text-align: left" id="%E4%B8%89%E3%80%81%E7%AB%99%E7%82%B9%E4%BF%A1%E6%81%AF">三、站点信息</h3>
<p style="text-align: left">在原始版本中，菜单导航是以三个部分（头像、站点数据以及联系方式）集成在卡片的中显示的，在使用时你会发现当访问量过于强大时会导致样式产生分裂，我们需要对它进行调整。</p>
<p style="text-align: center"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-sDGK.png&amp;size=m" alt="image-sDGK.png" width="100%" height="50%" style="display: inline-block"></p>
<ul>
 <li>
  <p style="text-align: left">在新版本中，站点信息以单独的形式展现，除了网站浏览量，文章发布数，剩下两项均可自定义。</p>
 </li>
 <li>
  <p style="text-align: left">站点信息上方集成了简单摘要，用于网站的介绍或者作者说....</p>
 </li>
 <li>
  <p style="text-align: left"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-JwrH.png&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
 </li>
</ul>
<h3 style="text-align: left" id="%E5%9B%9B%E3%80%81%E5%8D%9A%E5%AE%A2%E5%B1%95%E7%A4%BA">四、博客展示</h3>
<p style="text-align: left">在原始版本中，卡片式的博客布局很实用但太丑了，配上了奇丑无比的背景（实话讲当时觉得很酷）、过多的圆角会使得有很大的割裂感。</p>
<p style="text-align: left"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-mKEw.png&amp;size=m" alt="image-mKEw.png" width="100%" height="100%" style="display: inline-block"></p>
<ul>
 <li>
  <p style="text-align: left">在新版本中对博文显示进行了调整，依然采用了卡片是布局，将文章的图片置底作为背景，文字信息叠加在图片之上；使用渐变遮罩层提高文字的展示程度，将分类信息置于卡片左上角更醒目。</p>
 </li>
</ul>
<p style="text-align: center"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-NODn.png&amp;size=m" width="959px" height="544px" style="display: inline-block"></p>
<div class="columns" cols="2" style="display: flex;width: 100%;gap: 1em;">
 <div class="column" index="0" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fblog-light.jpg&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
 </div>
 <div class="column" index="1" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fblog-dark.jpg&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
 </div>
</div>
<h3 style="text-align: left" id="%E4%BA%94%E3%80%81%E4%BE%A7%E8%BE%B9%E8%81%9A%E5%90%88">五、侧边聚合</h3>
<p style="text-align: left">在原始版本中，侧边栏承载站点信息、热门文章、分类归档和标签归档、上文中我们将站点信息移除，当然在新版本中我依然要改进。至于为什么标签归档没有显示，可能是当时版本太古早没有适配Halo 2.20，不显示了....</p>
<div class="columns" cols="2" style="display: flex;width: 100%;gap: 1em;">
 <div class="column" index="0" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-ckNh.png&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
 </div>
 <div class="column" index="1" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-dbdm.png&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
 </div>
</div>
<ul>
 <li>
  <p style="text-align: left">在新版本中将不在使用双栏布局，小卡片的以聚合形式展示展示在主界面，主题以集成Font Awesome 6 Free字体库，可以自定义风格。</p>
 </li>
</ul>
<p style="text-align: left"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-PNdu.png&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
<div class="columns" cols="2" style="display: flex;width: 100%;gap: 1em;">
 <div class="column" index="0" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2FDocument-09-07-2025_08_31_PM.jpg&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
 </div>
 <div class="column" index="1" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2FDocument-09-07-2025_08_32_PM.jpg&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
 </div>
</div>
<ul>
 <li>
  <p style="text-align: left">在新版本中，我依然选择聚合标签的形式展示在主界面，当标签过多时则是以三行显示，如果标签过少则是一行显示。</p>
 </li>
</ul>
<p style="text-align: left"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-RrSZ.png&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
<div class="columns" cols="2" style="display: flex;width: 100%;gap: 1em;">
 <div class="column" index="0" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2FDocument-09-07-2025_08_39_PM.jpg&amp;size=m" alt="Document-09-07-2025_08_39_PM.jpg" width="100%" height="100%" style="display: inline-block"></p>
 </div>
 <div class="column" index="1" style="min-width: 0;flex: 1 1;box-sizing: border-box;">
  <p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2FDocument-09-07-2025_08_39_PM%2520%281%29.jpg&amp;size=m" alt="Document-09-07-2025_08_39_PM (1).jpg" width="100%" height="100%" style="display: inline-block"></p>
 </div>
</div>
<ul>
 <li>
  <p style="text-align: left">网站的订阅功能很重要，鱼佬写了订阅插件终于派上用场，这里直接复用了TW的UI案例</p>
 </li>
</ul>
<p style="text-align: left"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-DfZB.png&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
<p style="text-align: center"></p>
<p style="text-align: center">未完待续....</p>]]></description><guid isPermaLink="false">/2025/mego-update</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-QArn.png&amp;size=m" type="image/jpeg" length="593725"/><category>日志</category><pubDate>Sat, 30 Aug 2025 17:53:42 GMT</pubDate></item><item><title><![CDATA[AJAX ]]></title><link>https://w-flac.org.cn/2025/ajax</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=AJAX%20&amp;url=/2025/ajax" width="1" height="1" alt="" style="opacity:0;">
<h2 style="" id="%E7%AE%80%E4%BB%8B">简介</h2>
<p style="">AJAX 全称为 Asynchronous JavaScript And XML，就是异步的 JS 和 XML。</p>
<p style="">通过 AJAX 可以在浏览器中向服务器发送异步请求，最大的优势:<span style="font-size: 18px"><mark>无刷新获取数据</mark></span>。</p>
<p style="">AJAX 不是新的编程语言，而是一种将现有的标准组合在一起使用的新方式。</p>
<hr>
<h2 style="" id="%E3%80%90%E5%8E%9F%E7%94%9F%E3%80%91ajax%E8%AF%B7%E6%B1%82">【原生】AJAX请求</h2>
<h3 style="" id="%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C">准备工作</h3>
<blockquote>
 <p style="">1、前往 <a href="https://nodejs.org/" target="_new" rel="noreferrer">Node.js 官方网站</a> 并下载适合你操作系统的 Node.js 安装程序。</p>
 <p style="">2、前往并下载 <a href="https://expressjs.com/" target="_blank">Express</a> 框架。</p>
</blockquote>
<h4 style="" id="%E5%AE%89%E8%A3%85node.js">安装Node.js</h4>
<pre><code class="language-bash">node -v //检查Node.js版本</code></pre>
<pre><code class="language-bash">npm -v // 检查Npm包版本</code></pre>
<pre><code class="language-bash">npm install -g npm // 更细Npm</code></pre>
<h4 style="" id="%E5%AE%89%E8%A3%85express">安装Express</h4>
<pre><code class="language-bash">npm init --yes</code></pre>
<pre><code class="language-bash">npm i express //mac用户前置sudo命令</code></pre>
<h3 style="" id="http%E5%8D%8F%E8%AE%AE%E8%AF%B7%E6%B1%82">HTTP协议请求</h3>
<blockquote>
 <p style="">HTTP（hypertext transport protocol）协议『超文本传输协议』，协议详细规定了浏览器和万维网服务器之间互相通信的规则。</p>
</blockquote>
<h4 style="" id="%E8%AF%B7%E6%B1%82%E6%8A%A5%E6%96%87">请求报文</h4>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 985px">
  <colgroup>
   <col style="width: 292px">
   <col style="width: 693px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <th colspan="1" rowspan="1" colwidth="292">
     <p style="text-align: center">格式</p>
    </th>
    <th colspan="1" rowspan="1" colwidth="693">
     <p style="text-align: center">参数</p>
    </th>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="292">
     <p style="text-align: center">请求行</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="693">
     <p style="text-align: center">POST /form.html HTTP/1.1</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="4" colwidth="292">
     <p style="text-align: center"></p>
     <p style="text-align: center"></p>
     <p style="text-align: center">请求头</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="693">
     <p style="text-align: center">Host: www.example.com</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="693">
     <p style="text-align: center">User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="693">
     <p style="text-align: center">Content-Type: application/x-www-form-urlencoded</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="693">
     <p style="text-align: center">Content-Length: 27</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="292">
     <p style="text-align: center">请求体</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="693">
     <p style="text-align: center">/username=admin&amp;password=admin</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<h4 style="" id="%E5%93%8D%E5%BA%94%E6%8A%A5%E6%96%87">响应报文</h4>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 985px">
  <colgroup>
   <col style="width: 292px">
   <col style="width: 693px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <th colspan="1" rowspan="1" colwidth="292">
     <p style="text-align: center">格式</p>
    </th>
    <th colspan="1" rowspan="1" colwidth="693">
     <p style="text-align: center">参数</p>
    </th>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="292">
     <p style="text-align: center">状态行</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="693">
     <p style="text-align: center">HTTP/1.1 200 OK</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="4" colwidth="292">
     <p style="text-align: center"></p>
     <p style="text-align: center"></p>
     <p style="text-align: center">响应头</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="693">
     <p style="text-align: center">Date: Wed, 21 Oct 2015 10:55:34 GMT</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="693">
     <p style="text-align: center">Content-Type: text/html; charset=UTF-8</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="693">
     <p style="text-align: center">Content-Length: 1354</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="693">
     <p style="text-align: center">Content-encoding: gzip</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="292">
     <p style="text-align: center">响应体</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="693">
     <pre><code class="language-html">&lt;html&gt;
  &lt;head&gt; &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;hello ，Ajax ！&lt;/h1&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<h4 style="" id="%E7%8A%B6%E6%80%81%E7%A0%81">状态码</h4>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 988px">
  <colgroup>
   <col style="width: 154px">
   <col style="width: 241px">
   <col style="width: 593px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <th colspan="1" rowspan="1" colwidth="154">
     <p style="text-align: center">状态码</p>
    </th>
    <th colspan="1" rowspan="1" colwidth="241">
     <p style="text-align: center">类别</p>
    </th>
    <th colspan="1" rowspan="1" colwidth="593">
     <p style="text-align: center">描述</p>
    </th>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">100</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">信息性状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Continue：继续执行。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">101</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">信息性状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Switching Protocols：切换协议。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">200</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">成功状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">OK：请求成功。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">201</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">成功状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Created：请求成功并且服务器创建了新的资源。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">202</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">成功状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Accepted：请求已接受，但处理尚未完成。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">204</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">成功状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">No Content：请求成功，但响应不包含内容。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">301</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">重定向状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Moved Permanently：请求的资源已被永久移动到新位置。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">302</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">重定向状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Found：请求的资源临时从不同的URI响应。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">304</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">重定向状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Not Modified：资源未修改，可以使用客户端缓存的版本。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">400</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">客户端错误状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Bad Request：请求无效或无法被服务器理解。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">401</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">客户端错误状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Unauthorized：请求需要用户认证。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">403</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">客户端错误状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Forbidden：服务器拒绝请求。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">404</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">客户端错误状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Not Found：请求的资源在服务器上不存在。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">500</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">服务器错误状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Internal Server Error：服务器遇到未知错误。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">501</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241">
     <p style="text-align: center">服务器错误状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Not Implemented：服务器不支持请求的功能。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="154" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">502</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="241" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">服务器错误状态码</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="593" style="box-sizing: border-box; padding: 6px 13px; border: 1px solid rgb(221, 221, 221);">
     <p style="text-align: center">Bad Gateway：网关或代理服务器从上游服务器收到无效响应。</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<h3 style="" id="express%E8%A7%84%E5%88%99">Express规则</h3>
<pre><code class="language-javascript">// 引入express
const express = require('express');

// 创建应用对象
const app = express();

// 创建路由规则
// request是对请求报文的封装
// response是对响应报文的封装
app.get('/server',(request,response)=&gt;{
    // 设置响应头，设置允许跨域
    response.setHeader('Access-Control-Allow-Origin','*')
    // 设置响应体
    response.send('Hello AJAX!')
})
app.post('/server', (request, response) =&gt; {
    // 设置响应头，设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*')
    // 设置响应体
    response.send('Hello AJAX!')
})
// 监听端口，启动服务
app.listen(8000, ()=&gt;{
    console.log('服务器已启动，8000端口监听中...')
})</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
    const btn = document.getElementsByTagName('button')[0];
    const result = document.getElementById('result');
    btn.onclick = function() {
        // 1. 创建对象
        const xhr = new XMLHttpRequest();
        // 2. 初始化 设置请求方法和url
        xhr.open('GET','http://127.0.0.1:8000/server');
        // 3. 发送
        xhr.send(); 

        // 4. 事件绑定 处理服务端返回的结果
        // on when 当....时候

        // readystate 是xhr对象中的属性，表示状态 0-4
        // 0：xhr对象创建完成
        // 1：open方法调用完成
        // 2：send方法调用完成
        // 3：服务端返回部分结果
        // 4：服务端返回所有结果，可以在该阶段获取返回结果

        // change 改变
        xhr.onreadystatechange = function() {
            // 判断服务端返回所有结果
            if (xhr.readyState === 4) {
                // 判断响应状态码 200 404 403 401 500
                // 2xx 都为成功
                if (xhr.status &gt;= 200 &amp;&amp; xhr.status &lt; 300) {
                    // 处理结果 行 头 空行 体
                    // 1. 响应行
                    // console.log(xhr.status); // 状态码
                    // console.log(xhr.statusText); // 状态字符串
                    // console.log(xhr.getAllResponseHeaders()); // 所有响应头
                    // console.log(xhr.response); // 响应体
                    // 设置result的文本
                    result.innerText = xhr.response;
                }
            }
        }
    }
&lt;/script&gt;</code></pre>
<h3 style="" id="ajax%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86">AJAX基本原理</h3>
<blockquote>
 <p style=""><code>XMLHttpRequest(XHR)</code>对象用于与服务器交互。通过<code>XMLhttpRequest</code>可以再不刷新页面的情况下，请求特定URL获取数据。这允许网页在不影响用户操作的情况下，更新页面的局部内容。<code>XMLHttpRequest</code>在AJAX编程中被大量使用。</p>
</blockquote>
<h4 style="" id="%E4%BD%BF%E7%94%A8xmlhttprequest">使用XMLHttpRequest</h4>
<blockquote>
 <p style="">创建XMLHttpRequest对象</p>
</blockquote>
<pre><code class="language-javascript">const xhr = new XMLHttpRequest();</code></pre>
<blockquote>
 <p style="">配置请求方法和请求url地址</p>
</blockquote>
<pre><code class="language-javascript">xhr.open('请求方法'，'请求url地址')</code></pre>
<blockquote>
 <p style="">监听loadend时间，接收响应结果</p>
</blockquote>
<pre><code class="language-javascript">xhr.addEventListener('loadend',()=&gt;{
  //响应结果
  console.log(xhr.response)
})</code></pre>
<blockquote>
 <p style="">发送请求</p>
</blockquote>
<pre><code class="language-javascript">xhr.send()</code></pre>
<h4 style="" id="%E6%9F%A5%E8%AF%A2%E5%8F%82%E6%95%B0">查询参数</h4>
<pre><code class="language-html">&lt;p class="city-p"&gt;&lt;/p&gt;html</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
  //目标：使用XHR携带查询参数，展示某个省下属的城市列表
  const xhr = new XMLHttpRequest()
  xhr.open('GET', 'http://hmajax.itheima.net/api/city?pname=辽宁省')
  xhr.addEventListener('loadend', () =&gt; {
    console.log(xhr.response)
    const data = JSON.parse(xhr.response)
    console.log(data)
    document.querySelector('.city-p').innerHTML = data.list.join('&lt;br&gt;')
  })
  xhr.send()
&lt;/script&gt;</code></pre>
<h4 style="" id="%E6%A1%88%E4%BE%8B%E4%B8%80%EF%BC%9A%E5%9C%B0%E5%8C%BA%E6%9F%A5%E8%AF%A2">案例一：地区查询</h4>
<pre><code class="language-javascript">// 1、 创建URLSearchParams 对象
const paramsObj = new URLSearchParams({
    参数名1：值1,
    参数名2：值2
})
// 2、 生成指定格式查询参数 对象的toString() 方法
const queryString = paramsObj.toString
// 结果： 参数名=值1&amp;参数名2=值2</code></pre>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;

    &lt;head&gt;
        &lt;meta charset="UTF-8"&gt;
        &lt;meta content="IE=edge" http-equiv="X-UA-Compatible"&gt;
        &lt;meta content="width=device-width, initial-scale=1.0" name="viewport"&gt;
        &lt;title&gt;案例_地区查询&lt;/title&gt;
        &lt;link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"&gt;
        &lt;style&gt;
            :root {
                font-size: 15px;
            }

            body {
                padding-top: 15px;
            }
        &lt;/style&gt;
    &lt;/head&gt;

    &lt;body&gt;
        &lt;div class="container"&gt;
            &lt;form class="row" id="editForm"&gt;
                &lt;!-- 输入省份名字 --&gt;
                &lt;div class="mb-3 col"&gt;
                    &lt;label class="form-label"&gt;省份名字&lt;/label&gt;
                    &lt;input class="form-control province" name="province" placeholder="请输入省份名称" type="text"
                           value="北京"/&gt;
                &lt;/div&gt;
                &lt;!-- 输入城市名字 --&gt;
                &lt;div class="mb-3 col"&gt;
                    &lt;label class="form-label"&gt;城市名字&lt;/label&gt;
                    &lt;input class="form-control city" name="city" placeholder="请输入城市名称" type="text"
                           value="北京市"/&gt;
                &lt;/div&gt;
            &lt;/form&gt;
            &lt;button class="btn btn-primary sel-btn" type="button"&gt;查询&lt;/button&gt;
            &lt;br&gt;&lt;br&gt;
            &lt;p&gt;地区列表: &lt;/p&gt;
            &lt;ul class="list-group"&gt;
                &lt;!-- 示例地区 --&gt;
                &lt;li class="list-group-item"&gt;东城区&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
        &lt;script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"&gt;&lt;/script&gt;
        &lt;script&gt;
            /**
             * 目标: 根据省份和城市名字, 查询对应的地区列表
             */
            // 1. 获取表单元素
            document.querySelector('.sel-btn').addEventListener('click', () =&gt; {
                // 2. 获取表单数据
                const pname = document.querySelector('.province').value
                const cname = document.querySelector('.city').value

                // 3. 组织查询参数字符串
                const qObj = {
                    pname,
                    cname,
                }

                // 查询参数对象 -&gt; 查询参数字符串
                const paramsObj = new URLSearchParams(qObj)
                const queryString = paramsObj.toString()
                console.log(queryString)

                // 4. 发起请求XHR
                const xhr = new XMLHttpRequest()
                xhr.open('GET', `https://hmajax.itheima.net/api/area?${queryString}`)
                xhr.addEventListener('loadend', () =&gt; {
                    console.log(xhr.response)
                    const data = JSON.parse(xhr.response)
                    console.log(data)
                    const htmlStr = data.list.map(areaName =&gt; {
                        return `&lt;li class="list-group-item"&gt;${areaName}&lt;/li&gt;`
                    }).join('')
                    console.log(htmlStr)
                    document.querySelector('.list-group').innerHTML = htmlStr
                })
                xhr.send()
            })
        &lt;/script&gt;
    &lt;/body&gt;

&lt;/html&gt;</code></pre>
<hr>
<h3 style="" id="post%E8%AF%B7%E6%B1%82%E8%AE%BE%E7%BD%AE">POST请求设置</h3>
<pre><code class="language-html">/* 当鼠标移入#result，则发送Post请求... */
&lt;div id="result" class="w-48 h-48 border solid black"&gt;&lt;/div&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
    const result = document.getElementById('result');
    result.addEventListener('mouseover', function () {
        //1.创建对象
        const xhr = new XMLHttpRequest();
        //2.初始化
        xhr.open('POST', 'http://127.0.0.1:8000/server');
        xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); // 设置请求头信息（预定义）
        xhr.setRequestHeader('name','parlo'); //可以设置自定义请求头
        //3.发送
        xhr.send('a=100&amp;b=200'); //请求体也可以为'number'；'a:100&amp;b:100..'
        //4.事件绑定
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status &gt;= 200 &amp;&amp; xhr.status &lt; 300) {
                    result.innerText = xhr.response;
                }
            }
        }
    });
&lt;/script&gt;</code></pre>
<blockquote>
 <p style="">当设定为自定义的请求头时，则需要在后端添加新的请求类型（一般不需要前端去操作）</p>
</blockquote>
<pre><code class="language-javascript">// server.js

// 可以接受任意类型的请求
app.all('/server', (request, response) =&gt; {
    // 设置响应头，设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*')
    response.setHeader('Access-Control-Allow-Headers', '*')
    // 设置响应体
    response.send('Hello AJAX!')
})</code></pre>
<h3 style="" id="%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%93%8D%E5%BA%94json%E6%95%B0%E6%8D%AE">服务端响应JSON数据</h3>
<pre collapsed="true"><code class="language-javascript">// server.js

// 可以接受任意类型的请求
app.all('/json-server', (request, response) =&gt; {
    // 设置响应头，设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*')
    response.setHeader('Access-Control-Allow-Headers', '*')
    // 响应一个数据
    const data = {
        name: 'parlo',
    }
    // 对象转换为字符串
    let str = JSON.stringify(data)
    // 设置响应体
    response.send(str)
})</code></pre>
<pre><code class="language-html">/* 当键盘在浏览器视口按下，则发送请求 */
&lt;div id="result" class="w-48 h-48 border solid black"&gt;&lt;/div&gt;</code></pre>
<h4 style="" id="%E6%89%8B%E5%8A%A8%E8%BD%AC%E6%8D%A2%E6%95%B0%E6%8D%AE">手动转换数据</h4>
<pre collapsed="true"><code class="language-javascript">&lt;script&gt;
    //当键盘在浏览器视口下，按下键盘则发送POST请求
    const result = document.getElementById('result')
    window.onkeydown = function () {
        // 发送请求
        const xhr = new XMLHttpRequest();
        // 初始化
        xhr.open('get', 'http://127.0.0.1:8000/json-server');
        // 发送
        xhr.send();
        // 事件绑定
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status &gt;= 200 &amp;&amp; xhr.status &lt; 300) {
                    // 手动处理服务器返回的结果
                    let data = JSON.parse(xhr.response)
                    console.log(data)
                    result.innerText = data.name
                }
            }
        }
    }
&lt;/script&gt;</code></pre>
<h4 style="" id="%E8%87%AA%E5%8A%A8%E8%BD%AC%E6%8D%A2%E6%95%B0%E6%8D%AE">自动转换数据</h4>
<pre collapsed="true"><code class="language-javascript">&lt;script&gt;
    //当键盘在浏览器视口下，按下键盘则发送POST请求
    const result = document.getElementById('result')
    window.onkeydown = function () {
        // 发送请求
        const xhr = new XMLHttpRequest();
        // 设置响应体类型
        xhr.responseType = 'json'
        // 初始化
        xhr.open('get', 'http://127.0.0.1:8000/json-server');
        // 发送
        xhr.send();
        // 事件绑定
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status &gt;= 200 &amp;&amp; xhr.status &lt; 300) {
                    // 自动处理服务器返回的结果
                    console.log(xhr.response)
                    result.innerText = xhr.response.name
                }
            }
        }
    }
&lt;/script&gt;</code></pre>
<h3 style="" id="nodemon%E5%B7%A5%E5%85%B7">Nodemon工具</h3>
<h4 style="" id="%E5%AE%89%E8%A3%85nodemon">安装Nodemon</h4>
<pre collapsed="true"><code class="language-bash">npm install -g nodemon</code></pre>
<h4 style="" id="%E8%BF%90%E8%A1%8C%E6%9C%8D%E5%8A%A1%E7%AB%AF">运行服务端</h4>
<pre collapsed="true"><code class="language-bash">nodemon server.js</code></pre>
<h3 style="" id="ie%E7%BC%93%E5%AD%98%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3">IE缓存问题解决</h3>
<blockquote>
 <p style="">解决全世界最好用的IE浏览器的缓存解决问题！需要注意的是，现代浏览器几乎不需要调整。</p>
</blockquote>
<pre collapsed="true"><code class="language-html">&lt;button&gt;点我发送请求&lt;/button&gt;
&lt;div id="result" class="w-48 h-48 border solid black"&gt;&lt;/div&gt;</code></pre>
<pre collapsed="true"><code class="language-javascript">// server.js

app.get('/ie', (request, response) =&gt; {
    // 设置响应头，设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 设置响应体
    response.send('HELLO IE! 2~~~');
});</code></pre>
<pre collapsed="true"><code class="language-javascript">&lt;script&gt;
    const btn = document.getElementsByTagName('button')[0];
    const result = document.getElementById('result');
    btn.addEventListener('click', () =&gt; {
        const xhr = new XMLHttpRequest();
        // 初始化
        xhr.open('GET', 'http://localhost:8000/ie?t=' + Date.now()); //为IE浏览器添加参数 + 时间戳
        // 发送
        xhr.send();
        // 绑定事件
        xhr.onreadystatechange = () =&gt; {
            if (xhr.readyState === 4) {
                if (xhr.status &gt;= 200 &amp;&amp; xhr.status &lt; 300) {
                    result.innerText = xhr.response;
                }
            }
        };
    });
&lt;/script&gt;</code></pre>
<h3 style="" id="%E8%B6%85%E6%97%B6%E4%B8%8E%E7%BD%91%E7%BB%9C%E5%BC%82%E5%B8%B8">超时与网络异常</h3>
<blockquote>
 <p style="">增加友好的判定来告知AJAX请求的网络情况。</p>
</blockquote>
<pre collapsed="true"><code class="language-html">&lt;button&gt;点我发送请求&lt;/button&gt;
&lt;div id="result" class="w-48 h-48 border solid black"&gt;&lt;/div&gt;</code></pre>
<pre collapsed="true"><code class="language-javascript">// server.js

app.get('/delay', (request, response) =&gt; {
    // 设置响应头，设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 设置响应体
    setTimeout(() =&gt; {
        response.send('延时响应');
    }, 3000);
});</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
    const btn = document.getElementsByTagName('button')[0];
    const result = document.getElementById('result');
    btn.addEventListener('click', () =&gt; {
        // 创建对象
        const xhr = new XMLHttpRequest();
        // 设置超时时间
        xhr.timeout = 2000;
        // 设置超时回调
        xhr.ontimeout = function () {
            alert('网络超时，请稍后重试！');
        };
        // 设置网络异常回调
        xhr.onerror = function () {
            alert('网络异常，请稍后重试！');
        };
        // 初始化
        xhr.open('GET', 'http://localhost:8000/delay');
        // 发送
        xhr.send();
        // 事件绑定
        xhr.onreadystatechange = () =&gt; {
            if (xhr.readyState === 4) {
                if (xhr.status &gt;= 200 &amp;&amp; xhr.status &lt; 300) {
                    result.innerText = xhr.response;
                }
            }
        };
    });
&lt;/script&gt;</code></pre>
<h3 style="" id="%E5%8F%96%E6%B6%88%E8%AF%B7%E6%B1%82">取消请求</h3>
<blockquote>
 <p style="">取消正在发送的AJAX请求。</p>
</blockquote>
<pre collapsed="true"><code class="language-html">&lt;button&gt;点击发送请求&lt;/button&gt;
&lt;button&gt;点击取消请求&lt;/button&gt;</code></pre>
<pre collapsed="true"><code class="language-javascript">&lt;script&gt;
    const btn = document.querySelectorAll('button');

    let xhr = null; // 作用域需放在外层

    btn[0].onclick = function () {
        xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://localhost:8000/delay');
        xhr.send();
    };
    btn[1].onclick = function () {
        xhr.abort(); //取消请求
    };
&lt;/script&gt;</code></pre>
<h3 style="" id="%E9%87%8D%E5%A4%8D%E8%AF%B7%E6%B1%82%E9%97%AE%E9%A2%98">重复请求问题</h3>
<blockquote>
 <p style="">当多次发送AJAX请求时，取消之前的请求。这样可以减少服务器的性能冲突。</p>
</blockquote>
<pre collapsed="true"><code class="language-javascript">&lt;script&gt;
    const btn = document.querySelectorAll('button');
    let xhr = null;
    //标识变量
    let isSending = false; // 是否正在发送AJAX请求
    btn[0].onclick = function () {
        if (isSending) xhr.abort();//判断！如果正在发送，则取消本次发送
        xhr = new XMLHttpRequest();
        //修改 标识变量的值
        isSending = true;
        xhr.open('GET', 'http://localhost:8000/delay');
        xhr.send();
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                //修改表示变量
                isSending = false;
            }
        };
    };
    btn[1].onclick = function () {
        xhr.abort(); // 取消请求
    };
&lt;/script&gt;</code></pre>
<h2 style="" id="jquery%E6%96%B9%E6%B3%95">jQuery方法</h2>
<pre><code class="language-html">&lt;button&gt;GET请求&lt;/button&gt;
&lt;button&gt;POST请求&lt;/button&gt;
&lt;button&gt;通用AJAX请求&lt;/button&gt;</code></pre>
<pre><code class="language-javascript">// jquery
app.all('/jquery-server', (request, response) =&gt; {
    // 设置响应头，设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 设置响应体
    //response.send('HELLO jquery AJAX');
    const data = {name:'parlo'};
    response.send(JSON.stringify(data));
});</code></pre>
<h3 style="" id="get%E8%AF%B7%E6%B1%82">GET请求</h3>
<pre><code class="language-javascript">&lt;script&gt;
    $('button').eq(0).click(function () {
        $.get('http://127.0.0.1:8000/jquery-server', {name: 'parlor', age: 18}, function (data) {
            console.log(data);
        }, 'json');
    });
&lt;/script&gt;</code></pre>
<h3 style="" id="post%E8%AF%B7%E6%B1%82">POST请求</h3>
<pre><code class="language-javascript">&lt;script&gt;
    $('button').eq(1).click(function () {
        $.post('http://127.0.0.1:8000/jquery-server', {name: 'parlor', age: 18}, function (data) {
            console.log(data);
        }, 'json');
    });
&lt;/script&gt;</code></pre>
<h3 style="" id="%E9%80%9A%E7%94%A8%E6%96%B9%E6%B3%95">通用方法</h3>
<pre><code class="language-javascript">$('button').eq(2).click(function () {
    $.ajax({
        // url
        url: 'http://127.0.0.1:8000/jquery-server',
        // 参数
        data: {name: 'parlo', age: 18},
        // 请求类型
        type: 'GET',
        // 响应体结果
        dataType: 'json',
        // 成功的回调
        success: function (data) {
            console.log(data);
        },
        // 超时时间
        timeout: 2000,
        // 失败的回调
        error: function () {
            console.log('出错了');
        },
        headers: {
            a: 300,
            b: 400
        }
    });
});</code></pre>
<h2 style="" id="axiso%E6%96%B9%E6%B3%95">Axiso方法</h2>
<h3 style="" id="%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95">基本语法</h3>
<blockquote>
 <pre><code class="language-javascript">axuis({
  url:`目标资源地址`
}).then(result=&gt;{
//对服务器是返回的数据做后续处理
})</code></pre>
</blockquote>
<h3 style="" id="%E5%8F%82%E6%95%B0%E6%9F%A5%E8%AF%A2">参数查询</h3>
<blockquote>
 <pre><code class="language-javascript">axuis({
  url:`目标资源地址`
  params:{
    参数名：值
  }
}).then((result)=&gt;{
//对服务器是返回的数据做后续处理
})</code></pre>
</blockquote>
<pre collapsed="true"><code class="language-html">&lt;p&gt;&lt;/p&gt;
&lt;script&gt;
    axios({
        url: 'https://hmajax.itheima.net/api/city',
        params: {
            pname: '山东省'
        }
    }).then(result =&gt; {
        console.log(result.data.list);
        document.querySelector('p').innerHTML = result.data.list.join('&lt;br&gt;');
    });
&lt;/script&gt;</code></pre>
<pre collapsed="true"><code class="language-html">&lt;form&gt;
    &lt;label&gt;省份名字
        &lt;input name="province" placeholder="请输入省份名字" type="text" value="北京"&gt;
    &lt;/label&gt;
    &lt;label&gt;城市名字
        &lt;input name="city" placeholder="请输入城市名字" type="text" value="北京市"&gt;
    &lt;/label&gt;
&lt;/form&gt;
&lt;button type="button"&gt;查询&lt;/button&gt;
&lt;p&gt;地区列表&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;script&gt;
    &lt;!--创建绑定事件--&gt;
    document.querySelector('button').addEventListener('click', function () {
        // 获取用户输入的省份值
        let pname = document.querySelectorAll('input')[0].value;
        let cname = document.querySelectorAll('input')[1].value;
        console.log(pname, cname);
        // 使用axios发送请求
        axios({
            url: 'https://hmajax.itheima.net/api/area',
            params: {
                pname,
                cname
            }
        }).then(result =&gt; {
            // 打印并检查数据
            console.log(result.data.list);
            let list = result.data.list;
            // ele.map()方法是根据当前数组生成一个新数组
            let theLi = list.map(ele =&gt; `&lt;li&gt;${ele}&lt;/li&gt;`).join('');
            console.log(theLi);
            // 将生成的li标签添加到ul中
            document.querySelector('ul').innerHTML = theLi;
        });
    });
&lt;/script&gt;</code></pre>
<h3 style="" id="%E8%AF%B7%E6%B1%82%E9%85%8D%E7%BD%AE">请求配置</h3>
<blockquote>
 <pre><code class="language-javascript">axuis({
  url:`目标资源地址`,
  method:'请求方法',
  data:{
    参数名:值
  }
  params:{
    参数名:值
  }
}).then(result=&gt;{
//对服务器是返回的数据做后续处理
})</code></pre>
</blockquote>
<h3 style="" id="%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86">错误处理</h3>
<blockquote>
 <pre><code class="language-javascript">axuis({
  //请求选项
}).then(result=&gt;{
  //处理数据
}).catch(error=&gt;{
  //处理错误
})</code></pre>
</blockquote>
<pre><code class="language-html">&lt;button id="btn"&gt;点击注册用户&lt;/button&gt;
&lt;script&gt;
    document.getElementById('btn').addEventListener('click', () =&gt; {
        axios({
            url: 'https://hmajax.itheima.net/api/register',
            method: 'post',
            data: {
                username: 'parlo0532',
                password: '12345678'
            }
        }).then(result =&gt; {
            console.log(result);
        }).catch(error =&gt; {
            console.log(error);
            alert(error.response.data.message);
        });
    });
&lt;/script&gt;</code></pre>
<h3 style="" id="form-serialize(%E6%8F%92%E4%BB%B6)">Form-serialize(插件)</h3>
<blockquote>
 <p style="">引入插件<a href="https://github.com/defunctzombie/form-serialize" target="_blank"> Form-serialize</a></p>
</blockquote>
<pre><code class="language-html">&lt;script src="path/to/form-serialize.js"&gt;&lt;/script&gt;</code></pre>
<blockquote>
 <p style="">使用serialize函数快速手机表单元素的值</p>
</blockquote>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 850px">
  <colgroup>
   <col style="width: 233px">
   <col style="width: 617px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <th colspan="1" rowspan="1" colwidth="233">
     <p style="text-align: center">参数</p>
    </th>
    <th colspan="1" rowspan="1" colwidth="617">
     <p style="text-align: center">详情</p>
    </th>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="233">
     <p style="text-align: center">获取表单的数据</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="617">
     <p style="text-align: center">元素表单设置name属性，值会作为对象的属性名</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="233">
     <p style="text-align: center">配置对象</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="617">
     <p style="text-align: center">hash , empty</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<pre><code class="language-html">&lt;script&gt;
  document.querySelector('.btn').addEventListener('click',(){
    const form = document.querySelector('.example-form')
    /*
      hash：设置获取对象的结构
        - true：JS对象（推介）一般请求体里提交给服务器 
        - false：查询字符串
      empty：设置是否获取空值
        - true：获取空值（推介）一般请求体里提交给服务器
        - false：不获取空值
    */
    const data = serialize(form,{hash:true,empty:true})
    console.log(data)
  })
&lt;/script&gt;</code></pre>
<h3 style="" id="%E6%A1%88%E4%BE%8B%E4%B8%80%EF%BC%9A%E7%99%BB%E5%BD%95%E8%A1%A8%E5%8D%95">案例一：登录表单</h3>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;

    &lt;head&gt;
        &lt;meta charset="UTF-8"&gt;
        &lt;meta content="IE=edge" http-equiv="X-UA-Compatible"&gt;
        &lt;meta content="width=device-width, initial-scale=1.0" name="viewport"&gt;
        &lt;title&gt;案例_登录&lt;/title&gt;
        &lt;!-- 引入bootstrap.css --&gt;
        &lt;link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet"&gt;
        &lt;!-- 公共 --&gt;
        &lt;style&gt;
            html,
            body {
                background-color: #EDF0F5;
                width: 100%;
                height: 100%;
                display: flex;
                justify-content: center;
                align-items: center;
            }

            .container {
                width: 520px;
                height: 540px;
                background-color: #fff;
                padding: 60px;
                box-sizing: border-box;
            }

            .container h3 {
                font-weight: 900;
            }
        &lt;/style&gt;
        &lt;!-- 表单容器和内容 --&gt;
        &lt;style&gt;
            .form_wrap {
                color: #8B929D !important;
            }

            .form-text {
                color: #8B929D !important;
            }
        &lt;/style&gt;
        &lt;!-- 提示框样式 --&gt;
        &lt;style&gt;
            .alert {
                transition: .5s;
                opacity: 0;
            }

            .alert.show {
                opacity: 1;
            }
        &lt;/style&gt;
        &lt;script src="../node_modules/axios/dist/axios.js"&gt;&lt;/script&gt;
        &lt;script src="form-serialize.js"&gt;&lt;/script&gt;
    &lt;/head&gt;

    &lt;body&gt;
        &lt;div class="container"&gt;
            &lt;h3&gt;欢迎-登录&lt;/h3&gt;
            &lt;!-- 登录结果-提示框 --&gt;
            &lt;div class="alert alert-success" role="alert"&gt;
                提示消息
            &lt;/div&gt;
            &lt;!-- 表单 --&gt;
            &lt;div class="form_wrap"&gt;
                &lt;form class="login-form"&gt;
                    &lt;div class="mb-3"&gt;
                        &lt;label class="form-label" for="username"&gt;账号名&lt;/label&gt;
                        &lt;input autocomplete="current-username" class="form-control username" name="username"
                               type="text"&gt;
                    &lt;/div&gt;
                    &lt;div class="mb-3"&gt;
                        &lt;label class="form-label" for="password"&gt;密码&lt;/label&gt;
                        &lt;input autocomplete="current-password" class="form-control password" name="password"
                               type="password"&gt;
                    &lt;/div&gt;
                    &lt;button class="btn btn-primary btn-login" type="button"&gt; 登 录&lt;/button&gt;
                &lt;/form&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;script&gt;
            //目标2：将错误或登录信息放在前端显示
            const message = document.querySelector('.alert')

            function alertFn(msg, isSuccess) {
                //显示提示框
                message.classList.add('show')
                //放入提示消息
                message.innerText = msg
                //设置样式
                const className = isSuccess ? 'alert-success' : 'alert-danger'
                message.classList.add(className)
                //过两秒隐藏
                setTimeout(() =&gt; {
                    message.classList.remove('show')
                    message.classList.remove(className)
                }, 2000)
            }


            // 目标1：点击登录时，用户名和密码长度判断，并提交数据和服务器通信
            document.querySelector('.btn-login').addEventListener('click', () =&gt; {
                // 使用serialize函数收集表单里用户名和密码
                const form = document.querySelector('.login-form')
                const data = serialize(form, {hash: true, empty: true})
                console.log(data);
                const {username, password} = data;
                console.log(username, password)
                // const username = document.querySelector('.username').value
                // const password = document.querySelector('.password').value
                if (username.length &lt; 6) {
                    console.log('用户名长度不能小于6位');
                    alertFn('用户名长度不能小于6位', false)
                    return
                }
                if (password.length &lt; 8) {
                    console.log('密码长度不能小于8位')
                    alertFn('密码长度不能小于8位', false)
                    return
                }
                axios({
                    url: 'https://hmajax.itheima.net/api/login',
                    method: 'post',
                    data: {
                        username,
                        password,
                    },
                }).then(result =&gt; {
                    console.log(result);
                    console.log(result.data.message);
                    alertFn(result.data.message, true)
                }).catch(error =&gt; {
                    console.log(error);
                    console.log(error.response.data.message);
                    alertFn(error.response.data.message, false)
                });
            });


        &lt;/script&gt;

    &lt;/body&gt;

&lt;/html&gt;</code></pre>
<h3 style="" id="%E6%A1%88%E4%BE%8B%E4%BA%8C%EF%BC%9A%E5%9B%BE%E4%B9%A6%E7%AE%A1%E7%90%86">案例二：图书管理</h3>
<h4 style="" id="01%3E%E4%BD%BF%E7%94%A8%E5%B1%9E%E6%80%A7%E6%8E%A7%E5%88%B6%E5%BC%B9%E7%AA%97">01&gt;使用属性控制弹窗</h4>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 792px">
  <colgroup>
   <col style="width: 245px">
   <col style="width: 547px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <th colspan="1" rowspan="1" colwidth="245">
     <p style="text-align: center">Bootstrap</p>
    </th>
    <th colspan="1" rowspan="1" colwidth="547">
     <p style="text-align: center">含义</p>
    </th>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="245">
     <p style="text-align: left">data-bs-toggle="modal"</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="547">
     <p style="">用于触发模态框（Modal）的显示。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="245">
     <p style="text-align: left">data-bs-target="#myModal"</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="547">
     <p style="">查找具有相应NAME模态框，并显示或操作该模态框。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="245">
     <p style="text-align: left">data-bs-dismiss="modal"</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="547">
     <p style="">关闭对应的模态框</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<pre collapsed="true"><code class="language-html">&lt;!-- 使用属性控制弹窗显示
    1、引入bootstrap.css和bootstrap.js
    2、准备弹窗标签，确认结构
    3、通过自定义属性，控制弹窗的显示和隐藏

    data-bs-toggle="modal" 用于触发模态框（Modal）的显示。
    data-bs-target="#myModal" 查找具有相应NAME模态框，并显示或操作该模态框。
    data-bs-dismiss="modal" 关闭对应的模态框
--&gt;

&lt;button class="btn btn-primary" data-bs-target=".my-modal" data-bs-toggle="modal" type="button"&gt;显示弹窗
&lt;/button&gt;

&lt;div class="modal my-modal" tabindex="-1"&gt;
    &lt;div class="modal-dialog"&gt;
        &lt;div class="modal-content"&gt;
            &lt;div class="modal-header"&gt;
                &lt;h5 class="modal-title"&gt;Modal title&lt;/h5&gt;
                &lt;button aria-label="Close" class="btn-close" data-bs-dismiss="modal" type="button"&gt;&lt;/button&gt;
            &lt;/div&gt;
            &lt;div class="modal-body"&gt;
                &lt;p&gt;Modal body text goes here.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div class="modal-footer"&gt;
                &lt;button class="btn btn-secondary" data-bs-dismiss="modal" type="button"&gt;Close&lt;/button&gt;
                &lt;button class="btn btn-primary" type="button"&gt;Save changes&lt;/button&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</code></pre>
<h4 style="" id="02%3E%E4%BD%BF%E7%94%A8js%E6%8E%A7%E5%88%B6%E5%BC%B9%E7%AA%97">02&gt;使用JS控制弹窗</h4>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 792px">
  <colgroup>
   <col style="width: 245px">
   <col style="width: 547px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <th colspan="1" rowspan="1" colwidth="245">
     <p style="text-align: center">Bootstrap</p>
    </th>
    <th colspan="1" rowspan="1" colwidth="547">
     <p style="text-align: center">方法</p>
    </th>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="245">
     <p style="">创建弹窗对象</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="547">
     <pre><code class="language-javascript">const modaDom = document.querySelector('.modal')
const modal = new bootstrap.Modal(modaDom)</code></pre>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="245">
     <p style="">调用弹窗对象内置方法</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="547">
     <pre><code class="language-javascript">.show() 显示弹窗
.hide() 隐藏弹窗</code></pre>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<pre collapsed="true"><code class="language-html">&lt;!--
目标：使用JS控制弹窗，显示和隐藏
1. 创建弹窗对象
   const modaDom = document.querySelector('.modal')
   const modal = new bootstrap.Modal(modaDom)
2. 调用弹窗对象内置方法
   .show() 显示弹窗
   .hide() 隐藏弹窗
--&gt;
&lt;button class="btn btn-primary edit-btn" type="button"&gt;
    编辑姓名
&lt;/button&gt;

&lt;div class="modal name-box" tabindex="-1"&gt;
    &lt;div class="modal-dialog"&gt;
        &lt;div class="modal-content"&gt;
            &lt;div class="modal-header"&gt;
                &lt;h5 class="modal-title"&gt;请输入姓名&lt;/h5&gt;
                &lt;button aria-label="Close" class="btn-close" data-bs-dismiss="modal" type="button"&gt;&lt;/button&gt;
            &lt;/div&gt;
            &lt;div class="modal-body"&gt;
                &lt;form action=""&gt;
                    &lt;span&gt;姓名：&lt;/span&gt;
                    &lt;input class="username" type="text"&gt;
                &lt;/form&gt;
            &lt;/div&gt;
            &lt;div class="modal-footer"&gt;
                &lt;button class="btn btn-secondary" data-bs-dismiss="modal" type="button"&gt;取消&lt;/button&gt;
                &lt;button class="btn btn-primary save-btn" type="button"&gt;保存&lt;/button&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;!-- 引入bootstrap.js --&gt;
&lt;script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
    // 1. 创建弹窗对象
    const modaDom = document.querySelector('.name-box')
    const modal = new bootstrap.Modal(modaDom)
    // 编辑姓名-&gt;点击-&gt;弹窗显示
    document.querySelector('.edit-btn').addEventListener('click', () =&gt; {
        document.querySelector('.username').value = '张三'
        modal.show()
    })
    // 保存按钮-&gt;点击-&gt;获取姓名打印-&gt;弹窗隐藏
    document.querySelector('.save-btn').addEventListener('click', () =&gt; {
        const username = document.querySelector('.username').value
        console.log('模拟把姓名保存到服务器上', username)
        modal.hide()
    })
&lt;/script&gt;</code></pre>
<h4 style="" id="03%3E%E5%AE%8C%E6%95%B4%E4%BB%A3%E7%A0%81">03&gt;完整代码</h4>
<pre collapsed="true"><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;

    &lt;head&gt;
        &lt;meta charset="UTF-8"&gt;
        &lt;meta content="IE=edge" http-equiv="X-UA-Compatible"&gt;
        &lt;meta content="width=device-width, initial-scale=1.0" name="viewport"&gt;
        &lt;title&gt;案例-图书管理&lt;/title&gt;
        &lt;!-- 字体图标 --&gt;
        &lt;link href="https://at.alicdn.com/t/c/font_3736758_vxpb728fcyh.css" rel="stylesheet"&gt;
        &lt;!-- 引入bootstrap.css --&gt;
        &lt;link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/css/bootstrap.min.css" rel="stylesheet"&gt;
        &lt;!-- 核心样式 --&gt;
        &lt;link href="CSS/index.css" rel="stylesheet"&gt;
    &lt;/head&gt;

    &lt;body&gt;
        &lt;!-- 主体区域 --&gt;
        &lt;div class="container"&gt;
            &lt;!-- 头部标题和添加按钮 --&gt;
            &lt;div class="top"&gt;
                &lt;h3&gt;图书管理&lt;/h3&gt;
                &lt;button class="btn btn-primary plus-btn" data-bs-target=".add-modal" data-bs-toggle="modal"
                        type="button"&gt; + 添加
                &lt;/button&gt;
            &lt;/div&gt;
            &lt;!-- 数据列表 --&gt;
            &lt;table class="table"&gt;
                &lt;thead class="table-light"&gt;
                    &lt;tr&gt;
                        &lt;th style="width: 150px;"&gt;序号&lt;/th&gt;
                        &lt;th&gt;书名&lt;/th&gt;
                        &lt;th&gt;作者&lt;/th&gt;
                        &lt;th&gt;出版社&lt;/th&gt;
                        &lt;th style="width: 180px;"&gt;操作&lt;/th&gt;
                    &lt;/tr&gt;
                &lt;/thead&gt;
                &lt;tbody class="list"&gt;
                    &lt;tr&gt;
                        &lt;td&gt;1&lt;/td&gt;
                        &lt;td&gt;JavaScript程序设计&lt;/td&gt;
                        &lt;td&gt;马特·弗里斯比&lt;/td&gt;
                        &lt;td&gt;人民邮电出版社&lt;/td&gt;
                        &lt;td&gt;
                            &lt;span class="del"&gt;删除&lt;/span&gt;
                            &lt;span class="edit"&gt;编辑&lt;/span&gt;
                        &lt;/td&gt;
                    &lt;/tr&gt;
                &lt;/tbody&gt;
            &lt;/table&gt;
        &lt;/div&gt;
        &lt;!-- 新增-弹出框 --&gt;
        &lt;div class="modal fade add-modal"&gt;
            &lt;!-- 中间白色区域 --&gt;
            &lt;div class="modal-dialog"&gt;
                &lt;div class="modal-content"&gt;
                    &lt;div class="modal-header top"&gt;
                        &lt;span&gt;添加图书&lt;/span&gt;
                        &lt;button aria-label="Close" class="btn-close" data-bs-dismiss="modal" type="button"&gt;&lt;/button&gt;
                    &lt;/div&gt;
                    &lt;div class="modal-body form-wrap"&gt;
                        &lt;!-- 新增表单 --&gt;
                        &lt;form class="add-form"&gt;
                            &lt;div class="mb-3"&gt;
                                &lt;label class="form-label" for="bookname"&gt;书名&lt;/label&gt;
                                &lt;input class="form-control bookname" name="bookname" placeholder="请输入书籍名称"
                                       type="text"&gt;
                            &lt;/div&gt;
                            &lt;div class="mb-3"&gt;
                                &lt;label class="form-label" for="author"&gt;作者&lt;/label&gt;
                                &lt;input class="form-control author" name="author" placeholder="请输入作者名称"
                                       type="text"&gt;
                            &lt;/div&gt;
                            &lt;div class="mb-3"&gt;
                                &lt;label class="form-label" for="publisher"&gt;出版社&lt;/label&gt;
                                &lt;input class="form-control publisher" name="publisher" placeholder="请输入出版社名称"
                                       type="text"&gt;
                            &lt;/div&gt;
                        &lt;/form&gt;
                    &lt;/div&gt;
                    &lt;div class="modal-footer btn-group"&gt;
                        &lt;button class="btn btn-primary" data-bs-dismiss="modal" type="button"&gt; 取消&lt;/button&gt;
                        &lt;button class="btn btn-primary add-btn" type="button"&gt; 保存&lt;/button&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;!-- 编辑-弹出框 --&gt;
        &lt;div class="modal fade edit-modal"&gt;
            &lt;!-- 中间白色区域 --&gt;
            &lt;div class="modal-dialog"&gt;
                &lt;div class="modal-content"&gt;
                    &lt;div class="modal-header top"&gt;
                        &lt;span&gt;编辑图书&lt;/span&gt;
                        &lt;button aria-label="Close" class="btn-close" data-bs-dismiss="modal" type="button"&gt;&lt;/button&gt;
                    &lt;/div&gt;
                    &lt;div class="modal-body form-wrap"&gt;
                        &lt;!-- 编辑表单 --&gt;
                        &lt;form class="edit-form"&gt;
                            &lt;input class="id" name="id" type="hidden"&gt;
                            &lt;div class="mb-3"&gt;
                                &lt;label class="form-label" for="bookname"&gt;书名&lt;/label&gt;
                                &lt;input class="form-control bookname" name="bookname" placeholder="请输入书籍名称"
                                       type="text"&gt;
                            &lt;/div&gt;
                            &lt;div class="mb-3"&gt;
                                &lt;label class="form-label" for="author"&gt;作者&lt;/label&gt;
                                &lt;input class="form-control author" name="author" placeholder="请输入作者名称"
                                       type="text"&gt;
                            &lt;/div&gt;
                            &lt;div class="mb-3"&gt;
                                &lt;label class="form-label" for="publisher"&gt;出版社&lt;/label&gt;
                                &lt;input class="form-control publisher" name="publisher" placeholder="请输入出版社名称"
                                       type="text"&gt;
                            &lt;/div&gt;
                        &lt;/form&gt;
                    &lt;/div&gt;
                    &lt;div class="modal-footer btn-group"&gt;
                        &lt;button class="btn btn-primary" data-bs-dismiss="modal" type="button"&gt; 取消&lt;/button&gt;
                        &lt;button class="btn btn-primary edit-btn" type="button"&gt; 修改&lt;/button&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;script src="https://cdn.bootcdn.net/ajax/libs/axios/1.2.0/axios.min.js"&gt;&lt;/script&gt;
        &lt;script src="./lib/form-serialize.js"&gt;&lt;/script&gt;
        &lt;script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/js/bootstrap.min.js"&gt;&lt;/script&gt;
        &lt;!-- 核心逻辑 --&gt;
        &lt;script src="JS/index.js"&gt;&lt;/script&gt;
    &lt;/body&gt;

&lt;/html&gt;</code></pre>
<pre collapsed="true"><code class="language-html">&lt;script&gt;

  /**
   * 目标1：渲染图书列表
   * 1.1 获取数据
   * 1.2 渲染数据
   */
  const creator = '张三';
  
  function getBookList() {
      // 1.1 获取数据
      axios({
          url: 'https://hmajax.itheima.net/api/books',
          params: {
              creator,
          },
      }).then(result =&gt; {
          console.log(result)
          const bookList = result.data.data;
          console.log(bookList)
          // 1.2 渲染数据
          const htmlStr = bookList.map((item, index) =&gt; {
              return `&lt;tr&gt;
                  &lt;td&gt;${index + 1}&lt;/td&gt;
                  &lt;td&gt;${item.bookname}&lt;/td&gt;
                  &lt;td&gt;${item.author}&lt;/td&gt;
                  &lt;td&gt;${item.publisher}&lt;/td&gt;
                  &lt;td data-id="${item.id}"&gt;
                      &lt;span class="del"&gt;删除&lt;/span&gt;
                      &lt;span class="edit"&gt;编辑&lt;/span&gt;
                  &lt;/td&gt;
              &lt;/tr&gt;`
          }).join('')
          console.log(htmlStr)
          document.querySelector('.list').innerHTML = htmlStr
      })
  }
  
  //网页加载运行时，获取并渲染列表一次
  getBookList();
  
  /**
   * 目标2：新增图书
   * 2.1 新增弹窗--&gt;显示和隐藏
   * 2.2 收集表单数据并提交到服务器保存
   * 2.3 刷新图书列表
   */
  // 2.1 新增弹窗--&gt;显示和隐藏
  const addModalDom = document.querySelector('.add-modal')
  const addModal = new bootstrap.Modal(addModalDom)
  // 保存按钮--&gt;点击-&gt;隐藏弹窗
  document.querySelector('.add-btn').addEventListener('click', () =&gt; {
      // 2.2 收集表单数据
      const addForm = document.querySelector('.add-form')
      const bookObj = serialize(addForm, {hash: true, empty: true})
      console.log(bookObj)
      //提交到服务器保存
      axios({
          url: 'https://hmajax.itheima.net/api/books',
          method: 'post',
          data: {
              ...bookObj,
              creator,
          },
      }).then(result =&gt; {
          console.log(result)
          // 2.3 添加成功后，重新请求并渲染图书列表
          getBookList();
          // 重置表单
          addForm.reset()
          // 隐藏弹窗
          addModal.hide()
      })
  })
  
  /**
   * 目标3：删除图书
   * 3.1 删除元素绑定点击事件-&gt;获取图书ID
   * 3.2 调用删除接口
   * 3.3 刷新图书列表
   */
  
  // 3.1 删除元素-&gt;(事件委托)
  document.querySelector('.list').addEventListener('click', event =&gt; {
      // console.log(event.target)
      if (event.target.classList.contains('del')) {
          // console.log('删除')
          const theID = event.target.parentNode.dataset.id
          console.log(theID)
          // 3.2 删除元素
          axios({
              url: `https://hmajax.itheima.net/api/books/${theID}`,
              method: 'delete',
          }).then(() =&gt; {
              // 3.3 刷新图书列表
              getBookList()
          })
      }
  })
  
  /**
   * 目标4：编辑图书
   * 4.1 编辑弹窗-&gt;显示和隐藏
   * 4.2 获取当前编辑图书数据-&gt;回显到编辑表单中
   * 4.3 提交保存修改，并刷新列表
   */
  
  // 4.1 编辑弹窗-&gt;显示和隐藏
  const editDom = document.querySelector('.edit-modal')
  const editModal = new bootstrap.Modal(editDom)
  // 编辑元素-&gt;点击-&gt;显示弹窗
  document.querySelector('.list').addEventListener('click', event =&gt; {
      // 判断点击的是否为编辑元素
      if (event.target.classList.contains('edit')) {
          // console.log('编辑')
          // 4.2 获取当前编辑图书数据-&gt;回显到编辑表单中
          const theID = event.target.parentNode.dataset.id
          console.log(theID)
          axios({
              url: `https://hmajax.itheima.net/api/books/${theID}`,
          }).then(result =&gt; {
              // 查看数据
              console.log(result)
              const bookObj = result.data.data
              // 遍历数据对象，使用属性去获取对应的标签
              const keys = Object.keys(bookObj)
              keys.forEach(key =&gt; {
                  document.querySelector(`.edit-form .${key}`).value = bookObj[key]
              })
          })
          editModal.show()
      }
  })
  // 修改按钮-&gt;点击-&gt;隐藏弹窗
  document.querySelector('.edit-btn').addEventListener('click', () =&gt; {
      // 4.3 提交保存修改，并刷新列表
      const editForm = document.querySelector('.edit-form')
      const {id, bookname, author, publisher} = serialize(editForm, {hash: true, empty: true})
      axios({
          url: `https://hmajax.itheima.net/api/books/${id}`,
          method: 'put',
          data: {
              bookname,
              author,
              publisher,
              creator,
          },
      }).then(() =&gt; {
          getBookList()
          editModal.hide()
      })
  })  

&lt;/script&gt;</code></pre>
<h3 style="" id="%E5%9B%BE%E7%89%87%E4%B8%8A%E4%BC%A0">图片上传</h3>
<blockquote>
 <p style="">使用 FormData 携带图片文件</p>
</blockquote>
<pre><code class="language-javascript">const fd = new FormData()
fd.append(参数名，值)</code></pre>
<pre collapsed="true"><code class="language-html">&lt;!doctype html&gt;
&lt;html lang="en"&gt;
    &lt;head&gt;
        &lt;meta charset="UTF-8"&gt;
        &lt;meta content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
              name="viewport"&gt;
        &lt;meta content="ie=edge" http-equiv="X-UA-Compatible"&gt;
        &lt;title&gt;图片上传&lt;/title&gt;
        &lt;script src="../dist/http_cdn.bootcdn.net_ajax_libs_axios_1.2.0_axios.js"&gt;&lt;/script&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;input class="upload" type="file"&gt;
        &lt;img alt="" class="my-img" src=""&gt;

        &lt;script&gt;
            /**
             * 目标: 图片上传，显示在网页上
             * 1. 获取图片文件
             * 2. 使用 FormData 将图片文件传递给后端
             * 3. 提交到服务器，获取图片url网址并使用
             */
            // 文件选择元素 -&gt; change改变事件
            document.querySelector('.upload').addEventListener('change', e =&gt; {
                // 获取文件对象
                console.log(e.target.files[0])
                // 创建FormData对象
                const fd = new FormData()
                // 将文件对象添加到FormData中
                fd.append('img', e.target.files[0])
                // 发送请求
                axios({
                    url: 'https://hmajax.itheima.net/api/uploadimg',
                    method: 'post',
                    data: fd,
                }).then(result =&gt; {
                    console.log(result)
                    // 将图片地址显示在网页上
                    const imgUrl = result.data.data.url
                    document.querySelector('.my-img').src = imgUrl
                })
            })
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<h3 style="" id="%E6%A1%88%E4%BE%8B%E4%B8%89%EF%BC%9A%E6%9B%B4%E6%8D%A2%E8%83%8C%E6%99%AF">案例三：更换背景</h3>
<pre collapsed="true"><code class="language-html">&lt;!doctype html&gt;
&lt;html lang="en"&gt;
    &lt;head&gt;
        &lt;meta charset="UTF-8"&gt;
        &lt;meta content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
              name="viewport"&gt;
        &lt;meta content="ie=edge" http-equiv="X-UA-Compatible"&gt;
        &lt;title&gt;Document&lt;/title&gt;
        &lt;style&gt;
            .upload {
                display: none;
            }

            .bq {
                width: fit-content;
                padding: 10px;
                background: #000;
                color: #fff;
                border-radius: 10px;
            }
        &lt;/style&gt;
        &lt;script src="../dist/http_cdn.bootcdn.net_ajax_libs_axios_1.2.0_axios.js"&gt;&lt;/script&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;div class="bq"&gt;
            &lt;label for="upload"&gt;更换背景&lt;/label&gt;
            &lt;input class="upload" id="upload" type="file"&gt;
        &lt;/div&gt;

        &lt;script&gt;
            document.querySelector('.upload').addEventListener('change', e =&gt; {
                // 选择图片上传，设置body背景
                const formData = new FormData()
                formData.append('img', e.target.files[0])
                axios({
                    url: 'https://hmajax.itheima.net/api/uploadimg',
                    method: 'post',
                    data: formData,
                }).then(result =&gt; {
                    // 获取上传服务器后的返回地址
                    const imgUrl = result.data.data.url
                    // 设置body背景
                    document.body.style.backgroundImage = `url(${imgUrl})`
                    // 上传成功时保存在本地
                    localStorage.setItem('bg', imgUrl)
                })
            })
            // 页面加载时，如果本地有背景，则设置body背景
            const bgUrl = localStorage.getItem('bg')
            document.body.style.backgroundImage = `url(${bgUrl})`
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<h3 style="" id="%E6%A1%88%E4%BE%8B%E5%9B%9B%EF%BC%9A%E4%B8%AA%E4%BA%BA%E4%BF%A1%E6%81%AF%E8%AE%BE%E7%BD%AE">案例四：个人信息设置</h3>
<pre collapsed="true"><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="zh-CN"&gt;
    &lt;head&gt;
        &lt;meta charset="UTF-8"&gt;
        &lt;meta content="IE=edge" http-equiv="X-UA-Compatible"&gt;
        &lt;meta content="width=device-width, initial-scale=1.0" name="viewport"&gt;
        &lt;link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"&gt;
        &lt;!-- 核心样式 --&gt;
        &lt;link href="./css/index.css" rel="stylesheet"&gt;
        &lt;title&gt;个人信息设置&lt;/title&gt;
    &lt;/head&gt;

    &lt;body&gt;
        &lt;!-- toast 提示框 --&gt;
        &lt;div class="toast my-toast" data-bs-delay="1500"&gt;
            &lt;div class="toast-body"&gt;
                &lt;div class="alert alert-success info-box"&gt;
                    操作成功
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;!-- 核心内容区域 --&gt;
        &lt;div class="container"&gt;
            &lt;ul class="my-nav"&gt;
                &lt;li class="active"&gt;基本设置&lt;/li&gt;
                &lt;li&gt;安全设置&lt;/li&gt;
                &lt;li&gt;账号绑定&lt;/li&gt;
                &lt;li&gt;新消息通知&lt;/li&gt;
            &lt;/ul&gt;
            &lt;div class="content"&gt;
                &lt;div class="info-wrap"&gt;
                    &lt;h3 class="title"&gt;基本设置&lt;/h3&gt;
                    &lt;form action="javascript:;" class="user-form"&gt;
                        &lt;div class="form-item"&gt;
                            &lt;label for="email"&gt;邮箱&lt;/label&gt;
                            &lt;input autocomplete="off" class="email" id="email" name="email" placeholder="请输入邮箱"
                                   type="text"&gt;
                        &lt;/div&gt;
                        &lt;div class="form-item"&gt;
                            &lt;label for="nickname"&gt;昵称&lt;/label&gt;
                            &lt;input autocomplete="off" class="nickname" id="nickname" name="nickname" placeholder="请输入昵称"
                                   type="text"&gt;
                        &lt;/div&gt;
                        &lt;div class="form-item"&gt;
                            &lt;label&gt;性别&lt;/label&gt;
                            &lt;label class="male-label"&gt;&lt;input class="gender" name="gender" type="radio"
                                                             value="0"&gt;男&lt;/label&gt;
                            &lt;label class="male-label"&gt;&lt;input class="gender" name="gender" type="radio"
                                                             value="1"&gt;女&lt;/label&gt;
                        &lt;/div&gt;
                        &lt;div class="form-item"&gt;
                            &lt;label for="desc"&gt;个人简介&lt;/label&gt;
                            &lt;textarea autocomplete="off" class="desc" cols="20" id="desc" name="desc"
                                      placeholder="请输入个人简介" rows="10"&gt;&lt;/textarea&gt;
                        &lt;/div&gt;
                        &lt;button class="submit"&gt;提交&lt;/button&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
                &lt;div class="avatar-box"&gt;
                    &lt;h4 class="avatar-title"&gt;头像&lt;/h4&gt;
                    &lt;img alt="" class="prew" src="./img/头像.png"&gt;
                    &lt;label for="upload"&gt;更换头像&lt;/label&gt;
                    &lt;input class="upload" id="upload" type="file"&gt;
                &lt;/div&gt;

            &lt;/div&gt;
        &lt;/div&gt;
        &lt;script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"&gt;&lt;/script&gt;
        &lt;script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.min.js"&gt;&lt;/script&gt;
        &lt;script src="./lib/form-serialize.js"&gt;&lt;/script&gt;
        &lt;!-- 核心逻辑 --&gt;
        &lt;script src="./js/index.js"&gt;&lt;/script&gt;
    &lt;/body&gt;

&lt;/html&gt;</code></pre>
<h4 style="" id="01%3E%E4%BF%A1%E6%81%AF%E6%B8%B2%E6%9F%93">01&gt;信息渲染</h4>
<pre collapsed="true"><code class="language-javascript">/**
 * 目标1：信息渲染
 *  1.1 获取用户的数据
 *  1.2 回显数据到标签上
 * */
const creator = 'parlocc'
axios({
    url: 'https://hmajax.itheima.net/api/settings',
    params: {
        creator,
    },
}).then(result =&gt; {
    const userObj = result.data.data
    console.log(userObj)
    Object.keys(userObj).forEach(key =&gt; {
        if (key === 'avatar') {
            document.querySelector('.prew').src = userObj[key];
        } else if (key === 'gender') {
            const gRadio = document.querySelectorAll('.gender')
            const gNum = userObj[key]
            console.log(userObj[key])
            gRadio[gNum].checked = true
        } else {
            document.querySelector(`.${key}`).value = userObj[key]
        }
    })
})
</code></pre>
<h4 style="" id="02%3E%E4%BF%AE%E6%94%B9%E5%A4%B4%E5%83%8F">02&gt;修改头像</h4>
<pre collapsed="true"><code class="language-javascript">/**
 * 目标2：修改头像
 *  2.1 获取头像文件
 *  2.2 提交服务器并更新头像
 * */
document.querySelector('.upload').addEventListener('change', e =&gt; {
    console.log(e.target.files[0])
    const fd = new FormData()
    fd.append('avatar', e.target.files[0])
    fd.append('creator', creator)

    axios({
        url: 'https://hmajax.itheima.net/api/avatar',
        method: 'put',
        data: fd,
    }).then(result =&gt; {
        console.log(result)
        const imgUrl = result.data.data.avatar
        document.querySelector('.prew').url = imgUrl
    })
})</code></pre>
<h4 style="" id="03%3E%E6%8F%90%E4%BA%A4%E8%A1%A8%E5%8D%95">03&gt;提交表单</h4>
<pre><code class="language-javascript">/**
 * 目标3：提交表单
 *  3.1 收集表单信息
 *  3.2 提交服务器保存
 * */

document.querySelector('.submit').addEventListener('click', () =&gt; {
    const userFrom = document.querySelector('.user-form')
    const userObj = serialize(userFrom, {hash: true, empty: true})
    userObj.creator = creator
    // 性别数字字符串，转换成数字类型
    userObj.gender = +userObj.gender
    console.log(userObj)
    axios({
        url: 'https://hmajax.itheima.net/api/settings',
        method: 'put',
        data: userObj,
    }).then(result =&gt; {
        const toastDom = document.querySelector('.my-toast')
        const toast = new bootstrap.Toast(toastDom)
        toast.show()
    })
})</code></pre>
<h2 style="" id="fetch%E5%87%BD%E6%95%B0">Fetch函数</h2>
<pre><code class="language-html">&lt;button&gt;AJAX&lt;/button&gt;</code></pre>
<pre collapsed="true"><code class="language-javascript">&lt;script&gt;
    const btn = document.querySelector('button');
    btn.onclick = function () {
        fetch('http://127.0.0.1:8000/fetch-server?parlo=31', {
            //请求方法
            method: 'POST',
            //请求头
            headers: {
                name: 'parlo'
            },
            //请求体
            body: 'username=admin&amp;password=123456'
        }).then(response =&gt; {
            return response.json();
        }).then(response =&gt; {
            console.log(response);
        });
    };
&lt;/script&gt;</code></pre>
<h2 style="" id="%E8%B7%A8%E5%9F%9F">跨域</h2>
<h3 style="" id="%E5%90%8C%E6%BA%90%E7%AD%96%E7%95%A5">同源策略</h3>
<blockquote>
 <p style="">同源策略(Same-Origin Policy)最早由 Netscape 公司提出，是浏览器的一种安全策略。</p>
 <p style="">同源: 协议、域名、端口号 必须完全相同。</p>
 <p style="">而违背同源策略就是跨域。</p>
</blockquote>
<h3 style="" id="jsonp">JSONP</h3>
<blockquote>
 <p style="">JSONP(JSON with Padding)，是一个非官方的跨域解决方案，纯粹凭借程序员的聪明</p>
 <p style="">才智开发出来，只支持 get 请求。</p>
</blockquote>
<pre><code class="language-html">用户名：&lt;input id="username" type="text"/&gt;
&lt;p&gt;&lt;/p&gt;</code></pre>
<pre><code class="language-javascript">// 用户名检测是否存在
app.all('/check-username', (request, response) =&gt; {
    const data = {
        exist: 1,
        msg: '用户名已经存在'
    };
    let str = JSON.stringify(data);
    response.send(`handle(${str})`);
});</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
    //获取input元素
    const input = document.querySelector('input');
    const p = document.querySelector('p');

    // 声明handle函数
    function handle(data) {
        input.style.border = '1px solid red';
        //修改p标签的提示文本
        p.innerHTML = data.msg;
    }

    //绑定事件
    input.onblur = function () {
        //获取用户输入的值
        let username = this.value;
        //向服务器发送请求 检测用户名是否存在
        //1、创建script标签
        const script = document.createElement('script');
        //2、设置script标签的src属性
        script.src = 'http://127.0.0.1:8000/check-username';
        //3、将script标签添加到页面中
        document.body.appendChild(script);
    };
&lt;/script&gt;</code></pre>
<h4 style="" id="jquery%E5%8F%91%E9%80%81jsonp">jQuery发送JSONP</h4>
<pre><code class="language-javascript">app.all('/jquery-jsonp-server', (request, response) =&gt; {
    // response.send('HELLO IE! 2~~~');
    const data = {
        name: '中国',
        city: ['北京', '上海', '青岛']
    };
    let str = JSON.stringify(data);
    // 接受callback参数
    let cb = request.query.callback;
    // 拼接数据
    response.send(`${cb}(${str})`);
});</code></pre>
<pre><code class="language-html">&lt;button&gt;点击发送jsonp请求&lt;/button&gt;
&lt;div id="result"&gt;&lt;/div&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
    $('button').eq(0).click(function () {
        $.getJSON('http://127.0.0.1:8000/jquery-jsonp-server?callback=?', function (data) {
            // console.log(data);
            $('#result').html(
                `
                 名称：${data.name}&lt;br&gt;
                 城市: ${data.city}
                `
            );
        });
    });
&lt;/script&gt;</code></pre>
<h3 style="" id="cors">CORS</h3>
<blockquote>
 <p style="">CORS(Cross-Origin Resource Sharing)，跨域资源共享。</p>
 <p style="">CORS 是官方的跨域解决方案，它的特点是不需要在客户端做任何特殊的操作，完全在服务器中进行处理，支持 get 和 post 请求。跨域资源共享标准新增了一组 HTTP 首部字段，允许服务器声明哪些 源站通过浏览器有权限访问哪些资源。</p>
</blockquote>
<pre><code class="language-html">&lt;button&gt;点击发送jsonp请求&lt;/button&gt;
&lt;div id="result"&gt;&lt;/div&gt; </code></pre>
<pre><code class="language-javascript">javas//cors
app.all('/cors-server', (request, response) =&gt; {
    //设置响应头
    response.setHeader('Access-Control-Allow-Origin', '*');
    response.setHeader('Access-Control-Allow-Headers', '*');
    response.setHeader('Access-Control-Allow-Method', '*');
    response.send('hello cors');
});</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
    const btn = document.querySelector('button');

    btn.onclick = function () {
        //1. 创建对象
        const xhr = new XMLHttpRequest();
        //2. 设置请求方法和url
        xhr.open('GET', 'http://127.0.0.1:8000/cors-server');
        //3. 发送
        xhr.send();
        //4. 监听事件
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status &gt;= 200 &amp;&amp; xhr.status &lt; 300) {
                    console.log(xhr.response);
                }
            }
        };
    };
&lt;/script&gt;</code></pre>
<p style=""></p>]]></description><guid isPermaLink="false">/2025/ajax</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fajax.webp&amp;size=m" type="image/jpeg" length="8328"/><category>JavaScript</category><pubDate>Wed, 12 Mar 2025 04:34:57 GMT</pubDate></item><item><title><![CDATA[Jquery]]></title><link>https://w-flac.org.cn/2025/jqurey</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=Jquery&amp;url=/2025/jqurey" width="1" height="1" alt="" style="opacity:0;">
<p style=""><span style="font-size: 18px; color: rgb(102, 102, 102)">jQuery是一个快速的、小型的、具有丰富功能的JavaScript库。它的出现使得网页中的DOM、事件、动画、Ajax等操作变得更加简单。“写更少的代码，做更多的事儿”是jQuery一直坚信的开发理念。</span></p>
<hr>
<h3 style="" id="%3E%E5%BC%95%E5%85%A5jquery">&gt;引入jQuery</h3>
<blockquote>
 <h4 style="" id="%E5%AE%98%E6%96%B9%E4%B8%8B%E8%BD%BD"><a href="https://jquery.com/" target="_blank">官方下载</a></h4>
</blockquote>
<pre><code class="language-javascript">&lt;scripts src="path/to/jquery.xx.js" &gt; &lt;/script&gt;</code></pre>
<p style="">引入 jQuery 库，实际就是向网页添加了一个新的函数$(jQuery)。</p>
<p style="">$ 是 jQuery 中的核心函数，jQuery 的所有功能都是通过该函数来进行的，</p>
<h3 style="" id="%3Ejquery-%E7%9A%84%E6%A0%B8%E5%BF%83%E5%87%BD%E6%95%B0">&gt;jQuery 的核心函数</h3>
<blockquote>
 <h4 style="" id="%E4%BD%9C%E4%B8%BA%E5%B7%A5%E5%85%B7%E4%BD%BF%E7%94%A8">作为工具使用</h4>
 <ul>
  <li>
   <p style="">jQuery.contains()</p>
  </li>
  <li>
   <p style="">jQuery.isArray()</p>
  </li>
  <li>
   <p style="">jQuery.isFunction()</p>
  </li>
  <li>
   <p style="">jQuery.isNumeric()</p>
  </li>
  <li>
   <p style="">……</p>
  </li>
 </ul>
</blockquote>
<pre><code class="language-javascript">var num = 10
fuction fn(){}
console.log($.isFunction(num)) // false
console.log($.inFunction(fn))  // true</code></pre>
<blockquote>
 <h4 style="" id="%E4%BD%9C%E4%B8%BA%E5%87%BD%E6%95%B0%E4%BD%BF%E7%94%A8">作为函数使用</h4>
</blockquote>
<ul>
 <li>
  <p style="">将一个函数作为$的参数，这个函数会在文档加载完毕之后执行，相当于<code>document.addEventListener("DOMContentLoaded",function(){})</code></p>
 </li>
</ul>
<pre><code class="language-javascript">$(function(){
  alert("核心函数执行了~~")
}) //文档加载完毕后执行

alert("核心函数外部~~")</code></pre>
<ul>
 <li>
  <p style="">将选择器字符串作为参数，jQuery 自动去网页查找元素。类似于<code>document.querySelectorAll("...")</code></p>
 </li>
</ul>
<pre><code>&lt;button id="btn"&gt;&lt;/button&gt;
&lt;button id="btn01"&gt;&lt;/button&gt;</code></pre>
<pre><code class="language-javascript">$(function(){
  $("#btn").click(function(){
    alert("你点了我哦~")
  })
})</code></pre>
<p style="">需要注意的是，通过 jquery 核心函数查询到的结果并不是原生 DOM，而是经过包装的新对象，我们称之为 jquery 对象。</p>
<p style="">jquery对象中为我们提供了很多新的方法，方便我们做各种DOM 操作 ，但是jquery对象不能直接调用原生 DOM 对象的方法。</p>
<p style="">通过我们为 jquery 对象命名时，会使用$开头加以区分。</p>
<pre><code>var $box1 = $("#box1") // 获取id为box1的元素
var $news = $(".news") // 获取class为news的元素
var $hello = $("[title=hello]") // 获取title属性为hello的元素</code></pre>
<pre><code class="language-javascript">$(function () {

    $("#btn").click(function () {

        // alert("你点我干嘛~~")

        var btn = document.getElementById("btn01"); // [object HTMLButtonElement]

        var $btn = $("#btn01"); // [object Object]

    });
});</code></pre>
<blockquote>
 <h4 style="" id="%E5%B0%86-dom-%E5%AF%B9%E8%B1%A1%E4%BD%9C%E4%B8%BA%E5%8F%82%E6%95%B0">将 DOM 对象作为参数</h4>
</blockquote>
<p style="">可以将 DOM 对象转换为 jquery 对象，从而使用 jquery 对象的方法。</p>
<pre><code class="language-javascript">var box1 = document.getElementById("box1") // 获取DOM对象
var $box1 = $(box1) // 转换为jQuery对象</code></pre>
<pre><code class="language-javascript"> $(function () {

    $("#btn").click(function () {

        // alert("你点我干嘛~~")

        var btn = document.getElementById("btn01"); // [object HTMLButtonElement]

        var $btn = $("#btn"); // [object Object]
        
        alert($(btn))

    });
});</code></pre>
<blockquote>
 <h4 style="" id="%E5%B0%86-html-%E4%BB%A3%E7%A0%81%E4%BD%9C%E4%B8%BA%E5%8F%82%E6%95%B0">将 HTML 代码作为参数</h4>
</blockquote>
<p style="">会根据 html 代码来创建元素</p>
<pre><code class="language-javascript">$(function () {

    $("#btn").click(function () {

        var $h1 = $("&lt;h1&gt;我是一个标题&lt;/h1&gt;"); // 会根据html代码创建元素

        $("div").append($h1);

    });
});</code></pre>
<h3 style="" id="%3Ejquery%E5%AF%B9%E8%B1%A1">&gt;jQuery对象</h3>
<p style="">通过 jQuery 核心函数获取到的对象就是jQuery对象。</p>
<p style="">jQuery对象是jQuery中定义的对象，可以将其理解为是DOM对象的升级版；在jQuery对象中为我们提供了很多简单易用的方法，来帮助我们简化DOM操作。</p>
<pre><code class="language-html">- jQuery对象本质上是一个DOM对象的数组（类数组）
  可以通过索引获取jQuery对象中的DOM对象

&lt;button id="btn01"&gt;点我一下&lt;/button&gt;
&lt;ul&gt;
    &lt;li id="swk"&gt;孙悟空&lt;/li&gt;
    &lt;li id="zbj"&gt;猪八戒&lt;/li&gt;
    &lt;li&gt;沙和尚&lt;/li&gt;
    &lt;li&gt;唐僧&lt;/li&gt;
    &lt;li&gt;白骨精&lt;/li&gt;
&lt;/ul&gt;

&lt;script&gt;
  $("#btn01").click(function () {
      var $li = $("li")
      // alert($li[0].textContent)
      
      var text = $li.text() // 读取文本，返回所有标签中的文本
      var id = $li.attr("id") // 读取属性时，返回第一个标签的属性
      alert(id)
  })
&lt;/script&gt;</code></pre>
<h4 style="" id="%E9%9A%90%E5%BC%8F%E8%BF%AD%E4%BB%A3">隐式迭代</h4>
<p style="">当我们修改jQuery对象时，它会自动修改jQuery中的所有元素，这一特点称为jQuery的隐式迭代。</p>
<pre><code class="language-html">&lt;script&gt;
  $("#btn01").click(function () {
      var $li = $("li")    
      $li.text("新的文本内容")
  })
&lt;/script&gt;</code></pre>
<h4 style="" id="%E9%93%BE%E5%BC%8F%E8%B0%83%E7%94%A8">链式调用</h4>
<p style="">通常情况下，jQuery对象方法的返回值依然是一个jQuery对象。所以我们可以在调用一个方法后，继续调用其他的jQuery对象的方法。这一特性，称为jQuery对象的 链式调用</p>
<pre><code class="language-html">&lt;script&gt;
  $("#btn01").click(function () {
      var $li = $("li")
      $li.text("新的文本内容").css({"color":"red"})
  })
&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E9%80%89%E6%8B%A9%E5%99%A8%E9%9B%86%E5%90%88">&gt;选择器集合</h3>
<h4 style="" id="%E5%9F%BA%E7%A1%80%E9%80%89%E6%8B%A9%E5%99%A8">基础选择器</h4>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 971px">
  <colgroup>
   <col style="width: 205px">
   <col style="width: 203px">
   <col style="width: 563px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <th colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">选择器</p>
    </th>
    <th colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">名称</p>
    </th>
    <th colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">举例</p>
    </th>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">id选择器</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">$("ID属性值")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">选择 id 为指定的元素对象</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">类选择器</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">$(".class属性值")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">选择 class 为指定值的元素</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">元素选择器</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">$("标签名/元素名")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">选择所有指定标签元素的对象</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">选择所有元素</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">$("*")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">选中页面中所有的元素的对象</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">组合选择器</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">选择器1，选择器2...</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">选择指定选择器中的元素对象</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<pre><code class="language-vbscript-html">&lt;div id="mydiv1" class="blue"&gt;元素选择器&lt;/div&gt;
&lt;div id="mydiv1"&gt;id选择器1&lt;span&gt;span中的内容&lt;/span&gt;&lt;/div&gt;
&lt;span class="blue"&gt;样式选择器&lt;/span&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;

// id选择器
var $mydiv = $("#mydiv");
console.log($mydiv)

// 类选择器
var $class = $(".blue")
console.log($class)

// 元素选择器
var $span = $("span")
console.log($span)

// 通用选择器
var $all = $("*")
console.log($all)

&lt;/script&gt;</code></pre>
<h4 style="" id="%E5%B1%82%E6%AC%A1%E9%80%89%E6%8B%A9%E5%99%A8">层次选择器</h4>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 971px">
  <colgroup>
   <col style="width: 205px">
   <col style="width: 203px">
   <col style="width: 563px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <th colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">选择器</p>
    </th>
    <th colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">名称</p>
    </th>
    <th colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">举例</p>
    </th>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">后代选择器</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">$("父元素 指定元素")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">选择父元素的所有指定元素(包含第一代、第二代)</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">子代选择器</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">$("父元素 &gt; 指定元素")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">选择父元素的所有第一代指定元素</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">相邻选择器</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">$("元素 + 指定元素")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">选择元素下一个指定元素(如果元素不存在，则获取不到)</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">同辈选择器</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">$("元素 ~ 指定元素")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">选择元素下面的所有指定元素</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<p style=""></p>
<h4 style="" id="%E8%A1%A8%E5%8D%95%E9%80%89%E6%8B%A9%E5%99%A8">表单选择器</h4>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 971px">
  <colgroup>
   <col style="width: 205px">
   <col style="width: 203px">
   <col style="width: 563px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center"><strong>Forms</strong></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center"><strong>名称</strong></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">举例</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">表单选择器</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">:input</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">查找所有的input元素：$(":input")；</p>
     <p style="text-align: center">注意：会匹配所有的input、textarea、select和button元素。</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">文本框选择器</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">:text</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">查找所有⽂本框：$(":text")</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">密码框选择器</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">:password</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">查找所有密码框：$(":password")</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205">
     <p style="text-align: center">单选按钮选择器</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203">
     <p style="text-align: center">:radio</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563">
     <p style="text-align: center">查找所有单选按钮：$(":radio")</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205" style="padding: 6px 13px; color: rgb(40, 56, 75); font-size: 10pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: &quot;PingFang SC&quot;; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center; height: 16pt; width: 103pt;">
     <p style="text-align: center"><span style="font-size: 16px">复选框选择器</span></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203" style="padding: 6px 13px; color: black; font-size: 12pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: 等线; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center; width: 88pt;">
     <p style="text-align: center">:checkbox</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563" style="padding: 6px 13px; color: black; font-size: 12pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: 等线; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center; width: 272pt;">
     <p style="text-align: center">查找所有复选框：$(“:checkbox”)</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205" style="padding: 6px 13px; color: rgb(40, 56, 75); font-size: 10pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: &quot;PingFang SC&quot;; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center; height: 16pt;">
     <p style="text-align: center"><span style="font-size: 16px">提交按钮选择器</span></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203" style="padding: 6px 13px; color: black; font-size: 12pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: 等线; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center;">
     <p style="text-align: center">:submit</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563" style="padding: 6px 13px; color: black; font-size: 12pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: 等线; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center;">
     <p style="text-align: center">查找所有提交按钮：$(“:submit”)</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205" style="padding: 6px 13px; color: rgb(40, 56, 75); font-size: 10pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: &quot;PingFang SC&quot;; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center; height: 16pt;">
     <p style="text-align: center"><span style="font-size: 16px">图像域选择器</span></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203" style="padding: 6px 13px; color: black; font-size: 12pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: 等线; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center;">
     <p style="text-align: center">:image</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563" style="padding: 6px 13px; color: black; font-size: 12pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: 等线; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center;">
     <p style="text-align: center">查找所有图像域：$(“:image”)</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205" style="padding: 6px 13px; color: rgb(40, 56, 75); font-size: 10pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: &quot;PingFang SC&quot;; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center; height: 16pt;">
     <p style="text-align: center"><span style="font-size: 16px">重置按钮选择器</span></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203" style="padding: 6px 13px; color: black; font-size: 12pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: 等线; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center;">
     <p style="text-align: center">:reset</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563" style="padding: 6px 13px; color: black; font-size: 12pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: 等线; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center;">
     <p style="text-align: center">查找所有重置按钮：$(“:reset”)</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205" style="padding: 6px 13px; color: rgb(40, 56, 75); font-size: 10pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: &quot;PingFang SC&quot;; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center; height: 16pt;">
     <p style="text-align: center"><span style="font-size: 16px">按钮选择器</span></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203" style="padding: 6px 13px; color: black; font-size: 12pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: 等线; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center;">
     <p style="text-align: center">:button</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563" style="padding: 6px 13px; color: black; font-size: 12pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: 等线; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center;">
     <p style="text-align: center">查找所有按钮：$(“:button”)</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="205" style="padding: 6px 13px; color: rgb(40, 56, 75); font-size: 10pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: &quot;PingFang SC&quot;; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center; height: 16pt;">
     <p style="text-align: center"><span style="font-size: 16px">⽂件域选择器</span></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="203" style="padding: 6px 13px; color: black; font-size: 12pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: 等线; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center;">
     <p style="text-align: center">:file</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="563" style="padding: 6px 13px; color: black; font-size: 12pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: 等线; vertical-align: middle; border: 1px solid rgb(221, 221, 221); white-space: nowrap; box-sizing: border-box; text-align: center;">
     <p style="text-align: center">查找所有⽂件域：$(“:file”)</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<h3 style="" id="%3E%E6%93%8D%E4%BD%9C%E5%B1%9E%E6%80%A7%E7%9A%84%E5%85%83%E7%B4%A0">&gt;操作属性的元素</h3>
<blockquote>
 <h4 style="" id="%E8%8E%B7%E5%8F%96%E5%B1%9E%E6%80%A7-attr">获取属性 attr</h4>
 <p style="">固有属性：元素本身就有的属性(id、name、class、style)，返回值是 Boolean 的属性：checked、selected、disabled</p>
 <p style="">自定义属性：用户自己定义的属性</p>
</blockquote>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 971px">
  <colgroup>
   <col style="width: 392px">
   <col style="width: 579px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="392">
     <p style="text-align: center"><strong>方法</strong></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="579">
     <p style="text-align: center"><strong>说明</strong></p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="392">
     <p style="text-align: center">attr(属性名)</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="579">
     <p style="text-align: center">设置/获取元素的指定属性</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="392">
     <p style="text-align: center">prop(属性名)</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="579">
     <p style="text-align: center">获取具有 true和false的属性值</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<blockquote>
 <p style="">所以，attr()和prop()的区别是什么?</p>
 <ol>
  <li>
   <p style="">如果是固有属性，attr 和 prop 方法均可操作。</p>
  </li>
  <li>
   <p style="">如果是自定义属性，attr 可操作，prop 不可操作。</p>
  </li>
  <li>
   <p style="">如果返回值是 boolean 类型的属性，若设置了属性，attr 返回具体的值，prop 返回 true，反之 undefined 和 false。</p>
  </li>
 </ol>
</blockquote>
<pre><code class="language-vbscript-html">&lt;input abd="aabbcc" checked="checked" id="aa" name="ch" type="checkbox"/&gt; aa
&lt;input id="bb" name="ch" type="checkbox"/&gt; bb

&lt;script&gt;
    var name = $("#aa").attr("name");
    console.log(name); //ch
    var name2 = $("#aa").prop("name");
    console.log(name2); //ch
    // 返回值是 boolean 的属性 （元素设置了属性）
    var c1 = $("#aa").attr("checked");
    console.log(c1); //checked
    var c2 = $("#aa").prop("checked");
    console.log(c2); //true
    // 返回值是 boolean 的属性 （元素未设置属性）
    var c3 = $("#bb").attr("checked");
    console.log(c3); //undefined
    var c4 = $("#bb").prop("checked");
    console.log(c4); //false
    // 自定义属性
    var abc1 = $("#aa").attr("abd");
    console.log(abc1); //aabbcc
    var abc2 = $("#aa").prop("abd");
    console.log(abc2); //undefined
&lt;/script&gt;</code></pre>
<blockquote>
 <h4 style="" id="%E8%AE%BE%E7%BD%AE%E5%B1%9E%E6%80%A7-prop">设置属性 prop</h4>
</blockquote>
<pre><code class="language-vbscript-html">&lt;input abd="aabbcc" checked="checked" id="aa" name="ch" type="checkbox"/&gt; aa
&lt;input id="bb" name="ch" type="checkbox"/&gt; bb

&lt;script&gt;
    // 固有属性
    $('#aa').attr("value", "123");
    $('#bb').prop("value", "456");
    // 返回值是 boolean 的属性
    $('#aa').attr("checked", false);
    $('#bb').prop("checked", "checked");
    // 自定义属性
    $('#aa').attr("username", "admin");
    $('#bb').prop("username", "guest"); // prop() 不会解析 boolean 值
&lt;/script&gt;</code></pre>
<blockquote>
 <h4 style="" id="%E7%A7%BB%E9%99%A4%E5%B1%9E%E6%80%A7-removeattr">移除属性 removeAttr</h4>
</blockquote>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 983px">
  <colgroup>
   <col style="width: 363px">
   <col style="width: 620px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="363">
     <p style="text-align: center"><strong>方法</strong></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="620">
     <p style="text-align: center"><strong>说明</strong></p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="363">
     <p style="text-align: center">removeAttr(”属性名“)</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="620">
     <p style="text-align: center">移除元素的指定属性</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<pre><code class="language-vbscript-html">&lt;script&gt;
    var name = $("#aa").removeAttr("checked");
&lt;/script&gt;</code></pre>
<blockquote>
 <p style="">总结：</p>
 <p style="">如果属性的类型是 boolean，则使用 prop( )方法，反之使用 attr( )方法。</p>
</blockquote>
<h3 style="" id="%3E%E6%93%8D%E4%BD%9C%E5%85%83%E7%B4%A0%E7%9A%84%E6%A0%B7%E5%BC%8F">&gt;操作元素的样式</h3>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 984px">
  <colgroup>
   <col style="width: 355px">
   <col style="width: 629px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center"><strong>方法</strong></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center"><strong>说明</strong></p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">attr("class")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">获取 class 属性的值，即样式名称</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">attr("class","样式名")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">修改 class 属性的值，会覆盖原始样式</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">addClass(”样式名“)</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">添加样式的名称</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">css( )</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">添加具体的样式</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">removeClass("样式名")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">移除样式名称</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<blockquote>
 <p style="">添加元素的具体样式</p>
 <p style="">1)）css({'样式名':'样式值'，'样式名2','样式值2'})</p>
 <p style="">例：css({'background-color':'red','color':'#fff'});</p>
 <p style="">2）css('样式名','样式值')</p>
 <p style="">例：css('color','white')</p>
</blockquote>
<pre><code class="language-vbscript-html">&lt;script&gt;
    $("#aa").attr('color','blue');
    $("#aa").addClass('px-2');
    $("#aa").css({'background-color':'red','color':'#fff'});
    $("#aa").removeClass("px-2")
&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E6%93%8D%E4%BD%9C%E5%85%83%E7%B4%A0%E7%9A%84%E5%86%85%E5%AE%B9">&gt;操作元素的内容</h3>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 984px">
  <colgroup>
   <col style="width: 355px">
   <col style="width: 629px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center"><strong>方法</strong></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center"><strong>说明</strong></p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">html( )</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">获取元素的 html 内容（非表单元素）</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">html("html","内容")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">设置元素的 html 内容（非表单元素）</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">text( )</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">获取元素的文本内容，不包含 html（非表单元素）</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">text("html","内容")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">设置元素的文本内容，不包含 html （非表单元素）</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">var( )</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">获取元素value 值（表单元素）</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">var('值')</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">设定元素的 value 值（表单元素）</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<blockquote>
 <p style="">表单元素：</p>
 <p style="">文本框 text；密码框 password；单选框 radio；复选框 checkbox；隐藏域 hidden；文本域 textarea；下拉框select</p>
 <p style="">非表单元素：</p>
 <p style="">div；span；h1~h6；ul；li...</p>
</blockquote>
<pre><code class="language-vbscript-html">&lt;div id="html1"&gt;&lt;/div&gt;
&lt;div id="html2"&gt;&lt;/div&gt;
&lt;div id="text"&gt;&lt;/div&gt;
&lt;input type="text" name="username" id="oop" value="oop" /&gt; 

&lt;script&gt;
    // 非表单元素
    $("#html1").html("青岛");
    $("#html2").html("&lt;h2&gt;TsingTao&lt;h2&gt;");
    $("#text").text("山东") //山东
    $("#text").text("&lt;h2&gt;TsingTao&lt;h2&gt;") // &lt;h2&gt;TsingTao&lt;h2&gt;
    // 表单元素
    $("#oop").var("青岛啤酒")
&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E5%88%9B%E5%BB%BA%E4%B8%8E%E6%B7%BB%E5%8A%A0%E5%85%83%E7%B4%A0">&gt;创建与添加元素</h3>
<blockquote>
 <h4 style="" id="%E5%88%9B%E5%BB%BA%E5%85%83%E7%B4%A0">创建元素</h4>
</blockquote>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 984px">
  <colgroup>
   <col style="width: 355px">
   <col style="width: 629px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center"><strong>方法</strong></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center"><strong>说明</strong></p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$('元素内容')</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">$('&lt;p&gt;欢迎来到青岛&lt;/p&gt;')</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<pre><code class="language-javascript">&lt;script&gt;
    var p = $('&lt;p&gt;欢迎来到青岛&lt;/p&gt;')
&lt;/script&gt;</code></pre>
<blockquote>
 <h4 style="" id="%E6%B7%BB%E5%8A%A0%E5%85%83%E7%B4%A0">添加元素</h4>
</blockquote>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 984px">
  <colgroup>
   <col style="width: 355px">
   <col style="width: 629px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center"><strong>方法</strong></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center"><strong>说明</strong></p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">(指定元素).prepend("内容")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">在指定元素内部的最前面追加内容</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("内容").prependTo("指定元素")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">把内容追加到指定元素内部最前面</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">(指定元素).append"内容")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">在指定元素内部最后面追加内容</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("内容").appendTo("指定元素")</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">把内容追加到指定元素内部最后面</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").before( )</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">在指定元素的前面追加内容</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").after( )</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">在指定元素的后面追加内容</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").wrap()</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">为当前元素添加一个容器</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").wrapAll()</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">为当前所有元素统一添加一个容器</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").wrapInner()</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">为当前元素添加一个内部容器</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<pre><code class="language-vbscript-html">&lt;div id="html"&gt;&lt;/div&gt;
&lt;div id="text"&gt;&lt;/div&gt;

&lt;script&gt;
    // 创建元素
    var test = "&lt;span class='bg-black text-sm'&gt;china&lt;/span&gt;"
    $("html").prepend(test)
    $(test).prependTo("#html")

    var test2 = "&lt;span class='bg-black text-sm'&gt;TsingTao&lt;/span&gt;"
    $("#text").before("test2")
&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E5%88%A0%E9%99%A4%E5%85%83%E7%B4%A0">&gt;删除元素</h3>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 984px">
  <colgroup>
   <col style="width: 355px">
   <col style="width: 629px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center"><strong>方法</strong></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center"><strong>说明</strong></p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").remove()</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">完全删除(事件清空)</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").empty()</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">清空所有的子元素</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").detach()</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">删除元素(不会清空事件)</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").unwrap()</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">删除外层父元素</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<pre><code class="language-vbscript-html">&lt;div id="html"&gt;&lt;/div&gt;
&lt;div id="text"&gt;&lt;/div&gt;

&lt;script&gt;
    $("html").remove()
    $("text").detach()
&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E5%A4%8D%E5%88%B6%E5%85%83%E7%B4%A0">&gt;复制元素</h3>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 984px">
  <colgroup>
   <col style="width: 355px">
   <col style="width: 629px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center"><strong>方法</strong></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center"><strong>说明</strong></p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").clone()</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">用来复制 jQuery 对象</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<pre><code class="language-vbscript-html">&lt;button id="btn"&gt; 点我一下 &lt;/button&gt;

&lt;ul id="list"&gt;
    &lt;li&gt;孙悟空&lt;/li&gt;
    &lt;li&gt;猪八戒&lt;/li&gt;
&lt;/ul&gt;

&lt;ul id="list2"&gt;
    &lt;li&gt;沙和尚&lt;/li&gt;
    &lt;li&gt;唐僧&lt;/li&gt;
&lt;/ul&gt;


&lt;script&gt;
    $(function(){
    
        $("#list li:nth-child(1)").click(function(){
            alert("孙悟空")
        })
    
        var $swk = $("#list li:nth-child(1)").clone(true)
        var $list2 = $("#list2")
    
        $("#btn").click(function(){
            $list2.append($swk)
        })
    })  
&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E7%AD%9B%E9%80%89%E6%96%B9%E6%B3%95">&gt;筛选方法</h3>
<div style="overflow-x: auto; overflow-y: hidden;">
 <table style="width: 984px">
  <colgroup>
   <col style="width: 355px">
   <col style="width: 629px">
  </colgroup>
  <tbody>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center"><strong>方法</strong></p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center"><strong>说明</strong></p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").eq( )</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">获取 jQuery 对象中指定索引的元素</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("内容").first( )</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">获取第一个元素</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").last( )</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">获取最后一个元素</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").even( )</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">获取索引为偶数的元素</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").odd( )</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">获取索引为基数的元素</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").slice( )</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">截取元素（切片）</p>
    </td>
   </tr>
   <tr style="height: 60px;">
    <td colspan="1" rowspan="1" colwidth="355">
     <p style="text-align: center">$("元素").filter( )</p>
    </td>
    <td colspan="1" rowspan="1" colwidth="629">
     <p style="text-align: center">过滤筛选元素</p>
    </td>
   </tr>
  </tbody>
 </table>
</div>
<pre><code class="language-vbscript-html">&lt;button id="btn"&gt; 点我一下 &lt;/button&gt;

&lt;div class="box1"&gt;&lt;/div&gt;
&lt;div class="box1"&gt;&lt;/div&gt;
&lt;div class="box1 a"&gt;&lt;/div&gt;
&lt;div class="box1 a"&gt;&lt;/div&gt;
&lt;div class="box1"&gt;&lt;/div&gt;

&lt;script&gt;
    $(function(){ 
        $("#btn").click(function(){
           $(".box1").eq()
           $(".box1").filter(".a").css("background-color", "#bfa")
        })
    })  
&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E4%BA%8B%E4%BB%B6%E7%BB%91%E5%AE%9A">&gt;事件绑定</h3>
<blockquote>
 <h4 style="" id="%E9%80%9A%E8%BF%87%40%E6%8C%87%E5%AE%9A%E6%96%B9%E6%B3%95">通过@<a href="https://api.jquery.com/category/events/" target="_blank">指定方法 </a></h4>
</blockquote>
<pre><code class="language-vbscript-html">&lt;a href="#"&gt;超链接&lt;/a&gt;

&lt;script&gt;
    $(function(){ 
        $(".a").click(function(event){
             event.stopPropagation()
             event.preventDefault()
        })
    })  
&lt;/script&gt;</code></pre>
<blockquote>
 <h4 style="" id="%E9%80%9A%E8%BF%87-on(-)-%E6%96%B9%E6%B3%95">通过 on( ) 方法</h4>
</blockquote>
<pre><code class="language-vbscript-html">&lt;button id="btn1"&gt; 点我一下 &lt;/button&gt;
&lt;button id="btn2"&gt; 点我一下 &lt;/button&gt;

&lt;div class="box1"&gt;&lt;/div&gt;
&lt;div class="box1"&gt;&lt;/div&gt;
&lt;div class="box1"&gt;&lt;/div&gt;
&lt;div class="box1"&gt;&lt;/div&gt;
&lt;div class="box1"&gt;&lt;/div&gt;

&lt;script&gt;
     // on()可以通过on()方法来绑定事件
     $("#btn1").on("click.a", function(){
          alert("通过on绑定的事件！")
     })

     // off()可以用来取消事件绑定
     $("#btn2").on("click.a", function(){
          $("#btn1").off("click")
     })
     // 为所有box1的类添加事件委托
     $(document).on("click",".box1", function(event){
         alert("哈哈")
     })  
&lt;/script&gt;</code></pre>
<blockquote>
 <h4 style="" id="%E9%80%9A%E8%BF%87-one(-)-%E6%96%B9%E6%B3%95">通过 one( ) 方法</h4>
</blockquote>
<pre><code class="language-vbscript-html">&lt;script&gt;
    // one()用来绑定一个一次性的事件
    $(".box1").one("click", function(){
        alert('嘻嘻')
    })
&lt;/script&gt;</code></pre>
<h3 style="" id="%3Ejquery%E6%96%B9%E6%B3%95">&gt;jQuery方法</h3>
<h4 style="" id=".addclass()">.addClass()</h4>
<ul>
 <li>
  <p style="">为jQuery对象添加一个或多个class</p>
 </li>
</ul>
<h4 style="" id=".hasclass()">.hasClass()</h4>
<ul>
 <li>
  <p style="">检查jQuery对象是否含有某个class</p>
 </li>
</ul>
<h4 style="" id=".toggleclass()">.toggleClass()</h4>
<ul>
 <li>
  <p style="">切换jQuery对象的指定class</p>
 </li>
</ul>
<h4 style="" id=".insertafter()">.insertAfter()</h4>
<ul>
 <li>
  <p style="">将元素添加到某元素的后边</p>
 </li>
</ul>
<h4 style="" id=".insertbefore()">.insertBefore()</h4>
<ul>
 <li>
  <p style="">将元素添加到某元素的前边</p>
 </li>
</ul>
<h4 style="" id=".replaceall()">.replaceAll()</h4>
<ul>
 <li>
  <p style="">替换某个元素</p>
 </li>
</ul>
<h4 style="" id=".replacewith()">.replaceWith()</h4>
<ul>
 <li>
  <p style="">被某个元素替换</p>
 </li>
</ul>
<h4 style="" id=".height()">.height()</h4>
<ul>
 <li>
  <p style="">读取/设置元素的高度</p>
 </li>
</ul>
<h4 style="" id=".width()">.width()</h4>
<ul>
 <li>
  <p style="">读取/设置元素的宽度</p>
 </li>
</ul>
<h4 style="" id=".innerheight()">.innerHeight()</h4>
<ul>
 <li>
  <p style="">读取/设置元素的内部高度</p>
 </li>
</ul>
<h4 style="" id=".innerwidth()">.innerWidth()</h4>
<ul>
 <li>
  <p style="">读取/设置元素的内部宽度</p>
 </li>
</ul>
<h4 style="" id=".outerheight()">.outerHeight()</h4>
<ul>
 <li>
  <p style="">读取/设置元素可见框的高度</p>
 </li>
</ul>
<h4 style="" id=".outerwidth()">.outerWidth()</h4>
<ul>
 <li>
  <p style="">读取/设置元素可见框的宽度</p>
 </li>
</ul>
<h4 style="" id=".offset()">.offset()</h4>
<ul>
 <li>
  <p style="">读取/设置元素的偏移量</p>
 </li>
</ul>
<h4 style="" id=".position()">.position()</h4>
<ul>
 <li>
  <p style="">读取元素相当于包含块的偏移量</p>
 </li>
</ul>
<h4 style="" id=".scrollleft()">.scrollLeft()</h4>
<ul>
 <li>
  <p style="">读取/设置元素水平滚动条的位置</p>
 </li>
</ul>
<h4 style="" id=".scrolltop()">.scrollTop()</h4>
<ul>
 <li>
  <p style="">读取/设置元素垂直滚动条的位置</p>
 </li>
</ul>
<h4 style="" id=".has()">.has()</h4>
<ul>
 <li>
  <p style="">获取含有指定后代的元素</p>
 </li>
</ul>
<h4 style="" id=".is()">.is()</h4>
<ul>
 <li>
  <p style="">检查是否含有某元素</p>
 </li>
</ul>
<h4 style="" id=".map()">.map()</h4>
<ul>
 <li>
  <p style="">获取对象中的指定数据</p>
 </li>
</ul>
<h4 style="" id=".add()">.add()</h4>
<ul>
 <li>
  <p style="">创建包含当前元素的新的jQuery对象</p>
 </li>
</ul>
<h4 style="" id=".addback()">.addBack()</h4>
<ul>
 <li>
  <p style="">将之前操作的集合中的元素添加到当前集合中</p>
 </li>
</ul>
<h4 style="" id=".contents()">.contents()</h4>
<ul>
 <li>
  <p style="">获取当前jQuery对象的所有子节点（包括文本节点）</p>
 </li>
</ul>
<h4 style="" id=".end()">.end()</h4>
<ul>
 <li>
  <p style="">将筛选过的列表恢复到之前的状态</p>
 </li>
</ul>
<h4 style="" id=".not()">.not()</h4>
<ul>
 <li>
  <p style="">从列表中去除符合条件的元素</p>
 </li>
</ul>
<h4 style="" id=".children()">.children()</h4>
<ul>
 <li>
  <p style="">获取子元素</p>
 </li>
</ul>
<h4 style="" id=".closest()">.closest()</h4>
<ul>
 <li>
  <p style="">获取离当前元素最近的指定元素</p>
 </li>
</ul>
<h4 style="" id=".find()">.find()</h4>
<ul>
 <li>
  <p style="">查询指定的后代元素</p>
 </li>
</ul>
<h4 style="" id=".next()">.next()</h4>
<ul>
 <li>
  <p style="">获取后一个兄弟元素</p>
 </li>
</ul>
<h4 style="" id=".nextall()">.nextAll()</h4>
<ul>
 <li>
  <p style="">获取后边所有的兄弟元素</p>
 </li>
</ul>
<h4 style="" id=".nextuntil()">.nextUntil()</h4>
<ul>
 <li>
  <p style="">获取后边指定位置的兄弟元素</p>
 </li>
</ul>
<h4 style="" id=".offsetparent()">.offsetParent()</h4>
<ul>
 <li>
  <p style="">获取定位父元素</p>
 </li>
</ul>
<h4 style="" id=".parent()">.parent()</h4>
<ul>
 <li>
  <p style="">获取父元素</p>
 </li>
</ul>
<h4 style="" id=".parents()">.parents()</h4>
<ul>
 <li>
  <p style="">获取所有的祖先元素</p>
 </li>
</ul>
<h4 style="" id=".parensuntil()">.parensUntil()</h4>
<ul>
 <li>
  <p style="">获取指定的祖先元素</p>
 </li>
</ul>
<h4 style="" id=".prev()">.prev()</h4>
<ul>
 <li>
  <p style="">获取前边的兄弟元素</p>
 </li>
</ul>
<h4 style="" id=".prevall()">.prevAll()</h4>
<ul>
 <li>
  <p style="">获取前边所有的兄弟元素</p>
 </li>
</ul>
<h4 style="" id=".prevuntil()">.prevUntil()</h4>
<ul>
 <li>
  <p style="">获取指定的兄弟元素</p>
 </li>
</ul>
<h4 style="" id=".siblings()">.siblings()</h4>
<ul>
 <li>
  <p style="">获取所有的兄弟元素</p>
 </li>
</ul>
<p style=""></p>]]></description><guid isPermaLink="false">/2025/jqurey</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2FjQuery.webp&amp;size=m" type="image/jpeg" length="7988"/><category>JavaScript</category><pubDate>Sun, 9 Mar 2025 00:38:38 GMT</pubDate></item><item><title><![CDATA[JavaScript - BOM]]></title><link>https://w-flac.org.cn/2025/javascript-dom</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=JavaScript%20-%20BOM&amp;url=/2025/javascript-dom" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">在 JavaScript 中，BOM（Browser Object Model）指的是浏览器对象模型，它是一种用于表示和操作浏览器窗口、文档、历史记录等对象的模型。BOM 是 JavaScript 在浏览器环境中的核心组成部分，它与 DOM（文档对象模型）一起构成了 Web 开发的基石。</p>
</blockquote>
<hr>
<h3 style="" id="bom%E7%9A%84%E5%88%86%E7%B1%BB">BOM的分类</h3>
<ul>
 <li>
  <p style=""><code>window</code> 对象：表示浏览器窗口，包含许多属性和方法，如 <code>alert()</code>、<code>confirm()</code>、<code>prompt()</code> 等。<code>window</code> 对象是 BOM 的核心，它代表了整个浏览器窗口，并且是所有其他 BOM 对象的父对象。</p>
 </li>
 <li>
  <p style=""><code>history</code> 对象：表示浏览器历史记录，包含许多属性和方法，如 <code>back()</code>、<code>forward()</code>、<code>go()</code> 等。<code>history</code> 对象使得 JavaScript 能够访问和操作浏览器的历史记录，从而实现页面导航功能。</p>
 </li>
 <li>
  <p style=""><code>navigator</code> 对象：表示浏览器的信息，包含许多属性和方法，如 <code>appName</code>、<code>appVersion</code>、<code>platform</code> 等。<code>navigator</code> 对象使得 JavaScript 能够获取浏览器的相关信息，从而实现浏览器检测功能。</p>
 </li>
 <li>
  <p style=""><code>screen</code> 对象：表示客户端屏幕的信息，包含许多属性和方法，如 <code>width</code>、<code>height</code>、<code>availWidth</code> 等。<code>screen</code> 对象使得 JavaScript 能够获取客户端屏幕的相关信息，从而实现页面布局功能。</p>
 </li>
 <li>
  <p style=""><code>location</code> 对象：表示当前页面的 URL 信息，包含许多属性和方法，如 <code>href</code>、<code>protocol</code>、<code>host</code> 等。<code>location</code> 对象使得 JavaScript 能够访问和操作当前页面的 URL，从而实现页面跳转功能。</p>
 </li>
</ul>
<h3 style="" id="%3Ewindow">&gt;<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Window" target="_blank">Window</a></h3>
<h4 style="" id="localstorage.setitem(-)">localStorage.setItem( )</h4>
<p style="">下面的代码片段访问了当前域名下的本地<code> Storage</code> 对象，并通过 Storage.setItem() 增加了一个数据项目。</p>
<pre><code class="language-javascript">localStorage.setItem("myCat", "Tom");</code></pre>
<h4 style="" id="localstorage.getitem(-)">localStorage.getItem( )</h4>
<p style="">该语法用于读取 <code>localStorage</code> 项，如下：</p>
<pre><code class="language-javascript">let cat = localStorage.getItem("myCat");
</code></pre>
<h4 style="" id="localstorage.removeitem(-)">localStorage.removeItem( )</h4>
<p style="">该语法用于移除 <code>localStorage</code> 项，如下：</p>
<pre><code class="language-javascript">localStorage.removeItem("myCat");
</code></pre>
<h4 style="" id="ocalstorage.clear()">ocalStorage.clear()</h4>
<p style="">该语法用于移除所有的 <code>localStorage</code> 项，如下：</p>
<pre><code class="language-javascript">// 移除所有
localStorage.clear();</code></pre>
<h3 style="" id="%3Enavigator">&gt;<a href="https://developer.mozilla.org/en-US/docs/Web/API/Navigator" target="_blank">Navigator</a></h3>
<blockquote>
 <p style="">用来表示浏览器的相关信息</p>
</blockquote>
<h4 style="" id="useragent-%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E7%94%A8%E6%9D%A5%E6%8F%8F%E8%BF%B0%E6%B5%8F%E8%A7%88%E5%99%A8%E4%BF%A1%E6%81%AF%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2">userAgent 返回一个用来描述浏览器信息的字符串</h4>
<pre><code class="language-javascript">&lt;script&gt;

    // console.log(navigator.userAgent)

    let sBrowser;
    const sUsrAg = navigator.userAgent;

    // The order matters here, and this may report false positives for unlisted browsers.

    if (sUsrAg.indexOf("Firefox") &gt; -1) {
        sBrowser = "Mozilla Firefox";
        // "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0"
    } else if (sUsrAg.indexOf("SamsungBrowser") &gt; -1) {
        sBrowser = "Samsung Internet";
        // "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G955F Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.4 Chrome/67.0.3396.87 Mobile Safari/537.36
    } else if (sUsrAg.indexOf("Opera") &gt; -1 || sUsrAg.indexOf("OPR") &gt; -1) {
        sBrowser = "Opera";
        // "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 OPR/57.0.3098.106"
    } else if (sUsrAg.indexOf("Trident") &gt; -1) {
        sBrowser = "Microsoft Internet Explorer";
        // "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; Zoom 3.6.0; wbx 1.0.0; rv:11.0) like Gecko"
    } else if (sUsrAg.indexOf("Edge") &gt; -1) {
        sBrowser = "Microsoft Edge (Legacy)";
        // "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299"
    } else if (sUsrAg.indexOf("Edg") &gt; -1) {
        sBrowser = "Microsoft Edge (Chromium)";
        // Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.64
    } else if (sUsrAg.indexOf("Chrome") &gt; -1) {
        sBrowser = "Google Chrome or Chromium";
        // "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/66.0.3359.181 Chrome/66.0.3359.181 Safari/537.36"
    } else if (sUsrAg.indexOf("Safari") &gt; -1) {
        sBrowser = "Apple Safari";
        // "Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1 980x1306"
    } else {
        sBrowser = "unknown";
    }
    alert(`You are using: ${sBrowser}`);
&lt;/script&gt;</code></pre>
<h3 style="" id="%3Elocation">&gt;<a href="https://developer.mozilla.org/en-US/docs/Web/API/Location" target="_blank">Location</a></h3>
<blockquote>
 <p style="">表示浏览器地址的详细信息</p>
</blockquote>
<h4 style="" id="location.assign(-)-%E8%B7%B3%E8%BD%AC%E5%88%B0%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E5%9C%B0%E5%9D%80">location.assign( ) 跳转到一个新的地址</h4>
<h4 style="" id="location.replace(-)-%E8%B7%B3%E8%BD%AC%E6%96%B0%E7%9A%84%E5%9C%B0%E5%9D%80%EF%BC%88%E6%97%A0%E6%B3%95%E5%9B%9E%E9%80%80%EF%BC%89">location.replace( ) 跳转新的地址（无法回退）</h4>
<h4 style="" id="location.reload(-)-%E5%88%B7%E6%96%B0%E9%A1%B5%E9%9D%A2%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87-true-%E6%9D%A5%E5%88%B7%E6%96%B0%E7%BC%93%E5%AD%98">location.reload( ) 刷新页面，可以通过 true 来刷新缓存</h4>
<h4 style="" id="location.href(-)-%E8%8E%B7%E5%8F%96%E5%BD%93%E5%89%8D%E5%9C%B0%E5%9D%80">location.href( ) 获取当前地址</h4>
<pre><code class="language-vbscript-html">&lt;button id=“btn”&gt; 点我一下 &lt;/button&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
    const btn = document.getElementById("btn")
    btn.addEventListener("click", () =&gt; {

        // console.log(location.href)

        // location = "https://w-flac.org.cn"

        // location.assign("https://w-flac.org.cn")

        // location.replace("https://w-flac.org.cn")

        location.reload(true)
    })
&lt;/script&gt;</code></pre>
<h3 style="" id="%3Ehistory">&gt;<a href="https://developer.mozilla.org/en-US/docs/Web/API/History" target="_blank">History</a></h3>
<blockquote>
 <p style="">表示浏览器的历史记录</p>
</blockquote>
<h4 style="" id="history.back(-)-%E5%9B%9E%E9%80%80%E6%8C%89%E9%92%AE">history.back( ) 回退按钮</h4>
<h4 style="" id="history.forward-(-)-%E5%89%8D%E8%BF%9B%E6%8C%89%E9%92%AE">history.forward ( ) 前进按钮</h4>
<h4 style="" id="history.go(-)-%E5%90%91%E5%89%8D%E6%88%96%E5%90%91%E5%90%8E">history.go( ) 向前或向后</h4>
<pre><code class="language-vbscript-html">&lt;button id=“btn”&gt; 点我一下 &lt;/button&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
    const btn = document.getElementById("btn")
    btn.onclick = () =&gt; {

        // console.log(history.length)

        // history.back()

        // history.forward()

        history.go(-1)

    }
&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E5%AE%9A%E6%97%B6%E5%99%A8">&gt;定时器</h3>
<blockquote>
 <p style="">通过定时器可以使代码在指定时间后执行</p>
</blockquote>
<h4 style="" id="settimeout(-)-%E4%BB%A3%E7%A0%81%E5%8F%AA%E6%89%A7%E8%A1%8C%E4%B8%80%E6%AC%A1">setTimeout( ) 代码只执行一次</h4>
<blockquote>
 <p style="">参数：</p>
 <ul>
  <li>
   <p style="">回调函数</p>
  </li>
  <li>
   <p style="">间隔的时间</p>
  </li>
 </ul>
 <p style="">关闭定时器：</p>
 <p style="">clearTimeout( )</p>
</blockquote>
<pre><code class="language-javascript">&lt;script&gt;

const timer = setTimeout(()=&gt;{
    alert("我是定时器中的代码")
}, 3000)

clearTimeout(timer)

&lt;/script&gt;</code></pre>
<h4 style="" id="setinterval(-)-%E4%BB%A3%E7%A0%81%E6%AF%8F%E9%97%B4%E9%9A%94%E4%B8%80%E6%AE%B5%E6%97%B6%E9%97%B4%E6%89%A7%E8%A1%8C%E4%B8%80%E6%AC%A1">setInterval( ) 代码每间隔一段时间执行一次</h4>
<blockquote>
 <p style="">参数：</p>
 <ul>
  <li>
   <p style="">回调函数</p>
  </li>
  <li>
   <p style="">间隔的时间</p>
  </li>
 </ul>
 <p style="">关闭定时器：</p>
 <p style="">clearInterval( )</p>
</blockquote>
<pre><code class="language-vbscript-html">&lt;h1 id="num"&gt;&lt;/h1&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;

const numH1 = document.getElementById("num");

let num = 0;

const timer = setInterval(() =&gt; {
    num++;
    numH1.textContent = num;

    if (num === 200) {
        clearInterval(timer);
    }
}, 30);

&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF%EF%BC%88event-loop%EF%BC%89">&gt;事件循环（event loop）</h3>
<p style="">在函数每次执行时，都会产生一个新的执行环境；执行环境负责存储函数执行时产生的一切数据。</p>
<blockquote>
 <p style="">Q：函数的执行环境要存储到哪里呢？</p>
 <p style="">A：函数的执行环境存储到了一个叫做调用栈的地方。栈，是一种数据结构，特点：后进先出；队列，也是一种数据结构，特点：先进先出。</p>
</blockquote>
<h4 style="" id="%E8%B0%83%E7%94%A8%E6%A0%88%EF%BC%88call-stack%EF%BC%89">调用栈（call stack）</h4>
<ul>
 <li>
  <p style="">调用栈负责存储函数的执行环境。</p>
 </li>
 <li>
  <p style="">当一个函数被调用时，它的执行环境会作为一个栈帧；当插入到调用栈的栈顶，函数执行完毕时，其栈帧会自动从栈中弹出。</p>
 </li>
</ul>
<pre><code class="language-vbscript-html">&lt;script&gt;
function fn() {
    let a = 10
    let b = 20

    function fn2() {
        console.log("fn2")
    }

    fn2()

    console.log("fn~")
}

fn()

console.log(1111)
&lt;/script&gt;</code></pre>
<h4 style="" id="%E6%B6%88%E6%81%AF%E5%88%97%E9%98%9F">消息列队</h4>
<ul>
 <li>
  <p style="">消息队列负责存储将要执行的函数。</p>
 </li>
 <li>
  <p style="">当我们触发一个事件时，其响应函数并不是直接就添加到调用栈中的，因为调用栈中有可能会存在一些还没有执行完的代码。</p>
 </li>
 <li>
  <p style="">事件触发后，JS 引擎是将事件响应函数插入到消息列队中排队。</p>
 </li>
</ul>
<pre><code class="language-vbscript-html">&lt;button id=“btn”&gt; 点我一下 &lt;/button&gt;
&lt;button id="btn02"&gt;点我一下2&lt;/button&gt;</code></pre>
<pre><code class="language-vbscript-html">&lt;/script&gt;
    const btn = document.getElementById("btn")
    const btn02 = document.getElementById("btn02")
    btn.onclick = function () {
        alert(1111)

        const begin = Date.now()

        while (Date.now() - begin &lt; 3000) {}
    }

    btn02.onclick = function () {
        alert(2222)
    }
&lt;/script&gt;</code></pre>
<p style="text-align: center"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fevent%2520loop.png&amp;size=m" alt="event loop.png" width="100%" height="auto" style="display: inline-block"></p>
<blockquote>
 <p style="">而定时器的本质的就是在指定时间后，将函数添加到消息队列中</p>
</blockquote>
<pre><code class="language-vbscript-html">&lt;script&gt;
    // console.time()
    // setTimeout(function(){
    //     console.timeEnd()
    //     console.log("定时器执行了~")
    // }, 3000)

    // 使程序卡6s
    // const begin = Date.now()
    // while (Date.now() - begin &lt; 6000) {}

    /* 
    setInterval() 每间隔一段时间就将函数添加到消息队列中
    但是如果函数执行的速度比较慢，它是无法确保每次执行的间隔都是一样的
    */

    // console.time("间隔")
    // setInterval(function(){
    //     console.timeEnd("间隔")

    //     // console.log("定时器执行了~~")
    //     alert("定时器执行~")

    //     console.time("间隔")
    // }, 3000)

    /* 
    希望可以确保函数每次执行都有相同间隔
    */

    // console.time("间隔")
    // setTimeout(function fn() {
    //     console.timeEnd("间隔")
    //     alert("哈哈")

    //     console.time("间隔")
    //     // 在setTimeout的回调函数的最后，在调用一个setTimeout
    //     setTimeout(fn, 3000)
    // }, 3000)


    setTimeout(()=&gt;{
        console.log(11111)
    }, 0)

    console.log(222222)
&lt;/script&gt;</code></pre>
<p style=""></p>]]></description><guid isPermaLink="false">/2025/javascript-dom</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2FJavaScript.jpg&amp;size=m" type="image/jpeg" length="14553"/><category>JavaScript</category><pubDate>Tue, 4 Mar 2025 09:49:12 GMT</pubDate></item><item><title><![CDATA[使用 Docker 部署本地 Halo 开发环境]]></title><link>https://w-flac.org.cn/2025/docker-halo</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=%E4%BD%BF%E7%94%A8%20Docker%20%E9%83%A8%E7%BD%B2%E6%9C%AC%E5%9C%B0%20Halo%20%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83&amp;url=/2025/docker-halo" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <h3 style="" id="%E6%8B%89%E5%8F%96%E9%95%9C%E5%83%8F">拉取镜像</h3>
</blockquote>
<pre><code>docker pull registry.fit2cloud.com/halo/halo:2.20.？</code></pre>
<blockquote>
 <h3 style="" id="%E5%88%A0%E9%99%A4%E6%97%A7%E5%AE%B9%E5%99%A8">删除旧容器</h3>
</blockquote>
<pre><code>docker stop halo
docker rm halo</code></pre>
<blockquote>
 <h3 style="" id="%E6%9B%B4%E6%96%B0%E5%AE%B9%E5%99%A8">更新容器</h3>
</blockquote>
<pre><code>docker run -d --name halo -p 8090:8090 -e SPRING_THYMELEAF_CACHE=false -v ~/.halo2:/root/.halo2 registry.fit2cloud.com/halo/halo:2.20.？</code></pre>
<p style=""></p>]]></description><guid isPermaLink="false">/2025/docker-halo</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fhalo-vomg.jpg&amp;size=m" type="image/jpeg" length="4306"/><category>日志</category><pubDate>Fri, 7 Feb 2025 15:13:10 GMT</pubDate></item><item><title><![CDATA[JavaScript - DOM]]></title><link>https://w-flac.org.cn/2025/dom</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=JavaScript%20-%20DOM&amp;url=/2025/dom" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">DOM，全称Document Object Model，中文翻译为文档对象模型。DOM属于Web API的一部分。Web API中定义了非常多的对象，通过这些对象可以完成对网页的各种操作（添加删除元素、发送请求、操作浏览器等）。</p>
</blockquote>
<hr>
<h3 style="" id="%E4%BB%80%E4%B9%88%E6%98%AFdom">什么是DOM</h3>
<p style="">DOM中的D意为Document，即文档。所谓文档就是指整个网页，换言之，DOM是用来操作网页的。O意为Object，即对象。DOM将网页中的每一部分内容都转换为了对象，div有div的对象，input有input的对象，甚至一段文本，一段注释也有其所对应的对象。转换为对象干什么？还记得面向对象吗？转换对象以后，我们就可以以面向对象的方式去操作网页，想要操作哪个元素就获取哪个元素的对象，然后通过调用其方法或属性完成各种操作。M意为Model，即模型。模型用来表示对象之间的关系，也就是父子元素、祖先后代、兄弟元素等，明确关系后我们便可以通过任意一个对象去获取其他的对象。</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="zh"&gt;
&lt;head&gt;
    &lt;title&gt;My Title&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;A Heading&lt;/h1&gt;
    &lt;a href="#"&gt;Link Text&lt;/a&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p style="text-align: center"><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fdom-items.webp&amp;size=m" alt="dom-items.webp" width="100%" height="100%" style="display: inline-block"></p>
<h3 style="" id="%3E%E6%A6%82%E5%BF%B5">&gt;概念</h3>
<blockquote>
 <h4 style="" id="%E8%8A%82%E7%82%B9%EF%BC%88node%EF%BC%89">节点（Node）</h4>
</blockquote>
<p style="line-height: 1.85">在DOM标准下，网页中的每一个部分都会转换为对象。这些对象有一个共同的称呼——节点（Node）。一个页面将会由多个节点构成，虽然都称为节点，但是它们却有着不同的类型：</p>
<ol>
 <li>
  <p style="">文档节点</p>
 </li>
 <li>
  <p style="">元素节点</p>
 </li>
 <li>
  <p style="">文本节点</p>
 </li>
 <li>
  <p style="">属性节点</p>
 </li>
 <li>
  <p style="">…</p>
 </li>
</ol>
<p style="line-height: 1.85">每一个节点都有其不同的作用，文档节点表示整个网页，元素节点表示某个标签，文本节点表示网页中的文本内容，属性节点表示标签中的各种属性。如果从对象的结构上来讲，这些对象都有一个共同的父类Node。总的来说，都是属于节点，但是具体类型不同。</p>
<blockquote>
 <h4 style="" id="%E5%85%B3%E7%B3%BB">关系</h4>
</blockquote>
<ul>
 <li>
  <p style="">祖先 —— 包含后代元素的元素是祖先元素</p>
 </li>
 <li>
  <p style="">后代 —— 被祖先元素包含的元素是后代元素</p>
 </li>
 <li>
  <p style="">父 —— 直接包含子元素的元素是父元素</p>
 </li>
 <li>
  <p style="">子 —— 直接被父元素包含的元素是子元素</p>
 </li>
 <li>
  <p style="">兄弟 —— 拥有相同父元素的元素是兄弟元素</p>
 </li>
</ul>
<blockquote>
 <h4 style="" id="%E5%B0%8F%E8%AF%95%E7%89%9B%E5%88%80">小试牛刀</h4>
</blockquote>
<p style="">要使用DOM来操作网页，我们需要浏览器至少得先给我一个对象，才能去完成各种操作。所以浏览器已经为我们提供了一个document对象，它是一个全局变量可以直接使用，document代表的是整个的网页。</p>
<pre><code class="language-vbscript-html">&lt;button id="btn"&gt;点我一下&lt;/button&gt;

&lt;script&gt;
// 获取btn对象
const btn = document.getElementById("btn")

// 修改btn中的文字
btn.innerText = "Click ME"
&lt;/script&gt;</code></pre>
<hr>
<h3 style="" id="%3E%E6%96%87%E6%A1%A3%E8%8A%82%E7%82%B9%EF%BC%88document%EF%BC%89">&gt;文档节点（document）</h3>
<ul>
 <li>
  <p style=""><a href="https://developer.mozilla.org/en-US/docs/Web/API/Document" target="_blank">document</a>对象表示的是整个网页</p>
 </li>
 <li>
  <p style="">document对象的原型链</p>
 </li>
</ul>
<pre><code class="language-javascript">HTMLDocument -&gt; Document -&gt; Node -&gt; EventTarget -&gt; Object.prototype -&gt; null</code></pre>
<ul>
 <li>
  <p style="">凡是在原型链上存在的对象的属性和方法都可以通过Document去调用</p>
 </li>
 <li>
  <p style="">部分属性：</p>
 </li>
</ul>
<pre><code class="language-javascript">document.documentElement --&gt; html根元素
document.head --&gt; head元素
document.title --&gt; title元素
document.body --&gt; body元素
document.links --&gt; 获取页面中所有的超链接
...</code></pre>
<h3 style="" id="%3E%E5%85%83%E7%B4%A0%E8%8A%82%E7%82%B9%EF%BC%88element%EF%BC%89">&gt;元素节点（element）</h3>
<ul>
 <li>
  <p style="">在网页中，每一个标签都是一个元素节点</p>
 </li>
</ul>
<blockquote>
 <p style="">如何获取元素节点对象？</p>
</blockquote>
<ol>
 <li>
  <p style="">通过document对象来获取元素节点</p>
 </li>
 <li>
  <p style="">通过document对象来创建元素节点</p>
 </li>
</ol>
<blockquote>
 <p style="">通过document来获取已有的元素节点：</p>
</blockquote>
<h4 style="" id="document.getelementbyid()">document.getElementById()</h4>
<ul>
 <li>
  <p style="">根据id获取一个元素节点对象</p>
 </li>
</ul>
<pre><code class="language-vbscript-html">&lt;button id="btn"&gt;点我一下&lt;/button&gt;
&lt;script&gt;
const btn = document.getElementById("btn")
console.log(btn)
&lt;/script&gt;</code></pre>
<h4 style="" id="document.getelementsbyclassname()">document.getElementsByClassName()</h4>
<ul>
 <li>
  <p style="">根据元素的class属性值获取一组元素节点对象</p>
 </li>
</ul>
<pre><code class="language-vbscript-html">&lt;span class="s1"&gt;我是span&lt;/span&gt;
&lt;span class="s1"&gt;我是span&lt;/span&gt;
&lt;span class="s1"&gt;我是span&lt;/span&gt;
&lt;span class="s1"&gt;我是span&lt;/span&gt;
&lt;span class="s1"&gt;我是span&lt;/span&gt;

&lt;script&gt;

// 返回的是一个类数组对象，该方法返回的结果是一个实时更新的集合
// 当网页中新添加元素时，集合也会实时的刷新。

const spans = document.getElementsByClassName("s1")

console.log(spans) // HTMLCollection(5)&nbsp;[span.s1, span.s1, span.s1, span.s1, span.s1]

 for (let i = 0; i &lt; spans.length; i++) {
    spans[i].innerText = "我是span"+i
  }

&lt;/script&gt;</code></pre>
<h4 style="" id="document.getelementsbytagname()">document.getElementsByTagName()</h4>
<ul>
 <li>
  <p style="">根据标签名获取一组元素节点对象</p>
 </li>
</ul>
<pre><code class="language-vbscript-html">&lt;div&gt;我是div&lt;/div&gt;
&lt;div&gt;我是div&lt;/div&gt;
&lt;div&gt;我是div&lt;/div&gt;
&lt;div&gt;我是div&lt;/div&gt;
&lt;div&gt;我是div&lt;/div&gt;

&lt;script&gt;

// 返回的结果是可以实时更新的集合
const divs = document.getElementsByTagName("div")

// document.getElementsByTagName("*") 获取页面中所有的元素
const divs = document.getElementsByTagName("*") 

console.log(divs) // HTMLCollection(5) [div, div, div, div, div] 
&lt;/script&gt;</code></pre>
<h4 style="" id="document.getelementsbyname()">document.getElementsByName()</h4>
<ul>
 <li>
  <p style="">根据name属性获取一组元素节点对象</p>
 </li>
</ul>
<pre><code class="language-vbscript-html">&lt;form&gt;
    &lt;input type="text" name="username"&gt;
    &lt;input type="radio" name="gender" value="male"&gt; 男
    &lt;input type="radio" name="gender" value="female"&gt; 女
&lt;/form&gt;

&lt;script&gt;

// 返回一个实时更新的集合，主要用于表单项。
const genderInput = document.getElementsByName("gender")

console.log(genderInput) // NodeList(2) [input, input]
&lt;/script&gt;</code></pre>
<h4 style="" id="document.queryselectorall()">document.querySelectorAll()</h4>
<ul>
 <li>
  <p style="">根据选择器去页面中查询元素</p>
 </li>
</ul>
<pre><code class="language-vbscript-html">&lt;div&gt;我是div&lt;/div&gt;
&lt;div&gt;我是div&lt;/div&gt;
&lt;div&gt;我是div&lt;/div&gt;

&lt;script&gt;

// 会返回一个类数组（不会实时更新）
const divs2 = document.querySelectorAll("div")

console.log(divs2) // NodeList(3) [input, input,input]
&lt;/script&gt;</code></pre>
<h4 style="" id="document.queryselector()">document.querySelector()</h4>
<ul>
 <li>
  <p style="">根据选择器去页面中查询第一个符合条件的元素</p>
 </li>
</ul>
<pre><code class="language-vbscript-html">&lt;div&gt;我是div&lt;/div&gt;
&lt;div&gt;我是div&lt;/div&gt;

&lt;script&gt;

// 会返回一个类数组（不会实时更新）
const div = document.querySelector("div") // .xx | #xx

console.log(divs2) // NodeList(2) [input,input]

&lt;/script&gt;</code></pre>
<blockquote>
 <p style="">创建一个元素节点</p>
</blockquote>
<h4 style="" id="document.createelement()">document.createElement()</h4>
<ul>
 <li>
  <p style="">根据标签名创建一个元素节点对象</p>
 </li>
</ul>
<pre><code class="language-javascript">const h2 = document.createElement("h2") // 创建了H2，但未添加</code></pre>
<h3 style="" id="%3E%E5%85%83%E7%B4%A0%E7%9A%84%E5%B1%9E%E6%80%A7%E5%92%8C%E6%96%B9%E6%B3%95">&gt;元素的属性和方法</h3>
<pre><code class="language-vbscript-html">&lt;div id="box1"&gt;我是box1 &lt;/div&gt;

&lt;script&gt;

const box1 = document.getElementById("box1")

cosole.log(box1.__proto__)

&lt;/script&gt;</code></pre>
<ul>
 <li>
  <p style="">div的原型链</p>
 </li>
</ul>
<pre><code class="language-javascript">HTMLDivElement -&gt; HTMLElement -&gt; Element -&gt; Node -&gt; ...</code></pre>
<h4 style="" id="element.childnodes">element.childNodes</h4>
<ul>
 <li>
  <p style="">获取当前元素的子节点（会包含空白的子节点）</p>
 </li>
</ul>
<pre><code class="language-vbscript-html">&lt;div id="box1"&gt;
    我是box1
    &lt;span class="s1"&gt;我是s1&lt;/span&gt;
    &lt;span class="s1"&gt;我是s1&lt;/span&gt;
&lt;/div&gt;

&lt;script&gt;

const box1 = document.getElementById("box1")

const cns = box1.childNodes

console.log(children.length) // 输出：5 包含空格

&lt;/script&gt;</code></pre>
<h4 style="" id="element.children">element.children</h4>
<ul>
 <li>
  <p style="">获取当前元素的子元素</p>
 </li>
</ul>
<pre><code class="language-vbscript-html">&lt;div id="box1"&gt;
    我是box1
    &lt;span class="s1"&gt;我是s1&lt;/span&gt;
    &lt;span class="s1"&gt;我是s1&lt;/span&gt;
&lt;/div&gt;

&lt;script&gt;

const box1 = document.getElementById("box1")

const children = box1.children

console.log(children.length) // 输出：2（2个span）

&lt;/script&gt;</code></pre>
<h4 style="" id="element.firstelementchild">element.firstElementChild</h4>
<ul>
 <li>
  <p style="">获取当前元素的第一个子元素</p>
 </li>
</ul>
<pre><code class="language-vbscript-html">&lt;p&gt;Hello world! This is HTML5 Boilerplate.&lt;/p&gt;
&lt;div id="box1"&gt;
    我是box1
    &lt;span class="s1"&gt;我是s1&lt;/span&gt;
    &lt;span class="s1"&gt;我是s1-2&lt;/span&gt;
&lt;/div&gt;
    &lt;h1&gt;hello,world&lt;/h1&gt;

&lt;script&gt;

const box1 = document.getElementById("box1")

console.log(box1.firstElementChild) //输出: &lt;span class="s1"&gt;我是s1&lt;/span&gt;

&lt;/script&gt;</code></pre>
<h4 style="" id="element.lastelementchild">element.lastElementChild</h4>
<ul>
 <li>
  <p style="">获取当前元素的最后一个子元素</p>
 </li>
</ul>
<pre><code class="language-javascript">console.log(box1.lastElementChild) //输出: &lt;span class="s1"&gt;我是s1-2&lt;/span&gt;</code></pre>
<h4 style="" id="element.nextelementsibling">element.nextElementSibling</h4>
<ul>
 <li>
  <p style="">获取当前元素的下一个兄弟元素</p>
 </li>
</ul>
<pre><code class="language-javascript">console.log(box1.nextElementSibling) //输出: &lt;h1&gt;hello,world&lt;/h1&gt;</code></pre>
<h4 style="" id="element.previouselementsibling">element.previousElementSibling</h4>
<ul>
 <li>
  <p style="">获取当前元素的前一个兄弟元素</p>
 </li>
</ul>
<pre><code class="language-javascript">console.log(box1.previousElementSibling) //输出: &lt;p&gt;Hello world! This is HTML5 Boilerplate.&lt;/p&gt;</code></pre>
<h4 style="" id="element.parentnode">element.parentNode</h4>
<ul>
 <li>
  <p style="">获取当前元素的父节点</p>
 </li>
</ul>
<pre><code class="language-javascript">console.log(box1.parentNode) //输出: &lt;body&gt;...&lt;/body&gt;</code></pre>
<h4 style="" id="element.tagname">element.tagName</h4>
<ul>
 <li>
  <p style="">获取当前元素的标签名</p>
 </li>
</ul>
<pre><code class="language-javascript">console.log(box1.tagName) //输出: DIV</code></pre>
<h3 style="" id="%3E%E6%96%87%E6%9C%AC%E8%8A%82%E7%82%B9%EF%BC%88text%EF%BC%89">&gt;文本节点（Text）</h3>
<p style="">在DOM中，网页中所有的文本内容都是文本节点对象。</p>
<p style="">可以通过元素来获取其中的文本节点对象，但是我们通常不会这么做。</p>
<p style="">我们可以直接通过元素去修改其中的文本</p>
<blockquote>
 <p style="">修改文本的三个属性</p>
</blockquote>
<h4 style="" id="element.textcontent">element.textContent</h4>
<ul>
 <li>
  <p style="">获取或修改元素中的文本内容</p>
 </li>
</ul>
<pre><code class="language-vbscript-html">&lt;div id="box1"&gt;
    &lt;span style="text-transform: uppercase;"&gt;我是box1&lt;/span&gt;
&lt;/div&gt;

&lt;script&gt;

// 获取的是标签中的内容，不会考虑css样式
const box1 = document.getElementById("box1")

box1.textContent = "新的内容"

&lt;/script&gt;</code></pre>
<h4 style="" id="element.innertext">element.innerText</h4>
<ul>
 <li>
  <p style="">获取或修改元素中的文本内容</p>
 </li>
</ul>
<pre><code class="language-javascript">&lt;script&gt;

// innerText获取内容时，会考虑css样式
// 通过innerText去读取CSS样式，会触发网页的重排（计算CSS样式）
const box1 = document.getElementById("box1")

box1.innerText = "新的内容"

// 当字符串中有标签时，会自动对标签进行转义
box1.innerText = "&lt;li&gt;我是li&lt;/&gt;" //  &lt;li&gt; --&gt; &amp;lt;li&amp;gt;

&lt;/script&gt;</code></pre>
<h4 style="" id="element.innerhtml">element.innerHTML</h4>
<ul>
 <li>
  <p style="">获取或修改元素中的html代码</p>
 </li>
</ul>
<pre><code class="language-javascript">&lt;script&gt;

// 可以直接向元素中添加html代码
const box1 = document.getElementById("box1")

box1.innerHTML = "XXX"

// innerHTML插入内容时，有被xss注入的风险
box1.innerHTML = "&lt;、script src='https://sss/sss.js'&gt;&lt;\/script&gt;"
&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E5%B1%9E%E6%80%A7%E8%8A%82%E7%82%B9%EF%BC%88attr%EF%BC%89">&gt;属性节点（Attr）</h3>
<p style="">在DOM也是一个对象，通常不需要获取对象而是直接通过元素即可完成对其的各种操作。</p>
<blockquote>
 <p style="">如何操作属性节点：</p>
</blockquote>
<h4 style="" id="%E6%96%B9%E5%BC%8F%E4%B8%80">方式一</h4>
<ul>
 <li>
  <p style="">读取：元素.属性名(class属性需要使用 className 来读取)</p>
 </li>
</ul>
<p style="margin-left: 48px!important; text-indent: 2em">读取一个布尔值时，会返回 true 或 false （如 disabled）</p>
<ul>
 <li>
  <p style="">修改：元素.属性名 = 属性名</p>
 </li>
</ul>
<pre><code class="language-vbscript-html"> &lt;input disabled=“disabled” type="text" name="username" value="admin"&gt;

&lt;script&gt;

const input = document.getElementsByName("username")[0]

const input2 = document.querySelector("[name=username]")

console.log(input) // &#x8;console.log(input.type)

input.name = "biu" // 修改：元素.属性名 = 属性名

&lt;/script&gt;</code></pre>
<h4 style="" id="%E6%96%B9%E5%BC%8F%E4%BA%8C">方式二</h4>
<ul>
 <li>
  <p style="">读取：元素.getAttribute(属性名)</p>
 </li>
 <li>
  <p style="">修改：元素.setAttribute(属性名, 属性值)</p>
 </li>
 <li>
  <p style="">删除：元素.removeAttribute(属性名)</p>
 </li>
</ul>
<pre><code class="language-vbscript-html"> &lt;input disabled=“disabled” type="text" name="username" value="admin"&gt;

&lt;script&gt;

const input = document.getElementsByName("username")[0]

const input2 = document.querySelector("[name=username]")

input.getAttribute("name") // 读取：元素.getAttribute(属性名)

input.setAttribute("name","大王") // 修改：元素.setAttribute(属性名, 属性值)
input.setAttribute("disabled",true)

&#x8;input.removeAttribute("disabled") // 删除：元素.removeAttribute(属性名)

&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E4%BA%8B%E4%BB%B6%EF%BC%88event%EF%BC%89">&gt;事件（Event）</h3>
<p style="">事件就是用户和页面之间发生的交互行为。例如：点击按钮、鼠标移动、双击按钮、敲击键盘、松开按键....</p>
<p style="">可以通过为时间绑定响应函数（回调函数），来完成和用户之间的交互。</p>
<blockquote>
 <p style="">绑定响应函数</p>
</blockquote>
<h4 style="" id="%E7%9B%B4%E6%8E%A5%E5%9C%A8%E5%85%83%E7%B4%A0%E7%9A%84%E5%B1%9E%E6%80%A7%E4%B8%AD%E8%AE%BE%E7%BD%AE">直接在元素的属性中设置</h4>
<pre><code class="language-vbscript-html">&lt;button id="btn" onclick="alert('你点我干嘛~')"&gt;点我一下&lt;/button&gt;</code></pre>
<h4 style="" id="%E4%B8%BA%E5%85%83%E7%B4%A0%E6%8C%87%E5%AE%9A%E5%B1%9E%E6%80%A7%E8%AE%BE%E7%BD%AE(%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0)%E6%9D%A5%E7%BB%91%E5%AE%9A%E4%BA%8B%E4%BB%B6-%EF%BC%88%E4%B8%80%E4%B8%AA%E4%BA%8B%E4%BB%B6%E5%8F%AA%E8%83%BD%E7%BB%91%E5%AE%9A%E4%B8%80%E4%B8%AA%E5%93%8D%E5%BA%94%E5%87%BD%E6%95%B0%EF%BC%89">为元素指定属性设置(回调函数)来绑定事件 （一个事件只能绑定一个响应函数）</h4>
<pre><code class="language-javascript">&lt;script&gt;
// 获取到按钮对象
const btn = document.getElementById("btn")
// 为按钮对象的事件属性设置响应函数
btn.onclick = function(){
  alert("你点我干嘛~")
}
&lt;/script&gt;</code></pre>
<h4 style="" id="%E9%80%9A%E8%BF%87%E5%85%83%E7%B4%A0-addeventlistener(-)%E6%96%B9%E6%B3%95%E6%9D%A5%E7%BB%91%E5%AE%9A%E4%BA%8B%E4%BB%B6-%EF%BC%88%E5%8F%AF%E7%BB%91%E5%AE%9A%E5%A4%9A%E4%B8%AA%EF%BC%8C%E4%BC%9A%E4%BE%9D%E6%AC%A1%E6%89%A7%E8%A1%8C%EF%BC%89">通过元素 addEventListener( )方法来绑定事件 （可绑定多个，会依次执行）</h4>
<pre><code class="language-javascript">&lt;script&gt;
// 通过元素 addEventListener( )方法来绑定事件
btn.addEventListener("click", function(){
  alert("哈哈哈哈~")
})
&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E6%96%87%E6%A1%A3%E5%8A%A0%E8%BD%BD">&gt;文档加载</h3>
<p style="">网页是自上向下加载的，如果将 js 的代码编写到网页的上边，在 js 代码执行时，网页还没有加载完毕，这时候会出现无法获取到 DOM 对象的情况。</p>
<blockquote>
 <p style="">如何解决这个问题？</p>
</blockquote>
<h4 style="" id="%E5%B0%86-script-%E6%A0%87%E7%AD%BE%E7%BC%96%E5%86%99%E5%88%B0-body-%E7%9A%84%E6%9C%80%E5%90%8E">将 script 标签编写到 body 的最后</h4>
<pre><code class="language-vbscript-html">&lt;body&gt;

&lt;button id="btn"&gt;点我一下&lt;/button&gt;

&lt;script&gt;
  const btn = document.getElementById("btn")
  console.log(btn)
&lt;/script&gt;

&lt;/body&gt;
</code></pre>
<h4 style="" id="%E5%B0%86%E4%BB%A3%E7%A0%81%E7%BC%96%E5%86%99%E5%88%B0-window.onload-%E7%9A%84%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E4%B8%AD">将代码编写到 window.onload 的回调函数中</h4>
<pre><code class="language-vbscript-html">&lt;body&gt;

&lt;button id="btn"&gt;点我一下&lt;/button&gt;

&lt;script&gt;
// window.onload 事件会在窗口中的内容加载完毕之后才触发
window.onload = function () {
    const btn = document.getElementById("btn")
    console.log(btn)
}

window.addEventListener("load", function () {
    const btn = document.getElementById("btn")
    alert(btn)
})
&lt;/script&gt;

&lt;/body&gt;</code></pre>
<h4 style="" id="%E5%B0%86%E4%BB%A3%E7%A0%81%E7%BC%96%E5%86%99%E5%88%B0-document-%E5%AF%B9%E8%B1%A1%E7%9A%84-domcontentloaded-%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E4%B8%AD">将代码编写到 document 对象的 DOMContentLoaded 回调函数中</h4>
<pre><code class="language-vbscript-html">&lt;script&gt;
// document的DOMContentLoaded事件会在当前文档加载完毕之后触发
document.addEventListener("DOMContentLoaded", function () {
    const btn = document.getElementById("btn")
    alert(btn)
})
&lt;/script&gt;</code></pre>
<h4 style="" id="%E5%B0%86%E4%BB%A3%E7%A0%81%E7%BC%96%E5%86%99%E5%88%B0%E5%A4%96%E9%83%A8-js-%E6%96%87%E4%BB%B6%EF%BC%8C%E4%BB%A5-defer-%E5%BD%A2%E5%BC%8F%E5%BC%95%E5%85%A5">将代码编写到外部 js 文件，以 defer 形式引入</h4>
<pre><code class="language-vbscript-html">&lt;script defer src="./script/script.js"&gt;&lt;/script&gt;</code></pre>
<h3 style="" id="%3Edom%E7%9A%84%E4%BF%AE%E6%94%B9">&gt;Dom的修改</h3>
<h4 style="" id="element.appendchild">element.appendChild</h4>
<ul>
 <li>
  <p style="">给一个节点添加子节点</p>
 </li>
</ul>
<pre><code class="language-vbscript-html">&lt;ul id="list"&gt;
    &lt;li id="swk"&gt;孙悟空&lt;/li&gt;
    &lt;li id="zbj"&gt;猪八戒&lt;/li&gt;
    &lt;li id="shs"&gt;沙和尚&lt;/li&gt;
&lt;/ul&gt;

&lt;button id="btn"&gt;按钮&lt;/button&gt;

&lt;script&gt;
const list = document.getElementById("list")

// 获取按钮
const btn01 = document.getElementById("btn01")
btn01.onclick = function () {

    const li = document.createElement("li")
    // 向li中添加文本
    li.textContent = "唐僧"
    // 给li添加id属性
    li.id = "ts"

// 用于给一个节点添加子节点
list.appendChild(li)
&lt;/script&gt;</code></pre>
<h4 style="" id="element.insertadjacentelement(position%2C-element)">element.insertAdjacentElement(position, element)</h4>
<ul>
 <li>
  <p style="">可以向元素的任意位置添加元素</p>
 </li>
</ul>
<blockquote>
 <p style="">参数：</p>
 <ol>
  <li>
   <p style="">beforeend 标签的最后</p>
  </li>
  <li>
   <p style="">afterbegin 标签的开始 &nbsp;</p>
  </li>
  <li>
   <p style="">beforebegin 在元素的前边插入元素（兄弟元素）&nbsp;</p>
  </li>
  <li>
   <p style="">afterend 在元素的后边插入元素（兄弟元素）</p>
  </li>
 </ol>
</blockquote>
<pre><code class="language-javascript">&lt;script&gt;
list.insertAdjacentElement("afterend", li)
&lt;/script&gt;</code></pre>
<h4 style="" id="element.insertadjacenthtml(position%2C-text)">element.insertAdjacentHTML(position, text)</h4>
<ul>
 <li>
  <p style="">将HTML字符串添加到任意位置</p>
 </li>
</ul>
<blockquote>
 <p style="">参数：</p>
 <ol>
  <li>
   <p style="">beforeend 标签的最后</p>
  </li>
  <li>
   <p style="">afterbegin 标签的开始 &nbsp;</p>
  </li>
  <li>
   <p style="">beforebegin 在元素的前边插入元素（兄弟元素）&nbsp;</p>
  </li>
  <li>
   <p style="">afterend 在元素的后边插入元素（兄弟元素）</p>
  </li>
 </ol>
</blockquote>
<pre><code class="language-html">&lt;script&gt;
list.insertAdjacentHTML("beforeend", "&lt;li id='bgj'&gt;白骨精&lt;/li&gt;")
&lt;/script&gt;</code></pre>
<h4 style="" id="element.replacewith">element.replaceWith</h4>
<ul>
 <li>
  <p style="">使用一个元素替换当前元素</p>
 </li>
</ul>
<pre><code class="language-javascript">const bt = document.getElementById("btn")
btn02.onclick = function(){

    // 创建一个蜘蛛精替换孙悟空
    const li = document.createElement("li")
    li.textContent = "蜘蛛精"
    li.id = "zzj"

    // 获取swk
    const swk = document.getElementById("swk")

    // replaceWith() 使用一个元素替换当前元素
    swk.replaceWith(li)
}</code></pre>
<h4 style="" id="element.remove">element.remove</h4>
<ul>
 <li>
  <p style="">用来删除一个元素</p>
 </li>
</ul>
<pre><code class="language-javascript">&lt;script&gt;
swk.remove()
&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E5%B0%8F%E7%BB%83%E4%B9%A0">&gt;<a href="https://w-flac.org.cn/2025/js-ex1" target="_blank">小练习</a></h3>
<h3 style="" id="%3E%E8%8A%82%E7%82%B9%E7%9A%84%E5%A4%8D%E5%88%B6">&gt;节点的复制</h3>
<h4 style="" id="clonenode()">cloneNode()</h4>
<ul>
 <li>
  <p style="">对节点的所有属性进行复制（只会复制当前节点，而不会复制节点的子节点）</p>
 </li>
</ul>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="zh"&gt;
    &lt;head&gt;
        &lt;meta charset="UTF-8" /&gt;
        &lt;meta http-equiv="X-UA-Compatible" content="IE=edge" /&gt;
        &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
        &lt;title&gt;Document&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;button id="btn01"&gt;点我一下&lt;/button&gt;

        &lt;ul id="list1"&gt;
            &lt;li id="l1"&gt;孙悟空&lt;/li&gt;
            &lt;li id="l2"&gt;猪八戒&lt;/li&gt;
            &lt;li id="l3"&gt;沙和尚&lt;/li&gt;
        &lt;/ul&gt;

        &lt;ul id="list2"&gt;
            &lt;li&gt;蜘蛛精&lt;/li&gt;
        &lt;/ul&gt;

        &lt;script&gt;
            /* 点击按钮后，将id为l1的元素添加list2中 */
            const list2 = document.getElementById("list2")
            const l1 = document.getElementById("l1")
            const btn01 = document.getElementById("btn01")
            btn01.onclick = function () {
                // 用来对节点进行复制的,true作为参数，该方法将子节点一起复制
                const newL1 = l1.cloneNode(true) 
                newL1.id = "newL1"
                list2.appendChild(newL1)
            }
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<h3 style="" id="%3E%E4%BF%AE%E6%94%B9css%E6%A0%B7%E5%BC%8F">&gt;修改CSS样式</h3>
<h4 style="" id="%E5%85%83%E7%B4%A0.style.%E6%A0%B7%E5%BC%8F%E5%90%8D-%3D-%E6%A0%B7%E5%BC%8F%E5%80%BC">元素.style.样式名 = 样式值</h4>
<blockquote>
 <p style="">如果样式里含有-，则需要将样式表修改为驼峰命名法</p>
 <p style="">background-color --&gt; backgroundColor</p>
</blockquote>
<pre><code class="language-html">&lt;button id="btn"&gt;点我一下&lt;/button&gt;
&lt;div class="box1"&gt;&lt;/div&gt;</code></pre>
<pre><code class="language-auto">&lt;script&gt;

    const btn = document.getElementById("btn")
    const box1 = document.querySelector(".box1")

    btn.onclick = function () {
        // 修改box1的样式
        // 修改样式的方式：元素.style.样式名 = 样式值
        // 如果样式名中含有-，则需要将样式表修改为驼峰命名法
        // background-color --&gt; backgroundColor
        box1.style.width = "400px"
        box1.style.height = "400px"
        box1.style.backgroundColor = "yellow"
    }
&lt;/script&gt;</code></pre>
<h3 style="" id="%3E%E8%AF%BB%E5%8F%96css%E6%A0%B7%E5%BC%8F">&gt;读取CSS样式</h3>
<h4 style="" id="getcomputedstyle()">getComputedStyle()</h4>
<ul>
 <li>
  <p style="">返回一个包含当前元素所有的生效样式的对象</p>
 </li>
</ul>
<blockquote>
 <p style="">参数：</p>
 <p style="">1.要获取样式的对象</p>
 <p style="">2.要获取的伪元素</p>
 <p style="">返回值：</p>
 <p style="">返回的一个对象，对象中储存了当前元素的样式</p>
</blockquote>
<pre><code class="language-vbscript-html">&lt;button id="btn"&gt;点我一下&lt;/button&gt;
&lt;div class="box1"&gt;&lt;/div&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
    /* 
        点击按钮后，读取元素的css样式
    */

    const btn = document.getElementById("btn")
    const box1 = document.querySelector(".box1")

    btn.onclick = function () {

        const styleObj = getComputedStyle(box1)

        console.log(styleObj.width)
        console.log(styleObj.left)

        // console.log(parseInt(styleObj.width) + 100)
        // box1.style.width = parseInt(styleObj.width) + 100 + "px"

        // console.log(styleObj.backgroundColor)

        const beforeStyle = getComputedStyle(box1, "::before")
        // console.log(beforeStyle.color)

        console.log(box1.firstElementChild)
    }
&lt;/script</code></pre>
<h4 style="" id="element.clientheight-%2F-width">element.clientHeight / Width</h4>
<ul>
 <li>
  <p style="">获取元素内部的宽度和高度（包括内容区和内边距）</p>
 </li>
</ul>
<h4 style="" id="element.offsetheight-%2F-width">element.offsetHeight / Width</h4>
<ul>
 <li>
  <p style="">获取元素的可见框大小（包括内容区、内边距和边框）</p>
 </li>
</ul>
<h4 style="" id="element.scrollheight-%2F-width">element.scrollHeight / Width</h4>
<ul>
 <li>
  <p style="">获取元素滚动区域的大小</p>
 </li>
</ul>
<h4 style="" id="element.offsetparent">element.offsetParent</h4>
<ul>
 <li>
  <p style="">获取元素的定位父元素</p>
 </li>
</ul>
<blockquote>
 <p style="">当前元素最近的开启了定位的祖先元素，如果定位的元素都没有开启定位，则返回 body。</p>
</blockquote>
<h4 style="" id="element.offsettop-%2F-left">element.offsetTop / Left</h4>
<ul>
 <li>
  <p style="">获取元素相对于其定位父元素的偏移量</p>
 </li>
</ul>
<h4 style="" id="element.scrolltop-%2F-left">element.scrollTop / Left</h4>
<ul>
 <li>
  <p style="">获取或设置元素滚动条的偏移量</p>
 </li>
</ul>
<pre><code class="language-html"> &lt;button id="btn"&gt;点我一下&lt;/button&gt;
 &lt;hr&gt;
 &lt;div&gt;
     &lt;div id="box1"&gt;
         &lt;div id="box2"&gt;&lt;/div&gt;
     &lt;/div&gt;
&lt;/div&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;

    const btn = document.getElementById("btn")
    const box1 = document.getElementById("box1")

    btn.onclick = function(){
        // console.log(box1.scrollHeight)
        // console.log(box1.offsetParent)
        console.log(box1.scrollTop)
    }</code></pre>
<h3 style="" id="%3E%E4%BF%AE%E6%94%B9%E6%93%8D%E4%BD%9Cclass">&gt;修改操作Class</h3>
<h4 style="" id="element.classlist">element.classList</h4>
<blockquote>
 <p style="">这是一个对象，并提供了对当前元素的类的各种操作方法</p>
</blockquote>
<h4 style="" id="element.classlist.add(-)-%E5%90%91%E5%85%83%E7%B4%A0%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AAclass">element.classList.add( ) 向元素添加一个或多个Class</h4>
<h4 style="" id="element.classlist.remove(-)-%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AAclass">element.classList.remove( ) 移除元素中的一个或多个Class</h4>
<h4 style="" id="element.classlist.toggle(-)-%E5%88%87%E6%8D%A2%E5%85%83%E7%B4%A0%E7%9A%84class">element.classList.toggle( ) 切换元素的Class</h4>
<h4 style="" id="element.classlist.replace(-)-%E6%9B%BF%E6%8D%A2class">element.classList.replace( ) 替换Class</h4>
<h4 style="" id="element.classlist.contains(-)-%E6%A3%80%E6%9F%A5class">element.classList.contains( ) 检查Class</h4>
<pre><code class="language-vbscript-html">&lt;!DOCTYPE html&gt;
&lt;html lang="zh"&gt;
    &lt;head&gt;
        &lt;meta charset="UTF-8" /&gt;
        &lt;meta http-equiv="X-UA-Compatible" content="IE=edge" /&gt;
        &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
        &lt;title&gt;Document&lt;/title&gt;
        &lt;style&gt;
            .box1 {
                width: 200px;
                height: 200px;
                background-color: #bfa;
            }


            .box2{
                background-color: yellow;
                width: 300px;
                height: 500px;
                border: 10px greenyellow solid;
            }
        &lt;/style&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;button id="btn"&gt;点我一下&lt;/button&gt;

        &lt;hr /&gt;

        &lt;div class="box1 box3 box4"&gt;&lt;/div&gt;

        &lt;script&gt;
            /* 
                点击按钮后，修改box1的宽度
            */
            const btn = document.getElementById("btn")
            const box1 = document.querySelector(".box1")

            btn.onclick = function () {

                // box1.className += " box2"
                // box1.classList.add("box2", "box3", "box4")
                // box1.classList.add("box1")

                // box1.classList.remove("box2")
                // box1.classList.toggle("box2")
                // box1.classList.replace("box1", "box2")
                let result = box1.classList.contains("box3")
                console.log(result) 
            }
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<h3 style="" id="%3E%E4%BA%8B%E4%BB%B6%E5%AF%B9%E8%B1%A1">&gt;事件对象</h3>
<blockquote>
 <h4 style="" id="%E7%AE%80%E4%BB%8B(event)">简介(Event)</h4>
 <ul>
  <li>
   <p style="">事件对象就是有浏览器在事件触发时所创建的对象，这个对象中封装了时间相关的各种信息。</p>
  </li>
  <li>
   <p style="">通过事件对象可以获取到事件的详细信息，比如：鼠标的坐标、键盘的按键...</p>
  </li>
  <li>
   <p style="">浏览器在创建时间后，会将事件对象作为响应函数的参数传递，所以我们可以在事件的回调函数中定义一个形参来接收事件对象。</p>
  </li>
  <li>
   <p style="">在DOM中存在着多种不同类型的事件对象，它们有着共同的祖先，就是 Event。</p>
  </li>
 </ul>
</blockquote>
<pre><code class="language-vbscript-html">&lt;!DOCTYPE html&gt;
&lt;html lang="zh"&gt;
    &lt;head&gt;
        &lt;meta charset="UTF-8" /&gt;
        &lt;meta http-equiv="X-UA-Compatible" content="IE=edge" /&gt;
        &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
        &lt;title&gt;Document&lt;/title&gt;
        &lt;style&gt;
            #box1{
                width: 300px;
                height: 300px;
                border: 10px greenyellow solid;
            }

        &lt;/style&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;div id="box1"&gt;&lt;/div&gt;

        &lt;script&gt;
            const box1 = document.getElementById("box1")

            // box1.onmousemove = event =&gt; {
            //     console.log(event)
            // }

            box1.addEventListener("mousemove", event =&gt; {
                console.log(event.clientX, event.clientY)

                box1.textContent = event.clientX + "," + event.clientY
            })
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<h3 style="" id="%E5%86%92%E6%B3%A1(bubble)">冒泡(bubble)</h3>
<blockquote>
 <p style="">事件的冒泡就是指事件的向上传导。</p>
 <p style="">当元素上的某个事件被触发后，其祖先元素上的相同事件也会被同时触发。</p>
 <p style="">冒泡的存在大大的简化了代码的编写，但是在一些场景下我们并不希望冒泡存在，所以我可以通过时间对象来取消冒泡</p>
</blockquote>
<h4 style="" id="event.target-%E8%A7%A6%E5%8F%91%E4%BA%8B%E4%BB%B6%E7%9A%84%E5%AF%B9%E8%B1%A1">event.target 触发事件的对象</h4>
<h4 style="" id="event.currenttarget-%E7%BB%91%E5%AE%9A%E4%BA%8B%E4%BB%B6%E7%9A%84%E5%AF%B9%E8%B1%A1(%E5%90%8Cthis)">event.currentTarget 绑定事件的对象(同this)</h4>
<h4 style="" id="event.stoppropagetion(-)-%E5%81%9C%E6%AD%A2%E4%BA%8B%E4%BB%B6%E4%BC%A0%E5%AF%BC">event.stopPropagetion( ) 停止事件传导</h4>
<h4 style="" id="event.preventdefault(-)-%E5%8F%96%E6%B6%88%E9%BB%98%E8%AE%A4%E8%A1%8C%E4%B8%BA">event.preventDefault( ) 取消默认行为</h4>
<pre><code class="language-vbscript-html">&lt;!DOCTYPE html&gt;
&lt;html lang="zh"&gt;
    &lt;head&gt;
        &lt;meta charset="UTF-8" /&gt;
        &lt;meta http-equiv="X-UA-Compatible" content="IE=edge" /&gt;
        &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
        &lt;title&gt;Document&lt;/title&gt;
        &lt;style&gt;
            #box1 {
                width: 300px;
                height: 300px;
                background-color: greenyellow;
            }

            #box2 {
                width: 250px;
                height: 250px;
                background-color: #ff0;
            }

            #box3 {
                width: 200px;
                height: 200px;
                background-color: orange;
            }
        &lt;/style&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;div id="box1"&gt;
            &lt;div id="box2"&gt;
                &lt;div id="box3"&gt;&lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;

        &lt;a id="chao" href="https://parlo.cc"&gt;超链接&lt;/a&gt;

        &lt;script&gt;
            // 事件对象
            const box1 = document.getElementById("box1")
            const box2 = document.getElementById("box2")
            const box3 = document.getElementById("box3")
            const chao = document.getElementById("chao")

            chao.addEventListener("click", (event) =&gt; {

                event.preventDefault() // 取消默认行为

                alert("被点了~~~")

            })

            box1.addEventListener("click", function (event) {
                // alert(event)
                // console.log(event.target)
                // console.log(this)

                console.log(event.currentTarget)

                // alert("Hello 我是box1")
            })

            // box2.addEventListener("click", function(event){
            //     event.stopPropagation()
            //     alert("我是box2")
            // })</code></pre>
<h3 style="" id="%3E%E4%BA%8B%E4%BB%B6%E5%A7%94%E6%B4%BE">&gt;事件委派</h3>
<p style="">委派就是将本该绑定给多个元素的事件，统一绑定给 document，这样可以降低代码复杂度，方便维护。</p>
<pre><code class="language-vbscript-html">&lt;!DOCTYPE html&gt;
&lt;html lang="zh"&gt;
    &lt;head&gt;
        &lt;meta charset="UTF-8" /&gt;
        &lt;meta http-equiv="X-UA-Compatible" content="IE=edge" /&gt;
        &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
        &lt;title&gt;Document&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;button id="btn"&gt;点我一下&lt;/button&gt;

        &lt;hr /&gt;

        &lt;ul id="list"&gt;
            &lt;li&gt;&lt;a href="javascript:;"&gt;链接一&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href="javascript:;"&gt;链接二&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href="javascript:;"&gt;链接三&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href="javascript:;"&gt;链接四&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        &lt;script&gt;
            /* 
                我一个希望：
                    只绑定一次事件，既可以让所有的超链接，包括当前的和未来新建的超链接都具有这些事件

                思路：
                    可以将事件统一绑定给document，这样点击超链接时由于事件的冒泡，
                        会导致document上的点击事件被触发，这样只绑定一次，所有的超链接都会具有这些事件
            */

            const list = document.getElementById("list")
            const btn = document.getElementById("btn")

            // 获取list中的所有链接
            const links = list.getElementsByTagName("a")


            document.addEventListener("click", (event) =&gt; {
                // 在执行代码前，先来判断一下事件是由谁触发
                // 检查event.target 是否在 links 中存在

                // console.log(Array.from(links))

                if([...links].includes(event.target)){
                    alert(event.target.textContent)
                }                
            })

            // 点击按钮后，在ul中添加一个新的li
            btn.addEventListener("click", () =&gt; {
                list.insertAdjacentHTML(
                    "beforeend",
                    "&lt;li&gt;&lt;a href='javascript:;'&gt;新超链接&lt;/a&gt;&lt;/li&gt;"
                )
            })
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<h3 style="" id="%3E%E4%BA%8B%E4%BB%B6%E7%9A%84%E6%8D%95%E8%8E%B7">&gt;事件的捕获</h3>
<blockquote>
 <p style="">在 DOM 中，事件的传播主要分为三个阶段</p>
 <ul>
  <li>
   <p style="">捕获阶段（从祖先元向目标元素进行事件的捕获）</p>
  </li>
  <li>
   <p style="">目标阶段（触发事件的对象）</p>
  </li>
  <li>
   <p style="">冒泡阶段（由目标元素向祖先元素进行事件的冒泡）</p>
  </li>
 </ul>
</blockquote>
<p style="">当前元素触发事件后，会先从当前元素最大的祖先元素开始向当前元素进行事件的捕获。默认情况下，事件不会在捕获阶段触发。</p>
<p style="">如果希望在捕获阶段触发事件，可以将 addEventListener 的第三个参数设置为 true。一般情况下我们不希望事件在捕获阶段实现，所以通常我们并不需要设置第三个参数。</p>
<h4 style="" id="event.phase-%E8%A1%A8%E7%A4%BA%E4%BA%8B%E4%BB%B6%E8%A7%A6%E5%8F%91%E7%9A%84%E9%98%B6%E6%AE%B5">event.Phase 表示事件触发的阶段</h4>
<blockquote>
 <p style="">1 捕获阶段，2 目标阶段，3 冒泡阶段</p>
</blockquote>
<pre><code class="language-vbscript-html">&lt;!DOCTYPE html&gt;
&lt;html lang="zh"&gt;
    &lt;head&gt;
        &lt;meta charset="UTF-8" /&gt;
        &lt;meta http-equiv="X-UA-Compatible" content="IE=edge" /&gt;
        &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
        &lt;title&gt;Document&lt;/title&gt;
        &lt;style&gt;
            #box1 {
                width: 300px;
                height: 300px;
                background-color: greenyellow;
            }

            #box2 {
                width: 200px;
                height: 200px;
                background-color: orange;
            }

            #box3 {
                width: 100px;
                height: 100px;
                background-color: tomato;
            }
        &lt;/style&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;div id="box1"&gt;
            &lt;div id="box2"&gt;
                &lt;div id="box3"&gt;&lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;

        &lt;script&gt;
            const box1 = document.getElementById("box1")
            const box2 = document.getElementById("box2")
            const box3 = document.getElementById("box3")

            box1.addEventListener("click", event =&gt; {
                alert("1" + event.eventPhase)
            })

            box2.addEventListener("click", event =&gt; {

                alert("2" + event.eventPhase)
            })

            box3.addEventListener("click", event =&gt; {
                alert("3" + event.eventPhase)
            })

        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p style=""></p>]]></description><guid isPermaLink="false">/2025/dom</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fdom.webp&amp;size=m" type="image/jpeg" length="12932"/><category>JavaScript</category><pubDate>Fri, 24 Jan 2025 19:43:00 GMT</pubDate></item><item><title><![CDATA[ Tailwind V4 安装与使用]]></title><link>https://w-flac.org.cn/2025/tailwind-v4</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=%20Tailwind%20V4%20%E5%AE%89%E8%A3%85%E4%B8%8E%E4%BD%BF%E7%94%A8&amp;url=/2025/tailwind-v4" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">Tailwind CSS 从 3.x 升级到 4.x 的关键改进摘要：</p>
 <ul>
  <li>
   <p style=""><strong>性能优化</strong>：编译速度更快，生成的 CSS 文件更小，减少重复样式。</p>
  </li>
  <li>
   <p style=""><strong>容器查询支持</strong>：支持 <code>@container</code>，增强响应式布局能力。</p>
  </li>
  <li>
   <p style=""><strong>ARIA 和数据属性支持</strong>：新增对 <code>aria-</code> 和 <code>data-</code> 属性状态的工具类支持。</p>
  </li>
  <li>
   <p style=""><strong>默认断点增强</strong>：提供更灵活的断点配置选项。</p>
  </li>
  <li>
   <p style=""><strong>动画改进</strong>：优化 <code>transition</code> 和 <code>animation</code> 的工具类，使用更直观。</p>
  </li>
  <li>
   <p style=""><strong>JIT 编译增强</strong>：支持更复杂的动态类名生成，编译效率提升。</p>
  </li>
  <li>
   <p style=""><strong>排版插件升级</strong>：改进 <code>@tailwindcss/typography</code> 插件，默认样式更丰富。</p>
  </li>
  <li>
   <p style=""><strong>配置简化</strong>：优化 <code>tailwind.config.js</code> 格式，更易于维护和调整。</p>
  </li>
  <li>
   <p style=""><strong>插件兼容性</strong>：改进插件系统，确保官方和第三方插件更易集成。</p>
  </li>
  <li>
   <p style=""><strong>移除废弃功能</strong>：旧版中的一些弃用字段已被完全移除。</p>
  </li>
 </ul>
</blockquote>
<hr>
<h3 style="" id="%E5%AE%89%E8%A3%85node.js">安装Node.JS</h3>
<blockquote>
 <p style="">前往 <a rel="noreferrer" href="https://nodejs.org/" target="_new">Node.js 官方网站</a> 并下载适合你操作系统的 Node.js 安装程序。</p>
</blockquote>
<h4 style="" id="%E6%A3%80%E6%9F%A5node.js">检查Node.js</h4>
<pre><code class="language-bash">node -v</code></pre>
<h4 style="" id="%E6%A3%80%E6%9F%A5npm">检查NPM</h4>
<pre><code class="language-bash">npm -v</code></pre>
<h4 style="" id="%E6%9B%B4%E6%96%B0npm">更新NPM</h4>
<pre><code class="language-bash">npm install -g npm</code></pre>
<div class="html-edited">
 <br>
</div>
<h3 style="" id="tainlwind%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AE">Tainlwind安装配置</h3>
<blockquote>
 <p style="">从头开始使用 Tailwind CSS 的最简单、最快捷的方法是使用 Tailwind CLI 工具。</p>
</blockquote>
<h4 style="" id="%E5%88%9B%E5%BB%BApackage.json">创建package.json</h4>
<blockquote>
 <p style="">这将创建一个json文件</p>
</blockquote>
<pre><code class="language-bash">npm init -y</code></pre>
<h4 style="" id="%E5%AE%89%E8%A3%85tailwind"><strong>安装tailwind</strong></h4>
<pre><code class="language-bash">npm install tailwindcss @tailwindcss/postcss postcss</code></pre>
<h4 style="" id="%E5%88%9B%E5%BB%BA-postcss.config.mjs">创建 postcss.config.mjs</h4>
<pre><code class="language-json">export default {
  plugins: {
    "@tailwindcss/postcss": {},
  }
}</code></pre>
<h4 style="" id="%E5%88%9B%E5%BB%BAxxxxx.css%E6%96%87%E4%BB%B6">创建xxxxx.css文件</h4>
<blockquote>
 <p style="">由于Tailwind需要监听一个CSS文件，我们需要配置它，支持将自定义样式写在里面</p>
</blockquote>
<pre><code class="language-css">@import "tailwindcss";</code></pre>
<h4 style="" id="%E9%85%8D%E7%BD%AEtailwind.config.js"><strong>配置T</strong>ailwind.config.js</h4>
<blockquote>
 <p style=""><code>注意：V4 版本中，此配置为非必须项，也可作为自定义使用</code></p>
 <p style="">官方默认配置的生成</p>
</blockquote>
<pre><code class="language-bash">npx tailwindcss init --full</code></pre>
<blockquote>
 <p style="">配置基于Halo主题而配置，如果你是使用其他部分，请在 content 中修改项目地址即可。</p>
</blockquote>
<pre><code class="language-json">module.exports = {
  content: [
    "./templates/**/*.html",
    "./templates/assets/**/*.js"
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}</code></pre>
<h4 style="" id="%E6%89%AB%E6%8F%8F%E5%B9%B6%E6%9E%84%E5%BB%BAcss">扫描并构建CSS</h4>
<blockquote>
 <p style=""><code>注意：V4 版本中 @tailwindcss/cli 替换 tailwind</code></p>
 <p style="">通过监听content 中设置的项目地址，监听类名并生成css文件</p>
</blockquote>
<pre><code class="language-bash">npx @tailwindcss/cli -i ./src/input.css -o ./templates/assets/css/style.css --watch</code></pre>
<h4 style="" id="%E5%9C%A8html%E4%B8%AD%E7%BC%96%E5%86%99%E6%A0%B7%E5%BC%8F">在HTML中编写样式</h4>
<pre><code class="language-html">&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset="UTF-8"&gt;
  &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
  &lt;link href="./output.css" rel="stylesheet"&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1 class="text-3xl font-bold underline"&gt;
    Hello world!
  &lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<div class="html-edited">
 <br>
</div>
<h4 style="" id="%E9%AB%98%E7%BA%A7%E9%85%8D%E7%BD%AE">高级配置</h4>
<blockquote>
 <p style="">但往往每次使用扫描构建太麻烦了，我们可以简化代码package.json</p>
 <p style="">每次使用 <code>npm run tailwind</code> 快速构建</p>
</blockquote>
<pre><code class="language-json"> "scripts": {
    "tailwind": "npx @tailwindcss/cli -i ./src/input.css -o ./templates/assets/css/style.css --watch"
  },</code></pre>
<div class="html-edited">
 <br>
</div>
<h3 style="" id="prettier%E6%8F%92%E4%BB%B6">Prettier插件</h3>
<h4 style="" id="%E5%AE%89%E8%A3%85%E6%8F%92%E4%BB%B6">安装插件</h4>
<blockquote>
 <p style="">检查是否存在&#x8; Prettier插件</p>
</blockquote>
<pre><code class="language-bash">npm list prettier-plugin-tailwindcss</code></pre>
<blockquote>
 <p style="">安装 Prettier 插件</p>
</blockquote>
<pre><code class="language-bash">npm install -D prettier prettier-plugin-tailwindcss</code></pre>
<h4 style="" id="%E5%88%9B%E5%BB%BA.prettier%E6%96%87%E4%BB%B6">创建.prettier文件</h4>
<pre><code class="language-json">{
  "plugins": ["prettier-plugin-tailwindcss"],
  "tailwindConfig": "./tailwind.config.js"
}</code></pre>
<p style=""></p>]]></description><guid isPermaLink="false">/2025/tailwind-v4</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2FtailwindV4.webp&amp;size=m" type="image/jpeg" length="53592"/><category>CSS</category><pubDate>Fri, 24 Jan 2025 07:24:31 GMT</pubDate></item><item><title><![CDATA[JavaScript - 练习]]></title><link>https://w-flac.org.cn/2025/js-ex1</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=JavaScript%20-%20%E7%BB%83%E4%B9%A0&amp;url=/2025/js-ex1" width="1" height="1" alt="" style="opacity:0;">
<h3 style="" id="%3E%E5%88%87%E6%8D%A2%E7%85%A7%E7%89%87">&gt;切换照片</h3>
<pre><code class="language-vbscript-html">&lt;!DOCTYPE html&gt;
&lt;html lang="zh"&gt;

&lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;meta http-equiv="X-UA-Compatible" content="IE=edge" /&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
    &lt;title&gt;Document&lt;/title&gt;
    &lt;style&gt;
        .outer {
            width: 640px;
            margin: 50px auto;
            text-align: center;
        }
    &lt;/style&gt;
    &lt;script&gt;
        window.onload = function () {
            /* 
                点击按钮切换图片
            */

            // 获取info
            const info = document.getElementById("info")

            // 获取到图片
            const img = document.getElementsByTagName("img")[0]

            // 获取两个按钮
            const prev = document.getElementById("prev")
            const next = document.getElementById("next")

            // 创建一个数组来存储图片的路径
            const imgArr = [
                "./images/1.png",
                "./images/2.png",
                "./images/3.png",
                "./images/4.png",
                "./images/5.png",
            ]

            // 创建一个变量记录当前图片的索引
            let current = 0

            // 设置info元素的内容，显示总图片数和当前图片索引
            info.textContent = `总共 ${imgArr.length} 张图片，当前第 ${current + 1} 张`

            // 上一张
            prev.onclick = function () {
                current--

                // 如果当前图片索引小于0，则设置为最后一张图片的索引
                if (current &lt; 0) {
                    // current = 0
                    current = imgArr.length - 1
                }
                // 更新img元素的src属性，显示当前图片
                img.src = imgArr[current]

                // 更新info元素的内容，显示总图片数和当前图片索引
                info.textContent = `总共 ${imgArr.length} 张图片，当前第 ${current + 1} 张`

            }

            // 点击next按钮后，切换图片
            next.onclick = function () {
                current++

                if (current &gt; imgArr.length - 1) {
                    // current = imgArr.length - 1
                    current = 0
                }

                // 切换图片 --&gt; 2.png 就是修改img的src属性
                img.src = imgArr[current]

                info.textContent = `总共 ${imgArr.length} 张图片，当前第 ${current + 1} 张`

            }
        }
    &lt;/script&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;div class="outer"&gt;
        &lt;p id="info"&gt;
            总共n张图片，当前第m张
        &lt;/p&gt;
        &lt;div class="img-wrapper"&gt;
            &lt;img src="./images/1.png" alt="这是一个图片" /&gt;
        &lt;/div&gt;

        &lt;div class="btn-wrapper"&gt;
            &lt;button id="prev"&gt;上一张&lt;/button&gt;
            &lt;button id="next"&gt;下一张&lt;/button&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/body&gt;

&lt;/html&gt;</code></pre>
<h3 style="" id="%3E%E9%80%89%E6%8B%A9%E6%A1%86">&gt;选择框</h3>
<pre><code class="language-vbscript-html">// html
&lt;!doctype html&gt;
&lt;html lang="en"&gt;
    &lt;head&gt;
        &lt;meta charset="UTF-8"&gt;
        &lt;meta content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
              name="viewport"&gt;
        &lt;meta content="ie=edge" http-equiv="X-UA-Compatible"&gt;
        &lt;title&gt;Document&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;div&gt;
            &lt;form action="#"&gt;
                &lt;div&gt;
                    请选择你的爱好：
                    &lt;input id="check-all" type="checkbox"/&gt; 全选
                &lt;/div&gt;
                &lt;div&gt;
                    &lt;input name="hobby" type="checkbox" value="乒乓球"/&gt; 乒乓球
                    &lt;input name="hobby" type="checkbox" value="篮球"/&gt; 篮球
                    &lt;input name="hobby" type="checkbox" value="羽毛球"/&gt; 羽毛球
                    &lt;input name="hobby" type="checkbox" value="足球"/&gt; 足球
                &lt;/div&gt;
                &lt;div&gt;
                    &lt;button id="all" type="button"&gt;全选&lt;/button&gt;
                    &lt;button id="no" type="button"&gt;取消&lt;/button&gt;
                    &lt;button id="reverse" type="button"&gt;反选&lt;/button&gt;
                    &lt;button id="send" type="button"&gt;提交&lt;/button&gt;
                &lt;/div&gt;
            &lt;/form&gt;
        &lt;/div&gt;
        &lt;script src="main.js"&gt;&lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<pre><code class="language-javascript">// main.js
const hobby = document.getElementsByName("hobby")
const allBtn = document.getElementById('all')

allBtn.onclick = function () {
    for (let i = 0; i &lt; hobby.length; i++) {
        hobby[i].checked = true
    }
    checkBtn.checked = true
}

const noBtn = document.getElementById('no')

noBtn.onclick = function () {
    for (let i = 0; i &lt; hobby.length; i++) {
        hobby[i].checked = false
    }
    checkBtn.checked = false
}

const reverseBtn = document.getElementById('reverse')

reverseBtn.onclick = function () {
    for (let i = 0; i &lt; hobby.length; i++) {
        hobby[i].checked = !hobby[i].checked
    }
    const checkedBox = document.querySelectorAll(
        "[name=hobby]:checked"
    )

    if (hobby.length === checkedBox.length) {
        checkBtn.checked = true
    } else {
        checkBtn.checked = false
    }
}

const sendBtn = document.getElementById('send')

sendBtn.onclick = function () {
    for (let i = 0; i &lt; hobby.length; i++) {
        hobby[i].checked &amp;&amp; alert(hobby[i].value)
    }
}

const checkBtn = document.getElementById('check-all')

checkBtn.onchange = function () {
    for (let i = 0; i &lt; hobby.length; i++) {
        hobby[i].checked = this.checked
    }
}
for (let i = 0; i &lt; hobby.length; i++) {

    hobby[i].onchange = function () {
        const checkedBox = document.querySelectorAll(
            "[name=hobby]:checked"
        )

        if (hobby.length === checkedBox.length) {
            checkBtn.checked = true
        } else {
            checkBtn.checked = false
        }
    }
}</code></pre>
<h3 style="" id="%3E%E8%87%AA%E5%AE%9A%E4%B9%89%E5%91%98%E5%B7%A5%E4%BF%A1%E6%81%AF">&gt;自定义员工信息</h3>
<pre><code class="language-vbscript-html">// html
&lt;!DOCTYPE html&gt;
&lt;html lang="zh"&gt;
    &lt;head&gt;
        &lt;meta charset="UTF-8" /&gt;
        &lt;meta http-equiv="X-UA-Compatible" content="IE=edge" /&gt;
        &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
        &lt;title&gt;Document&lt;/title&gt;
        &lt;style&gt;
            .outer {
                width: 400px;
                margin: 100px auto;
                text-align: center;
            }

            table {
                width: 400px;
                border-collapse: collapse;
                margin-bottom: 20px;
            }

            td,
            th {
                border: 1px black solid;
                padding: 10px 0;
            }

            form div {
                margin: 10px 0;
            }
        &lt;/style&gt;


    &lt;/head&gt;
    &lt;body&gt;
        &lt;div class="outer"&gt;
            &lt;table&gt;
                &lt;tbody&gt;
                    &lt;tr&gt;
                        &lt;th&gt;姓名&lt;/th&gt;
                        &lt;th&gt;邮件&lt;/th&gt;
                        &lt;th&gt;薪资&lt;/th&gt;
                        &lt;th&gt;操作&lt;/th&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;孙悟空&lt;/td&gt;
                        &lt;td&gt;swk@hgs.com&lt;/td&gt;
                        &lt;td&gt;10000&lt;/td&gt;
                        &lt;td&gt;&lt;a href="javascript:;"&gt;删除&lt;/a&gt;&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;猪八戒&lt;/td&gt;
                        &lt;td&gt;zbj@glz.com&lt;/td&gt;
                        &lt;td&gt;8000&lt;/td&gt;
                        &lt;td&gt;&lt;a href="javascript:;"&gt;删除&lt;/a&gt;&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;沙和尚&lt;/td&gt;
                        &lt;td&gt;shs@lsh.com&lt;/td&gt;
                        &lt;td&gt;6000&lt;/td&gt;
                        &lt;td&gt;&lt;a href="javascript:;"&gt;删除&lt;/a&gt;&lt;/td&gt;
                    &lt;/tr&gt;
                &lt;/tbody&gt;
            &lt;/table&gt;

            &lt;form action="#"&gt;
                &lt;div&gt;
                    &lt;label for="name"&gt;姓名&lt;/label&gt;
                    &lt;input type="text" id="name" /&gt;
                &lt;/div&gt;
                &lt;div&gt;
                    &lt;label for="email"&gt;邮件&lt;/label&gt;
                    &lt;input type="email" id="email" /&gt;
                &lt;/div&gt;
                &lt;div&gt;
                    &lt;label for="salary"&gt;薪资&lt;/label&gt;
                    &lt;input type="number" id="salary" /&gt;
                &lt;/div&gt;
                &lt;button id="btn" type="button"&gt;添加&lt;/button&gt;
            &lt;/form&gt;
        &lt;/div&gt;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<pre><code class="language-javascript">// main.js
document.addEventListener("DOMContentLoaded", function () {
		/* 
            点击删除超链接后，删除当前的员工信息
        */

		function delEmpHandler() {
			// 本练习中的超链接，我们是不希望发生跳转，但是跳转行为是超链接的默认行为
			// 只要点击超链接就会触发页面的跳转，事件中可以通过取消默认行为来阻止超链接的跳转
			// 使用return false来取消默认行为，只在 xxx.xxx = function(){}这种形式绑定的事件中才适用
			// return false

			// 删除当前员工 删除当前超链接所在的tr
			// console.log(this)

			// this表示当前点击的超链接
			const tr = this.parentNode.parentNode;

			// 获取要删除的员工的姓名
			// const empName = tr.getElementsByTagName("td")[0].textContent
			const empName = tr.firstElementChild.textContent;

			// 弹出一个友好的提示
			if (confirm("确认要删除【" + empName + "】吗？")) {
				// 删除tr
				tr.remove();
			}
		}

		// 获取所有的超链接
		const links = document.links;
		// 为他们绑定单级响应函数
		for (let i = 0; i &lt; links.length; i++) {
			links[i].onclick = delEmpHandler;

			// links[i].addEventListener("click", function(){
			//     alert(123)
			//     return false // 无法取消默认行为
			// })
		}

		/* 
            点击按钮后，将用户的信息插入到表格中
        */
		// 获取tbody
		const tbody = document.querySelector("tbody");
		const btn = document.getElementById("btn");
		btn.onclick = function () {
			// 获取用户输入的数据
			const name = document.getElementById("name").value;
			const email = document.getElementById("email").value;
			const salary = document.getElementById("salary").value;

			// 将获取到的数据设置DOM对象
			/* 
                &lt;tr&gt;
                    &lt;td&gt;孙悟空&lt;/td&gt;
                    &lt;td&gt;swk@hgs.com&lt;/td&gt;
                    &lt;td&gt;10000&lt;/td&gt;
                    &lt;td&gt;&lt;a href="javascript:;"&gt;删除&lt;/a&gt;&lt;/td&gt;
                &lt;/tr&gt;
            */

			// 创建元素
			const tr = document.createElement("tr");

			// 创建td
			const nameTd = document.createElement("td");
			const emailTd = document.createElement("td");
			const salaryTd = document.createElement("td");

			// 添加文本
			nameTd.innerText = name;
			emailTd.textContent = email;
			salaryTd.textContent = salary;

			// 将三个td添加到tr中
			tr.appendChild(nameTd);
			tr.appendChild(emailTd);
			tr.appendChild(salaryTd);
			tr.insertAdjacentHTML(
				"beforeend",
				'&lt;td&gt;&lt;a href="javascript:;"&gt;删除&lt;/a&gt;&lt;/td&gt;'
			);

			tbody.appendChild(tr);

			// 由于上边的超链接是新添加的，所以它的上边并没有绑定单级响应函数，所以新添加的员工无法删除
			// 解决方式：为新添加的超链接单独绑定响应函数
			links[links.length - 1].onclick = delEmpHandler;
		};
	});</code></pre>
<p style=""></p>]]></description><guid isPermaLink="false">/2025/js-ex1</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fbanner-%25E6%25A1%2588%25E4%25BE%258B.jpg&amp;size=m" type="image/jpeg" length="13807"/><category>JavaScript</category><pubDate>Tue, 14 Jan 2025 18:04:33 GMT</pubDate></item><item><title><![CDATA[SASS使用规范]]></title><link>https://w-flac.org.cn/2025/scss</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=SASS%E4%BD%BF%E7%94%A8%E8%A7%84%E8%8C%83&amp;url=/2025/scss" width="1" height="1" alt="" style="opacity:0;">
<p style="">在使用 <strong>SCSS</strong> 时，遵循一些最佳实践和规范可以帮助你保持代码的整洁、可维护性和可扩展性。</p>
<p style="">以下是一些常见的 <strong>SCSS 使用规范</strong>，适用于大多数项目：</p>
<h3 style="" id="1.-%E6%96%87%E4%BB%B6%E7%BB%93%E6%9E%84%E8%A7%84%E8%8C%83"><strong>1. 文件结构规范</strong></h3>
<p style="">SCSS 文件的结构应该清晰，以便于组织和维护。常见的文件结构如下：</p>
<pre><code>scss/
├── base/
│   ├── _reset.scss        # 重置样式
│   ├── _typography.scss   # 字体和排版样式
│   └── _variables.scss    # 全局变量
├── components/
│   ├── _buttons.scss      # 按钮样式
│   └── _cards.scss        # 卡片样式
├── layout/
│   ├── _header.scss       # 页头样式
│   ├── _footer.scss       # 页脚样式
│   └── _grid.scss         # 栅格系统
├── pages/
│   ├── _home.scss         # 首页样式
│   └── _about.scss        # 关于页面样式
├── themes/
│   └── _theme.scss        # 主题样式
└── main.scss              # 主入口文件，导入所有其他文件</code></pre>
<ul>
 <li>
  <p style=""><strong>base/</strong> 文件夹包含重置、排版、变量等全局样式。</p>
 </li>
 <li>
  <p style=""><strong>components/</strong> 包含可复用的 UI 组件样式。</p>
 </li>
 <li>
  <p style=""><strong>layout/</strong> 包含布局样式，如页头、页脚、栅格等。</p>
 </li>
 <li>
  <p style=""><strong>pages/</strong> 包含特定页面的样式。</p>
 </li>
 <li>
  <p style=""><strong>themes/</strong> 包含主题样式，允许切换主题时修改变量。</p>
 </li>
 <li>
  <p style=""><code>main.scss</code> 是主入口文件，导入所有其他的 SCSS 文件。</p>
 </li>
</ul>
<h3 style="" id="2.-%E4%BD%BF%E7%94%A8%E5%8F%98%E9%87%8F"><strong>2. 使用变量</strong></h3>
<p style="">使用变量可以提高可维护性和一致性。通常将所有的变量定义在 <code>_variables.scss</code> 中，并且遵循一致的命名规范。</p>
<pre><code class="language-scss">// _variables.scss
$primary-color: #3498db;
$font-family: Arial, sans-serif;
$font-size-base: 16px;</code></pre>
<p style=""><strong>命名规范</strong>：</p>
<ul>
 <li>
  <p style="">使用 <code>kebab-case</code>（短横线连接的小写字母）来命名变量：如 <code>$primary-color</code>。</p>
 </li>
 <li>
  <p style="">为避免命名冲突，可以使用命名空间，如：<code>$theme-primary-color</code>。</p>
 </li>
</ul>
<h3 style="" id="3.-%E5%B5%8C%E5%A5%97%E7%9A%84%E5%90%88%E7%90%86%E4%BD%BF%E7%94%A8"><strong>3. 嵌套的合理使用</strong></h3>
<p style="">SCSS 支持嵌套，但嵌套不应过多，避免深层嵌套导致代码难以维护。一般来说，嵌套层级不应超过 3 层。</p>
<pre><code class="language-scss">// 好的做法
.card {
  padding: 20px;
  .card-header {
    font-size: 1.5rem;
  }
}

// 不推荐：过多的嵌套会影响可维护性
.card {
  padding: 20px;
  .card-header {
    .title {
      font-size: 1.5rem;
    }
  }
}</code></pre>
<h3 style="" id="4.-%E4%BD%BF%E7%94%A8%E6%B7%B7%E5%85%A5%EF%BC%88mixins%EF%BC%89"><strong>4. 使用混入（Mixins）</strong></h3>
<p style="">混入可以复用样式，并接受参数。它们是避免重复代码的有效工具。</p>
<pre><code class="language-scss">// _mixins.scss
@mixin border-radius($radius) {
  -webkit-border-radius: $radius;
  -moz-border-radius: $radius;
  border-radius: $radius;
}

// 使用
.box {
  @include border-radius(10px);
}</code></pre>
<h3 style="" id="5.-%E4%BD%BF%E7%94%A8%E5%8D%A0%E4%BD%8D%E7%AC%A6%EF%BC%88placeholders%EF%BC%89"><strong>5. 使用占位符（Placeholders）</strong></h3>
<p style="">占位符 (<code>%</code>) 用于继承，避免代码重复。它们不像类一样编译成 CSS，只有在被继承时才会被生成。</p>
<pre><code class="language-scss">// _mixins.scss
%button {
  padding: 10px 20px;
  border: none;
  cursor: pointer;
}

.primary-button {
  @extend %button;
  background-color: $primary-color;
}

.secondary-button {
  @extend %button;
  background-color: gray;
}</code></pre>
<h3 style="" id="6.-%E4%BD%BF%E7%94%A8-bem%EF%BC%88%E5%9D%97%E5%85%83%E7%B4%A0%E4%BF%AE%E9%A5%B0%E7%AC%A6%EF%BC%89%E5%91%BD%E5%90%8D%E7%BA%A6%E5%AE%9A"><strong>6. 使用 BEM（块元素修饰符）命名约定</strong></h3>
<p style="">BEM（块元素修饰符）是一种 CSS 类名命名约定，能提高代码的可读性和可维护性。即使使用 SCSS，也推荐使用 BEM 规范来命名类。</p>
<pre><code class="language-scss">// BEM 规范
.button {
  padding: 10px 20px;
  background-color: $primary-color;

  &amp;--primary {
    background-color: $primary-color;
  }

  &amp;--secondary {
    background-color: gray;
  }

  &amp;__icon {
    margin-right: 5px;
  }
}</code></pre>
<h3 style="" id="7.-%E4%BD%BF%E7%94%A8%E5%8A%9F%E8%83%BD%E6%80%A7%E7%B1%BB%E5%90%8D"><strong>7. 使用功能性类名</strong></h3>
<p style="">为了确保代码复用和灵活性，推荐使用功能性类名。避免每个元素都使用具体的名称，而是根据功能来命名。</p>
<pre><code class="language-scss">// 功能性类名
.text-center {
  text-align: center;
}

.no-margin {
  margin: 0;
}</code></pre>
<h3 style="" id="8.-%E4%BD%BF%E7%94%A8%E6%B3%A8%E9%87%8A"><strong>8. 使用注释</strong></h3>
<p style="">清晰的注释可以帮助其他开发者理解你的代码。常用的注释格式如下：</p>
<pre><code class="language-scss">// 变量
$primary-color: #3498db;

// 混入
@mixin border-radius($radius) {
  border-radius: $radius;
}

// 主体样式
body {
  font-family: $font-family;
}</code></pre>
<ul>
 <li>
  <p style=""><strong>单行注释</strong>：<code>//</code> 用于简短的注释。</p>
 </li>
 <li>
  <p style=""><strong>多行注释</strong>：<code>/* */</code> 用于长注释，尤其是描述某个模块的整体功能或特殊逻辑。</p>
 </li>
</ul>
<h3 style="" id="9.-%E9%81%BF%E5%85%8D%E9%87%8D%E5%A4%8D%E7%9A%84%E6%A0%B7%E5%BC%8F"><strong>9. 避免重复的样式</strong></h3>
<p style="">尽量避免为相同的元素或组件编写重复的样式，利用 SCSS 的继承、混入等功能来复用样式。</p>
<pre><code class="language-scss">// 使用 mixin 避免重复
@mixin button($color) {
  padding: 10px 20px;
  border-radius: 5px;
  background-color: $color;
}

.primary-button {
  @include button($primary-color);
}

.secondary-button {
  @include button(gray);
}</code></pre>
<h3 style="" id="10.-%E4%BD%BF%E7%94%A8-%40use"><strong>10. 使用 </strong><code>@use</code></h3>
<ul>
 <li>
  <p style=""><code>@import</code> 已废弃，建议使用 <code>@use</code> 来导入 SCSS 文件。<code>@use</code> 会自动命名空间化导入的样式，避免全局污染。</p>
 </li>
</ul>
<pre><code class="language-scss">// _variables.scss
$primary-color: #3498db;

// main.scss
@use 'variables';

.button {
  background-color: variables.$primary-color;
}</code></pre>
<h3 style="" id="%E6%80%BB%E7%BB%93">总结</h3>
<p style="">遵循这些 SCSS 使用规范有助于保持代码的结构清晰、可读性高、可维护性强。</p>
<p style="">合理使用变量、嵌套、混入、BEM 命名和文件结构将大大提高开发效率，并避免出现难以调试和维护的代码。</p>]]></description><guid isPermaLink="false">/2025/scss</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2FSCSS-or-CSS.webp&amp;size=m" type="image/jpeg" length="6622"/><category>CSS</category><pubDate>Wed, 8 Jan 2025 08:40:22 GMT</pubDate></item><item><title><![CDATA[JavaScript - 正则表达式]]></title><link>https://w-flac.org.cn/2025/regular-expression</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=JavaScript%20-%20%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F&amp;url=/2025/regular-expression" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">正则表达式是一种强大的文本处理工具，用于匹配字符串中的特定模式。在 JavaScript 中，正则表达式被广泛用于字符串的搜索、替换、验证等操作。</p>
</blockquote>
<hr>
<h2 style="" id="%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F">正则表达式</h2>
<h3 style="" id="%3E%E7%AE%80%E4%BB%8B">&gt;简介</h3>
<ul>
 <li>
  <p style="">正则表达式用来定义一个规则</p>
 </li>
 <li>
  <p style="">通过这个规则计算机可以检查一个字符串是否符合规则，或者将字符串中符合规则的内容提取出来。</p>
 </li>
 <li>
  <p style="">正则表达式也是JS中的一个对象，所以要使用正则表达式，需要先创建正则表达式的对象。</p>
 </li>
</ul>
<blockquote>
 <h4 style="" id="%E5%88%9B%E5%BB%BA-new-regexp()">创建 new RegExp()</h4>
</blockquote>
<pre><code class="language-javascript"> // new RegExp() 可以接收两个参数（字符串） 1.正则表达式 2.匹配模式
let reg = new RegExp("a", "i") // 通过构造函数来创建一个正则表达式的对象
let reg = /a/i</code></pre>
<p style=""><code>let reg = new RegExp("a", "i")</code> 和 <code>let reg = /a/i</code> 这两行代码定义了一个正则表达式 <code>reg</code>，它匹配字母 "a"，并且忽略大小写（由于使用了 "i" 标志）。</p>
<blockquote>
 <h4 style="" id="%E5%AD%97%E9%9D%A2%E9%87%8F-xx-%3D-%2F%3F%2F">字面量 xx = /?/</h4>
</blockquote>
<pre><code class="language-javascript">// 使用字面量来创建正则表达式：/正则/匹配模式
let reg = /\w/</code></pre>
<p style=""><code>let reg = /\w/</code> 这行代码将 <code>reg</code> 重新定义为匹配任何字母、数字或下划线的正则表达式（<code>\w</code> 是一个字符类）。</p>
<pre><code class="language-javascript">let reg = new RegExp("\\w")
    reg = new RegExp("a") // /a/ 表示，检查一个字符串中是否有a</code></pre>
<p style=""><code>reg = new RegExp("\\w")</code> 这行代码将 <code>reg</code> 重新定义为匹配任何字母、数字或下划线的正则表达式。在 JavaScript 中，字符串中的反斜杠是一个转义字符，所以我们需要使用两个反斜杠 <code>\\</code> 来表示一个实际的反斜杠。因此，<code>"\\w"</code> 在正则表达式中表示 <code>\w</code>，它是一个字符类，匹配任何字母、数字或下划线。</p>
<p style=""><code>reg = new RegExp("a")</code> 这行代码将 <code>reg</code> 重新定义为匹配字母 "a" 的正则表达式。</p>
<pre><code class="language-javascript">// 通过正则表达式检查一个字符串是否符合规则
let str = "a"

let result = reg.test(str) // true

    result = reg.test("b") // false
    result = reg.test("abc") // true
    result = reg.test("bcabc") // true

    reg = /a/
    console.log(result);</code></pre>
<p style=""><code>let str = "a"</code> 这行代码定义了一个字符串 <code>str</code>，内容为 "a"。</p>
<p style=""><code>let result = reg.test(str)</code> 这行代码使用正则表达式 <code>reg</code> 测试字符串 <code>str</code>，并将结果存储在 <code>result</code> 中。由于 <code>reg</code> 最后被定义为匹配 "a"，所以 <code>result</code> 为 <code>true</code>。</p>
<p style=""><code>result = reg.test("b")</code> 这行代码测试字符串 "b"，由于 "b" 不匹配 "a"，所以 <code>result</code> 为 <code>false</code>。</p>
<p style=""><code>result = reg.test("abc")</code> 这行代码测试字符串 "abc"，由于字符串中包含 "a"，所以 <code>result</code> 为 <code>true</code>。</p>
<p style=""><code>result = reg.test("bcabc")</code> 这行代码测试字符串 "bcabc"，由于字符串中包含 "a"，所以 <code>result</code> 为 <code>true</code>。</p>
<p style=""><code>reg = /a/</code> 这行代码将 <code>reg</code> 重新定义为匹配字母 "a" 的正则表达式。</p>
<p style=""><code>console.log(result)</code> 这行代码输出 <code>result</code> 的值。由于前面的测试结果是 <code>true</code>，所以控制台将输出 <code>true</code>。</p>
<h3 style="" id="%3E%E8%AF%AD%E6%B3%95">&gt;语法</h3>
<blockquote>
 <h4 style="" id="%E5%A4%A7%E9%83%A8%E5%88%86%E5%AD%97%E7%AC%A6%E9%83%BD%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E5%86%99">大部分字符都可以直接写</h4>
</blockquote>
<pre><code class="language-javascript">let re = /ab/
let result = re.test('abc')</code></pre>
<blockquote>
 <h4 style="" id="%7C-%E5%9C%A8%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%AD%E8%A1%A8%E7%A4%BA%E6%88%96">| 在正则表达式中表示或</h4>
</blockquote>
<pre><code class="language-javascript">let re = /abc|bcd/
let result = re.test('c') //false</code></pre>
<blockquote>
 <h4 style="" id="%5B%5D-%E8%A1%A8%E7%A4%BA%E6%88%96%EF%BC%88%E5%AD%97%E7%AC%A6%E9%9B%86%EF%BC%89">[] 表示或（字符集）</h4>
</blockquote>
<ul>
 <li>
  <p style="">[a-z] 任意的小写字母</p>
 </li>
 <li>
  <p style="">[A-Z] 任意的大写字母</p>
 </li>
 <li>
  <p style="">[a-zA-Z] 任意的字母</p>
 </li>
 <li>
  <p style="">[0-9]任意数字</p>
 </li>
</ul>
<pre><code class="language-javascript">let re = /[ab]/ 
    re = /[a-z]/i    //匹配模式i 表示忽略大小写
let result = re.test('c') //false
let result = re.test('a') //true</code></pre>
<blockquote>
 <h4 style="" id="%5B%5E%5D-%E8%A1%A8%E7%A4%BA%E9%99%A4%E4%BA%86">[^] 表示除了</h4>
</blockquote>
<ul>
 <li>
  <p style="">[^x] 除了x</p>
 </li>
</ul>
<pre><code class="language-javascript">let re = /[^a-z]/   //匹配包含小写字母以外内容的字符串
let result = re.test('c') //false
let result = re.test('aH') //true</code></pre>
<blockquote>
 <p style="">. 表示除了换行外的任意字符</p>
</blockquote>
<pre><code class="language-javascript">let re = /./ 
let result = re.test('aH') //true</code></pre>
<blockquote>
 <h4 style="" id="%E5%9C%A8%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%AD%E4%BD%BF%E7%94%A8%5C%E4%BD%9C%E4%B8%BA%E8%BD%AC%E4%B9%89%E5%AD%97%E7%AC%A6">在正则表达式中使用\作为转义字符</h4>
</blockquote>
<pre><code class="language-javascript">let re = /\./   //表示只匹配.
let result = re.test('c') //false</code></pre>
<blockquote>
 <h4 style="" id="%E5%85%B6%E4%BB%96%E7%9A%84%E5%AD%97%E7%AC%A6%E9%9B%86">其他的字符集</h4>
</blockquote>
<ul>
 <li>
  <p style="">\w 任意的单词字符 [A-Za-z0-9_]</p>
 </li>
</ul>
<ul>
 <li>
  <p style="">\W 除了单词字符 [^A-Za-z0-9_]</p>
 </li>
 <li>
  <p style="">\d 任意数字 [0-9]</p>
 </li>
 <li>
  <p style="">\D 除了数字 [^0-9]</p>
 </li>
 <li>
  <p style="">\s 空格</p>
 </li>
 <li>
  <p style="">\S 除了空格</p>
 </li>
 <li>
  <p style="">\b 单词边界</p>
 </li>
 <li>
  <p style="">\B 除了单词边界</p>
 </li>
</ul>
<blockquote>
 <h4 style="" id="%E5%BC%80%E5%A4%B4%E5%92%8C%E7%BB%93%E5%B0%BE">开头和结尾</h4>
</blockquote>
<ul>
 <li>
  <p style="">^ 表示字符串的开头</p>
  <pre><code class="language-javascript">let re = /^a/   //表示匹配开始位置的a
let result = re.test('c') //false</code></pre>
 </li>
 <li>
  <p style="">$ 表示字符串的结尾</p>
  <pre><code class="language-javascript">let re = /a$/   //表示匹配结束位置的a
    re = /^a$/ //完全匹配，只匹配字母a,要求字符串必须和正则完全一致
let result = re.test('a') //true
console.log(result)</code></pre>
 </li>
</ul>
<h3 style="" id="%3E%E9%87%8F%E8%AF%8D">&gt;量词</h3>
<blockquote>
 <h4 style="" id="%7Bm%7D-%E6%AD%A3%E5%A5%BDm%E4%B8%AA">{m} 正好m个</h4>
</blockquote>
<pre><code class="language-javascript">let re = /a{3}/ 
    re = /^ab{3}$/ //实际上匹配的是 abbb
    re = /^(ab){3}$/
let result = re.test("aaa") // true</code></pre>
<blockquote>
 <h4 style="" id="%7Bm%2C%7D-%E6%AD%A3%E5%B0%91m%E4%B8%AA">{m,} 正少m个</h4>
</blockquote>
<pre><code class="language-javascript">let re = /^(ab){1,}$/ </code></pre>
<blockquote>
 <h4 style="" id="%7Bm%2Cn%7D-%E6%AD%A3%E5%B0%91m-n%E4%B8%AA">{m,n} 正少m-n个</h4>
</blockquote>
<pre><code class="language-javascript">let re = /^(ab){1,3}$/ </code></pre>
<blockquote>
 <h4 style="" id="%2B-%E4%B8%80%E4%B8%AA%E4%BB%A5%E4%B8%8A%EF%BC%8C%E7%9B%B8%E5%BD%93%E4%BA%8E%7B1%2C%7D">+ 一个以上，相当于{1,}</h4>
</blockquote>
<pre><code class="language-javascript">let re = /^ba+$/ </code></pre>
<blockquote>
 <h4 style="" id="*-%E4%BB%BB%E6%84%8F%E6%95%B0%E9%87%8F">* 任意数量</h4>
</blockquote>
<pre><code class="language-javascript">let re = /^ba*$/ </code></pre>
<blockquote>
 <h4 style="" id="%3F-0-1%E6%AC%A1%EF%BC%8C%E7%9B%B8%E5%BD%93%E4%BA%8E%7B0%2C1%7D">? 0-1次，相当于{0,1}</h4>
</blockquote>
<pre><code class="language-javascript">let re = /^ba?$/ </code></pre>
<h3 style="" id="%3Eexec%E6%96%B9%E6%B3%95">&gt;exec方法</h3>
<p style="">获取字符串中符合正则表达式的内容</p>
<blockquote>
 <p style="">g表示全局匹配</p>
</blockquote>
<pre><code class="language-javascript">let str = "abcaecafcacc"

// 提取出str中符合axc格式的内容

// g表示全局匹配
let re = /a(([a-z])c)/ig

let result = re.exec(str)

//    console.log(result)

while(result){
    console.log(result[0], result[1], result[2])
    result = re.exec(str)
}</code></pre>
<blockquote>
 <h4 style="" id="%E5%B0%8F%E7%BB%83%E4%B9%A0">小练习</h4>
</blockquote>
<pre><code class="language-javascript">/* 
    dajsdh13715678903jasdlakdkjg13457890657djashdjka13811678908sdadadasd

    用自己的语言来把描述出来
        1    3         501789087
        1    3到9之间   任意数字 x 9

*/

let re = /1[3-9]\d{9}/g

re = /(1[3-9]\d)\d{4}(\d{4})/g

let str =
    "dajsdh13715678903jasdlakdkjg13457890657djashdjka13811678908sdadadasd"

let result

while (result = re.exec(str)) {
    // console.log(result[0], result[1], result[2])
    console.log(result[1] + "****" + result[2])
}


re = /^1[3-9]\d{9}$/

console.log(re.test("13456789042"))</code></pre>
<h3 style="" id="%3E%E5%AD%97%E7%AC%A6%E4%B8%B2">&gt;字符串</h3>
<blockquote>
 <h4 style="" id="split(-)-%E6%A0%B9%E6%8D%AE%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%AF%B9%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%8B%86%E5%88%86">split( ) 根据正则表达式对一个字符串拆分</h4>
</blockquote>
<pre><code class="language-javascript">let str = "孙悟空abc猪八戒abc沙和尚"
let result = str.split(/a[bc]c/)
console.log(result) // (3)&nbsp;['孙悟空', '猪八戒', '沙和尚']</code></pre>
<blockquote>
 <h4 style="" id="search(-)-%E6%90%9C%E7%B4%A2%E7%AC%AC%E4%B8%80%E6%AC%A1%E5%9C%A8%E7%AC%A6%E5%90%88%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E5%86%85%E5%AE%B9%E5%87%BA%E7%8E%B0%E7%9A%84%E4%BD%8D%E7%BD%AE">search( ) 搜索第一次在符合正则表达式的内容出现的位置</h4>
</blockquote>
<pre><code class="language-javascript">let str = "dajsdh13715678903jasdlakdkjg13457890657djashdjka13811678908sdadadasd"
let result = str.search(/1[3-9]\d{9}/)
console.log(result) // 6</code></pre>
<blockquote>
 <h4 style="" id="replace(-)-%E6%A0%B9%E6%8D%AE%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%9B%BF%E6%8D%A2%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E7%9A%84%E6%8C%87%E5%AE%9A%E5%86%85%E5%AE%B9">replace( ) 根据正则表达式替换字符串中的指定内容</h4>
</blockquote>
<pre><code class="language-javascript">let result = str.replace(/1[3-9]\d{9}/g, "哈哈哈")</code></pre>
<blockquote>
 <h4 style="" id="match(-)-%E6%A0%B9%E6%8D%AE%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8E%BB%E5%8C%B9%E9%85%8D%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E7%AC%A6%E5%90%88%E8%A6%81%E6%B1%82%E7%9A%84%E5%86%85%E5%AE%B9">match( ) 根据正则表达式去匹配字符串中符合要求的内容</h4>
</blockquote>
<pre><code class="language-javascript">let str = "dajsdh13715678903jasdlakdkjg13457890657djashdjka13811678908sdadadasd"
let result = str.match(/1[3-9]\d{9}/g)
console.log(result) // (3)&nbsp;['13715678903', '13457890657', '13811678908']</code></pre>
<blockquote>
 <h4 style="" id="matchall()-%E6%A0%B9%E6%8D%AE%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8E%BB%E5%8C%B9%E9%85%8D%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E7%AC%A6%E5%90%88%E8%A6%81%E6%B1%82%E7%9A%84%E5%86%85%E5%AE%B9(%E5%BF%85%E9%A1%BB%E8%AE%BE%E7%BD%AEg-%E5%85%A8%E5%B1%80%E5%8C%B9%E9%85%8D)">matchAll() 根据正则表达式去匹配字符串中符合要求的内容(必须设置g 全局匹配)</h4>
 <p style="">它返回的是一个迭代器</p>
</blockquote>
<pre><code class="language-javascript">let result = str.matchAll(/1[3-9]\d{9}/g)
for(let item of result){
    console.log(item)
}</code></pre>
<h3 style="" id="%3E%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6">&gt;垃圾回收</h3>
<p style="">和生活一样，生活时间长了以后会产生生活垃圾。程序运行一段时间后也会产生垃圾。</p>
<blockquote>
 <p style="">在程序的世界中，什么是垃圾？</p>
 <ul>
  <li>
   <p style="">如果一个对象没有任何的变量对其进行引用，那么这个对象就是一个垃</p>
  </li>
  <li>
   <p style="">垃圾对象的存在，会严重的影响程序的性能</p>
  </li>
  <li>
   <p style="">在JS中有自动的垃圾回收机制，这些垃圾对象会被解释器自动回收，我们无需手动处理</p>
  </li>
  <li>
   <p style="">对于垃圾回收来说，我们唯一能做的事情就是将不再使用的变量设置为null</p>
  </li>
 </ul>
</blockquote>
<pre><code class="language-javascript">let obj = {name:"孙悟空"}
let obj2 = obj

obj = null
obj2 = null</code></pre>
<p style=""></p>]]></description><guid isPermaLink="false">/2025/regular-expression</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fbanner-%25E5%2589%258D%25E7%25AB%25AF-fyjy.png&amp;size=m" type="image/jpeg" length="26871"/><category>JavaScript</category><pubDate>Tue, 7 Jan 2025 15:59:41 GMT</pubDate></item><item><title><![CDATA[JavaScript - 内建对象]]></title><link>https://w-flac.org.cn/2025/javascript-nei-jian-dui-xiang</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=JavaScript%20-%20%E5%86%85%E5%BB%BA%E5%AF%B9%E8%B1%A1&amp;url=/2025/javascript-nei-jian-dui-xiang" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">JavaScript 中的内建对象是由语言本身提供的一系列对象，无需实例化即可使用。这些对象覆盖了从数学计算、日期处理到数据结构操作等多种功能。常见的内建对象包括<span style="font-size: 13px; color: rgb(204, 204, 204)"> </span><code>Object</code><span style="font-size: 13px; color: rgb(204, 204, 204)">, </span><code>Array</code><span style="font-size: 13px; color: rgb(204, 204, 204)">, </span><code>Math</code><span style="font-size: 13px; color: rgb(204, 204, 204)">, </span><code>Date</code><span style="font-size: 13px; color: rgb(204, 204, 204)">, </span><code>JSON</code><span style="font-size: 13px; color: rgb(204, 204, 204)">, </span><code>RegExp</code><span style="font-size: 13px; color: rgb(204, 204, 204)"> </span>等。</p>
</blockquote>
<hr>
<h2 style="" id="%E5%86%85%E5%BB%BA%E5%AF%B9%E8%B1%A1">内建对象</h2>
<h3 style="" id="%3E%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC">&gt;解构赋值</h3>
<p style="">ES6中引入的一种新的赋值方式，它允许我们从数组或对象中提取数据并赋值给新的变量。这种语法形式非常简洁，使得变量的赋值和声明更加直观和方便。</p>
<pre><code class="language-javascript">const arr = ["孙悟空", "猪八戒", "沙和尚"]

let a,
    b,
    c

    // a = arr[0]
    // b = arr[1]
    // c = arr[2]
;[a, b, c] = arr // 解构赋值

let [d, e, f, g] = ["唐僧", "白骨精", "蜘蛛精", "玉兔精"] // 声明同时解构

console.log(d, e, f, g)
// ;[d, e, f, g] = [1, 2, 3]
// ;[d, e, f = 77, g = 10] = [1, 2, 3]
;[d, e, f = 77, g = g] = [1, 2, 3]

let [n1, n2, ...n3] = [4, 5, 6, 7] // 解构数组时，可以使用...来设置获取多余的元素

// console.log(n1, n2, n3)


function fn(){
    return ["二郎神", "猪八戒"]
}

let [name1, name2] = fn()

// 可以通过解构赋值来快速交换两个变量的值
let a1 = 10
let a2 = 20

// let temp = a1
// a1 = a2
// a2 = temp

;[a1, a2] = [a2, a1] // [20, 10]

const arr2 = ["孙悟空", "猪八戒"]
// console.log(arr2)

;[arr2[0], arr2[1]] = [arr2[1], arr2[0]]
// console.log(arr2)


// console.log("a1 =", a1)
// console.log("a2 =", a2)


/* 
    数组中可以存储任意类型的数据，也可以存数组,
    如果一个数组中的元素还是数组，则这个数组我们就称为是二维数组
*/

const arr3 = [["孙悟空", 18, "男"], ["猪八戒" ,28, "男"]]

// for(let stu of arr3){
//     for(let v of stu){
//         console.log(v)
//     }
// }


let [[name, age, gender], obj] = arr3

console.log(name, age, gender)
console.log(obj)</code></pre>
<h3 style="" id="%3E%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%A7%A3%E6%9E%84">&gt;对象的解构</h3>
<pre><code class="language-javascript">const obj = { name: "孙悟空", age: 18, gender: "男" }

// let { name, age, gender } = obj // 声明变量同时解构对象

let name, age, gender

;({ name, age, gender } = obj)

let { address } = obj // 没有的属性返回undefined

// console.log(name, age, gender)

let {name:a, age:b, gender:c, address:d="花果山"} = obj

console.log(a, b, c, d)</code></pre>
<h3 style="" id="%3E%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%BA%8F%E5%88%97%E5%8C%96">&gt;对象的序列化</h3>
<h4 style="" id="json.stringify()-%E2%80%94%E2%80%94-%E5%8F%AF%E4%BB%A5%E5%B0%86%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E8%BD%AC%E6%8D%A2%E4%B8%BA-json-%E5%AD%97%E7%AC%A6%E4%B8%B2">JSON.stringify() —— 可以将一个对象转换为 JSON 字符串</h4>
<h4 style="" id="json.parse()-%E2%80%94%E2%80%94-%E5%8F%AF%E4%BB%A5%E5%B0%86%E4%B8%80%E4%B8%AA-json-%E6%A0%BC%E5%BC%8F%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%AC%E6%8D%A2%E6%88%90-js-%E5%AF%B9%E8%B1%A1">JSON.parse() —— 可以将一个 JSON 格式的字符串转换成 JS 对象</h4>
<blockquote>
 <p style="">编写 JSON 的注意事项：</p>
 <ul>
  <li>
   <p style="">JSON 字符串有两种类型</p>
   <ul>
    <li>
     <p style="">JSON 对象{}</p>
    </li>
    <li>
     <p style="">JSON 数组[]</p>
    </li>
   </ul>
  </li>
  <li>
   <p style="">JSON 字符串的属性名必须用双引号引起来</p>
  </li>
  <li>
   <p style="">JSON 中可以使用的属性值（元素）</p>
   <ul>
    <li>
     <p style="">数字（Number）</p>
    </li>
    <li>
     <p style="">字符串（String） 必须使用双引号</p>
    </li>
    <li>
     <p style="">布尔值（Boolean）</p>
    </li>
    <li>
     <p style="">空值（Null）</p>
    </li>
    <li>
     <p style="">对象（Object {}）</p>
    </li>
    <li>
     <p style="">数组（Array []）</p>
    </li>
   </ul>
  </li>
  <li>
   <p style="">JSON的格式和JS对象的格式基本上一致的。
    <br>
    注意：JSON字符串如果属性是最后一个，则不要再加,</p>
  </li>
 </ul>
</blockquote>
<pre><code class="language-javascript">/* 
    对象的序列化
        - JS中的对象使用时都是存在于计算机的内存中的
        - 序列化指将对象转换为一个可以存储的格式
            在JS中对象的序列化通常是将一个对象转换为字符串（JSON字符串）
        - 序列化的用途（对象转换为字符串有什么用）：
            - 对象转换为字符串后，可以将字符串在不同的语言之间进行传递
                甚至人可以直接对字符串进行读写操作，使得JS对象可以不同的语言之间传递
            - 用途：
                1. 作为数据交换的格式
                2. 用来编写配置文字
        - 如何进行序列化：
            - 在JS中有一个工具类 JSON （JavaScript Object Notation） JS对象表示法
            - JS对象序列化后会转换为一个字符串，这个字符串我们称其为JSON字符串  
            
        - 也可以手动的编写JSON字符串，在很多程序的配置文件就是使用JSON编写的
*/

const obj = {
    name: "孙悟空",
    age: 18,
}

// 将obj转换为JSON字符串
const str = JSON.stringify(obj) //JSON.stringify() 可以将一个对象转换为JSON字符串

const obj2 = JSON.parse(str) // JSON.parse() 可以将一个JSON格式的字符串转换为JS对象

// console.log(obj)
// console.log(str) // {"name":"孙悟空","age":18}
// console.log(obj2)

const str2 = `{"name":"猪八戒","age":28}`
const str3 = "{}"
const str4 = '["hello", true, []]'

console.log(str2)</code></pre>
<h3 style="" id="%3E%E4%BD%BF%E7%94%A8-json-%E8%BF%9B%E8%A1%8C%E6%B7%B1%E5%A4%8D%E5%88%B6">&gt;使用 JSON 进行深复制</h3>
<pre><code class="language-javascript">const obj = {
    name: "孙悟空",
    friend: {
        name: "猪八戒",
    },
}

// 对obj进行浅复制
const obj2 = Object.assign({}, obj)

// 对obj进行深复制
const obj3 = structuredClone(obj)

// 利用JSON来完成深复制
const str = JSON.stringify(obj)
const obj4 = JSON.parse(str)

// const obj5 = JSON.parse(JSON.stringify(obj))</code></pre>
<h3 style="" id="%3Emap">&gt;Map</h3>
<blockquote>
 <h4 style="" id="%E5%88%9B%E5%BB%BAmap">创建Map</h4>
 <ul>
  <li>
   <p style="">new Map()</p>
  </li>
 </ul>
 <h4 style="" id="%E5%B1%9E%E6%80%A7%E5%92%8C%E6%96%B9%E6%B3%95">属性和方法</h4>
 <ul>
  <li>
   <p style="">map.size() 获取map中键值对的数</p>
  </li>
  <li>
   <p style="">map.set(key, value) 向map中添加键值对</p>
  </li>
  <li>
   <p style="">map.get(key) 根据key获取值</p>
  </li>
  <li>
   <p style="">map.delete(key) 删除指定数据</p>
  </li>
  <li>
   <p style="">map.has(key) 检查map中是否包含指定键</p>
  </li>
  <li>
   <p style="">map.clear() 删除全部的键值对</p>
  </li>
  <li>
   <p style="">map.keys() - 获取map的所有的key</p>
  </li>
  <li>
   <p style="">map.values() - 获取map的所有的value</p>
  </li>
 </ul>
</blockquote>
<pre><code class="language-javascript">/* 
- Map用来存储键值对结构的数据（key-value）
- Object中存储的数据就可以认为是一种键值对结构
- Map和Object的主要区别：
    - Object中的属性名只能是字符串或符号，如果传递了一个其他类型的属性名，JS解释器会自动将其转换为字符串
    - Map中任何类型的值都可以称为数据的key
*/

const obj2 = {}

const obj = {
    "name":"孙悟空",
    'age':18,
    [Symbol()]:"哈哈",
    [obj2]:"嘻嘻"
}

// console.log(obj)

// 创建一个Map
const map = new Map()

map.set("name", "孙悟空")
map.set(obj2, "呵呵")
map.set(NaN, "哈哈哈")

map.delete(NaN)
// map.clear()

console.log(map)
console.log(map.get("name"))
console.log(map.has("name"))</code></pre>
<pre><code class="language-javascript">const map = new Map()

map.set("name", "孙悟空")
map.set("age", 18)
map.set({}, "呵呵")

// 将map转换为数组

const arr = Array.from(map) // [["name","孙悟空"],["age",18]]

const arr = [...map]

const map2 = new Map([
    ["name", "猪八戒"],
    ["age", 18],
    [{}, () =&gt; {}],
])


// 遍历map

// for (const [key, value] of map) {
//     // const [key, value] = entry
//     console.log(key, value)
// }

// map.forEach((key, value)=&gt;{
//     console.log(key, value)
// })

for(const key of map.keys()){
    console.log(key)
}</code></pre>
<h3 style="" id="%3Eset">&gt;Set</h3>
<blockquote>
 <h4 style="" id="%E5%88%9B%E5%BB%BAset">创建Set</h4>
 <ul>
  <li>
   <p style="">new Set()</p>
  </li>
  <li>
   <p style="">new Set([...]</p>
  </li>
 </ul>
 <h4 style="" id="%E6%96%B9%E6%B3%95">方法</h4>
 <ul>
  <li>
   <p style="">size 获取数量</p>
  </li>
  <li>
   <p style="">add() 添加元素</p>
  </li>
  <li>
   <p style="">has() 检查元素</p>
  </li>
  <li>
   <p style="">delete() 删除元素</p>
  </li>
 </ul>
</blockquote>
<pre><code class="language-javascript">/* 
    Set
        - Set用来创建一个集合
        - 它的功能和数组类似，不同点在于Set中不能存储重复的数据                        
*/

// 创建一个Set
const set = new Set()

// 向set中添加数据
set.add(10)
set.add("孙悟空")
set.add(10)

// console.log(set)

// for(const item of set){
//     console.log(item)
// }

const arr = [...set]

// console.log(arr)

const arr2 = [1,2,3,2,1,3,4,5,4,6,7,7,8,9,10]

const set2 = new Set(arr2)

console.log([...set2])</code></pre>
<h3 style="" id="%3Emath">&gt;Math</h3>
<p style="">Math是一个工具类，它为我们提供了数学运算相关的一些常量和方法</p>
<blockquote>
 <h4 style="" id="%E5%B8%B8%E9%87%8F">常量</h4>
 <ul>
  <li>
   <p style="">Math.PI 圆周率</p>
  </li>
 </ul>
 <h4 style="" id="%E6%96%B9%E6%B3%95-1">方法</h4>
 <ul>
  <li>
   <p style="">Math.abs( ) 求一个数的绝对值</p>
  </li>
  <li>
   <p style="">Math.min( ) 求多个值中的最小值</p>
  </li>
  <li>
   <p style="">Math.max( ) 求多个值中的最大值</p>
  </li>
  <li>
   <p style="">Math.pow( ) 求x的y次幂</p>
  </li>
  <li>
   <p style="">Math.sqrt( ) 求一个数的平方根</p>
  </li>
  <li>
   <p style="">Math.floor( ) 向下取整</p>
  </li>
  <li>
   <p style="">Math.ceil( ) 向上取整</p>
  </li>
  <li>
   <p style="">Math.round( ) 四舍五入取整</p>
  </li>
  <li>
   <p style="">Math.trunc( ) 直接去除小数位</p>
  </li>
  <li>
   <p style="">Math.random( ) 生成一个0-1之间的随机数</p>
  </li>
 </ul>
</blockquote>
<pre><code class="language-javascript">// console.log(Math.PI)

let result = Math.abs(10)
result = Math.abs(-10)

result = Math.min(10, 20, 30, 44, 55, -1)
result = Math.max(10, 20, 30, 44, 55, -1)
result = Math.pow(4, 2) // 4 ** 2
result = Math.sqrt(4) // 4 ** .5

result = Math.floor(1.2)
result = Math.ceil(1.2)
result = Math.round(1.4)
result = Math.trunc(1.5)

for (let i = 0; i &lt; 50; i++) {
    /* 
        生成0-5之间的随机数
            Math.random() --&gt; 0 - 1
            生成 0-x之间的随机数：
                Math.round(Math.random() * x)
                Math.floor(Math.random() * (x + 1))

            生成 x-y 之间的随机数
                Math.round(Math.random() * (y-x) + x)
    */
    // result = Math.round(Math.random() * 5)
    // result = Math.floor(Math.random() * 6)

    // 1-6
    // result = Math.round(Math.random() * 5 + 1)

    // 11 - 20
    result = Math.round(Math.random() * 9 + 11)

    console.log(result)
}</code></pre>
<h3 style="" id="%3Edate">&gt;Date</h3>
<p style="">在 JS 中所有的和时间有关的数据都由 Date 对象来表示</p>
<blockquote>
 <h4 style="" id="%E5%88%9B%E5%BB%BAdate">创建Date</h4>
</blockquote>
<pre><code class="language-javascript">let d = new Date() //直接通过new Date()创建时间对象时，它创建的是当前时间的对象

// 可以在 Data()的构造函数中，传递一个表示时间的字符串
// 字符串的格式：月/日/年 时:分:秒
d = new Date("12/31/2024 00:00:00")
// 字符串的格式：年-月-日T时:分:秒
d = new Date("2024年12月31日T00:00:00")
// new Date(年份, 月, 日, 时, 分, 秒, 毫秒)
d = new Date("2024,11,31,00,00,00")
</code></pre>
<blockquote>
 <h4 style="" id="%E6%96%B9%E6%B3%95-2">方法</h4>
 <ul>
  <li>
   <p style="">getFullyear( )获取4 位年份</p>
  </li>
  <li>
   <p style="">getMonth( ) 返回当前日期的月份( 0 - 11 ）</p>
  </li>
  <li>
   <p style="">getDate( ) 返回当前几日</p>
  </li>
  <li>
   <p style="">getDay( ) 返回当前日期是周几（0 - 6) 0 表示周日</p>
  </li>
  <li>
   <p style="">getHours( ) 返回当前时间的小时（0-23）</p>
  </li>
  <li>
   <p style="">getMinutes( ) 返回当前时间的分钟（0-59）</p>
  </li>
  <li>
   <p style="">getSeconds( ) 返回当前时间的秒数（0-59）</p>
  </li>
  <li>
   <p style="">getMilliseconds( ) 返回当前时间的毫秒数（0-999）</p>
  </li>
  <li>
   <p style="">getTime( ) 返回当前日期对象的时间戳</p>
  </li>
 </ul>
 <p style="text-indent: 2em">时间戳：自 1970年1月1日0时0分0秒到当前时间所经历的毫秒数</p>
 <ul>
  <li>
   <p style="">Date.now( ) 获取当前的时间戳</p>
  </li>
 </ul>
</blockquote>
<h3 style="" id="%3E%E6%97%A5%E6%9C%9F%E6%A0%BC%E5%BC%8F%E5%8C%96">&gt;日期格式化</h3>
<p style="">toLocaleDateString( ) —— 将日期转换为本地的字符串</p>
<p style="">toLocaleTimeString( ) —— 将时间转换为本地的字符串</p>
<h4 style="" id="tolocalestring(-)-%E2%80%94%E2%80%94-%E5%8F%AF%E4%BB%A5%E5%B0%86%E4%B8%80%E4%B8%AA%E6%97%A5%E6%9C%9F%E8%BD%AC%E6%8D%A2%E4%B8%BA%E6%9C%AC%E5%9C%B0%E6%97%B6%E9%97%B4%E6%A0%BC%E5%BC%8F%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2">toLocaleString( ) —— 可以将一个日期转换为本地时间格式的字符串</h4>
<blockquote>
 <h4 style="" id="%E5%8F%82%E6%95%B0"><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options" target="_blank">参数</a></h4>
 <ul>
  <li>
   <p style="">描述语言和国家信息的字符串</p>
   <ul>
    <li>
     <p style="">zh-CN 中文中国</p>
    </li>
    <li>
     <p style="">zh-HK 中文香港</p>
    </li>
    <li>
     <p style="">en-US 美国</p>
    </li>
   </ul>
  </li>
  <li>
   <p style="">以对象作为参数，通过对象的属性对日期配置</p>
   <ul>
    <li>
     <p style="">dateStyle 日期 : full , long , medium , short</p>
    </li>
    <li>
     <p style="">timeStyle 时间 : full , long , medium , short</p>
    </li>
    <li>
     <p style="">hour12 时制 : ture , false</p>
    </li>
    <li>
     <p style="">weekday 星期 : long , narrow , short</p>
    </li>
    <li>
     <p style="">year 年份 : numeric , 2-digit</p>
    </li>
   </ul>
  </li>
 </ul>
</blockquote>
<pre><code class="language-javascript">let d =  new Date()

let result = d.toLocaleString("zh-CN", {
    year: "numeric",
    month: "long",
    day: "2-digit",
    weekday: "short",
})

console.log(result)</code></pre>
<h3 style="" id="%3E%E5%8C%85%E8%A3%85%E7%B1%BB">&gt;包装类</h3>
<p style="">在 JS 中，除了直接创建原始值外，也可以创建原始值的对象。</p>
<blockquote>
 <p style="">不推介的做法：</p>
 <ul>
  <li>
   <p style="">new String( ) 创建 String 类型的对象</p>
  </li>
  <li>
   <p style="">new Number( ) 创建 Number 类型的对象</p>
  </li>
  <li>
   <p style="">new Boolean( ) 创建 Boolean 类型的对象</p>
  </li>
 </ul>
</blockquote>
<pre><code class="language-javascript">let str = new String("hello")
let num = new Number(11)
let bool = new Boolean(true)
let bool2 = new Boolean(true)

alert(bool == bool2) // 比较的是内存地址，所以会判断 false </code></pre>
<blockquote>
 <p style="">在 JS 中一共有 5 个包装类：</p>
 <ul>
  <li>
   <p style="">String --&gt; 字符串包装为 String 对象</p>
  </li>
  <li>
   <p style="">Number --&gt; 数值包装为 Number 对象</p>
  </li>
  <li>
   <p style="">Boolean --&gt; 布尔值包装为 Boolean 对象</p>
  </li>
  <li>
   <p style="">BigInt --&gt; 大整数包装为 BigInt 对象</p>
  </li>
  <li>
   <p style="">Symbol --&gt; 符号包装为 Symbol 对象</p>
  </li>
 </ul>
</blockquote>
<p style="">通过包装类可以将一个原始值包装为一个对象，当我们对一个原始值调用方法或属性时，JS解释器会临时将原始值包装为对应的对象，然后调用这个对象的属性或方法。</p>
<p style="">由于原始值会被临时转换为对应的对象，这就意味着对象中的方法都可以直接通过原始值来调用。</p>
<h3 style="" id="%3E%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E6%96%B9%E6%B3%95">&gt;字符串的方法</h3>
<p style="">字符串其本质就是一个字符数组，例如："hello" --&gt; ["h","e","l","l","o"]</p>
<p style="">字符串的很多方法都和数组是非常类似的。</p>
<blockquote>
 <p style="">ength 获取字符串的长度</p>
 <p style="">字符串[索引] 获取指定位置的字符</p>
</blockquote>
<pre><code class="language-javascript">let str = "hello"  
console.log(str.length)
console.log(str[0])</code></pre>
<blockquote>
 <h4 style="" id="%E5%B1%9E%E6%80%A7%E5%92%8C%E6%96%B9%E6%B3%95-1">属性和方法</h4>
 <blockquote>
  <p style="">请注意！字符串是不可变属性！</p>
 </blockquote>
 <ul>
  <li>
   <p style="">str.at( ) 根据索引获取字符，可以接受负索引</p>
  </li>
 </ul>
 <pre><code class="language-javascript">let str = "hello"  
console.log(str.at(0)) //输出 H
console.log(str.at(3)) //输出 l
console.log(str.at(-4)) //输出 e</code></pre>
 <ul>
  <li>
   <p style="">str.charAt( ) 根据索引获取字符，不接受负索引</p>
  </li>
  <li>
   <p style="">str.concat( ) 用来连接两个或多个字符串</p>
  </li>
  <li>
   <p style="">str.includes( ) 用来检查字符串中是否包含某个内容</p>
  </li>
 </ul>
 <pre><code class="language-javascript">let str = "hello hello how are you"
console.log(str.includes("hello")) //输出 true
console.log(str.includes("hello",13)) //第二个参数为字符串的起始位置</code></pre>
 <ul>
  <li>
   <p style="">str.indexof( )</p>
  </li>
  <li>
   <p style="">str.lstIndexOf( )</p>
  </li>
  <li>
   <p style="">str.startsWith( ) 检查一个字符串是否以指定内容开头</p>
  </li>
  <li>
   <p style="">str.endsWith( ) 检查一个字符串是否以指定内容结尾</p>
  </li>
  <li>
   <p style="">str.padStart( ) 通过添加指定的内容，使字符串保持某个长度</p>
  </li>
 </ul>
 <ul>
  <li>
   <p style="">str.padEnd( ) 通过添加指定的内容，使字符串保持某个长度</p>
  </li>
  <li>
   <p style="">str.replace( ) 使用一个新字符串替换一个指定内容</p>
  </li>
  <li>
   <p style="">str.replaceAll( ) 使用一个新字符串替换所有指定内容</p>
  </li>
  <li>
   <p style="">str.slice( ) 对字符串进行切片</p>
  </li>
  <li>
   <p style="">str.substring( ) 截取字符串</p>
  </li>
  <li>
   <p style="">str.split( ) 用来将一个字符串拆分为一个数组</p>
  </li>
  <li>
   <p style="">str.toLowerCase( ) 将字符串转换为小写</p>
  </li>
  <li>
   <p style="">str.toUpperCase( ) 将字符串转换为大写</p>
  </li>
  <li>
   <p style="">str.trim( ) 去除前后空格</p>
  </li>
  <li>
   <p style="">str.trimStart( ) 去除开始空格</p>
  </li>
  <li>
   <p style="">str.trimEnd( )去除结束空格</p>
  </li>
  <li>
   <p style=""><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String" target="_blank">查看更多</a>...</p>
  </li>
 </ul>
</blockquote>
<p style=""></p>]]></description><guid isPermaLink="false">/2025/javascript-nei-jian-dui-xiang</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fbanner-%25E5%2589%258D%25E7%25AB%25AF-fyjy.png&amp;size=m" type="image/jpeg" length="26871"/><category>JavaScript</category><pubDate>Fri, 3 Jan 2025 17:30:47 GMT</pubDate></item><item><title><![CDATA[JavaScript - 高阶函数小练习]]></title><link>https://w-flac.org.cn/2024/Higher-Function</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=JavaScript%20-%20%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E5%B0%8F%E7%BB%83%E4%B9%A0&amp;url=/2024/Higher-Function" width="1" height="1" alt="" style="opacity:0;">
<h3 style="" id="%E4%BB%A3%E7%A0%81%E5%B1%95%E7%A4%BA">代码展示</h3>
<pre><code class="language-javascript">class Person {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
}

const personArr = [
    new Person("孙悟空", 18),
    new Person("沙和尚", 38),
    new Person("红孩儿", 8),
    new Person("白骨精", 16),
]

function filter(arr, cb) {
    const newArr = [] 

    for (let i = 0; i &lt; arr.length; i++) { 
        if (cb(arr[i])) {   
            newArr.push(arr[i]) 
        }
    }

    return newArr 
}


result = filter(personArr, a =&gt; a.name === "孙悟空") 
result = filter(personArr, a =&gt; a.age &gt;= 18)

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = filter(arr, a =&gt; a % 2 === 0)

console.log(result)</code></pre>
<pre><code class="language-javascript">function someFn() {
    return "hello"
}

function outer(cb){
    return () =&gt; {
        console.log("记录日志~~~~~")
        const result = cb()
        return result
    }
}

let result = outer(someFn)

// console.log(result)


function test(){
    console.log("test~~~~")
    return "test"
}

let newTest = outer(test)

newTest()</code></pre>
<hr>
<h3 style="" id="%E7%AC%AC%E4%B8%80%E4%B8%AA%E4%BB%A3%E7%A0%81%E7%89%87%E6%AE%B5%EF%BC%88filter-%E5%87%BD%E6%95%B0%EF%BC%89">第一个代码片段（<code>filter</code> 函数）</h3>
<p style="">这个片段定义了一个 <code>filter</code> 函数，它接受一个数组和一个回调函数作为参数。</p>
<p style=""><code>filter</code> 函数遍历数组，对每个元素调用回调函数进行测试，然后返回一个新数组，其中包含所有通过测试的元素。这个功能类似于 JavaScript 内置的 <code>Array.prototype.filter</code> 方法。</p>
<pre><code class="language-javascript">function filter(arr, cb) {
    const newArr = [];
    for (let i = 0; i &lt; arr.length; i++) {
        if (cb(arr[i])) {
            newArr.push(arr[i]);
        }
    }
    return newArr;
}
</code></pre>
<h3 style="" id="%E7%AC%AC%E4%BA%8C%E4%B8%AA%E4%BB%A3%E7%A0%81%E7%89%87%E6%AE%B5%EF%BC%88outer-%E5%87%BD%E6%95%B0%EF%BC%89">第二个代码片段（<code>outer</code> 函数）</h3>
<p style="">这个片段定义了一个 <code>outer</code> 函数，它接受一个回调函数 <code>cb</code> 作为参数，并返回一个新的函数。</p>
<p style="">这个新函数在执行时会先记录日志，然后调用 <code>cb</code> 并返回其结果。这个模式通常用于在函数执行前后添加额外的逻辑，例如日志记录、性能监控等。</p>
<pre><code class="language-javascript">function outer(cb) {
    return () =&gt; {
        console.log("记录日志~~~~~");
        const result = cb();
        return result;
    };
}
</code></pre>
<h3 style="" id="%E4%B8%8D%E5%90%8C%E7%82%B9">不同点</h3>
<ol>
 <li>
  <p style=""><strong>用途不同</strong>：</p>
  <ul>
   <li>
    <p style=""><code>filter</code> 函数用于数组过滤，生成一个新数组。</p>
   </li>
   <li>
    <p style=""><code>outer</code> 函数用于在回调函数执行前后添加额外的逻辑。</p>
   </li>
  </ul>
 </li>
 <li>
  <p style=""><strong>参数和返回值</strong>：</p>
  <ul>
   <li>
    <p style=""><code>filter</code> 接受一个数组和一个回调函数作为参数，返回一个新数组。</p>
   </li>
   <li>
    <p style=""><code>outer</code> 接受一个回调函数作为参数，返回一个新的函数。</p>
   </li>
  </ul>
 </li>
 <li>
  <p style=""><strong>实现细节</strong>：</p>
  <ul>
   <li>
    <p style=""><code>filter</code> 内部使用 <code>for</code> 循环遍历数组，并根据回调函数的返回值决定是否将元素添加到新数组中。</p>
   </li>
   <li>
    <p style=""><code>outer</code> 返回一个新的匿名函数，该函数在执行时会先记录日志，然后调用并返回回调函数的结果。</p>
   </li>
  </ul>
 </li>
</ol>
<p style=""></p>]]></description><guid isPermaLink="false">/2024/Higher-Function</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2FJavaScript.jpg&amp;size=m" type="image/jpeg" length="14553"/><category>JavaScript</category><pubDate>Sun, 29 Dec 2024 07:07:52 GMT</pubDate></item><item><title><![CDATA[JavaScript - 数组]]></title><link>https://w-flac.org.cn/2024/javascript-4</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=JavaScript%20-%20%E6%95%B0%E7%BB%84&amp;url=/2024/javascript-4" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">在 JavaScript 中，数组是一种用于存储多个值的特殊对象。它提供了丰富的内置方法，如<span style="font-size: 13px; color: rgb(204, 204, 204)"> </span><code>push</code><span style="font-size: 13px; color: rgb(204, 204, 204)">, </span><code>pop</code><span style="font-size: 13px; color: rgb(204, 204, 204)">, </span><code>forEach</code><span style="font-size: 13px; color: rgb(204, 204, 204)">, </span><code>map</code><span style="font-size: 13px; color: rgb(204, 204, 204)">, </span><code>filter</code><span style="font-size: 13px; color: rgb(204, 204, 204)">, </span><code>reduce</code><span style="font-size: 13px; color: rgb(204, 204, 204)"> </span>等，用于操作和访问数组中的元素。数组支持动态添加和删除元素，并且可以通过索引快速访问特定位置的元素。数组的长度是可变的，这使得它在处理数据集合时非常灵活和强大。</p>
</blockquote>
<hr>
<h2 style="" id="%E6%95%B0%E7%BB%84%EF%BC%88array%EF%BC%89">数组（Array）</h2>
<h3 style="" id="%3E%E7%AE%80%E4%BB%8B">&gt;简介</h3>
<blockquote>
 <p style="">数组也是一种复合数据类型，在数组可以存储多个不同类型的数据。</p>
 <p style="">数组中存储的是有序的数据，数组中的每个数据都有一个唯一的索引，可以通过索引来操作获取数据。</p>
 <p style="">数组中存储的数据叫做元素，索引(index)是一组大于 0 的数。</p>
 <p style=""><strong><mark data-color="#fce7f3" style="background-color: #fce7f3; color: inherit">length是用来获取数组的长度。</mark></strong></p>
</blockquote>
<pre><code class="language-javascript">- 创建数组
    通过Array()来创建数组，也可以通过[]来创建数组

    const arr = new Array()
  
- 向数组中添加元素
    语法：
        数组[索引] = 元素

    arr[0] = 10
    arr[1] = 22
    arr[2] = 44
    arr[3] = 88
    arr[4] = 99
 // arr[100] = 99  // 使用数组时，应该避免非连续数组，因为它性能不好
    const arr2 = [1, 2, 3, 4, 5] // 数组字面量

- 读取数组中的元素
    语法：
        数组[索引]
        - 如果读取了一个不存在的元素，不好报错而是返回undefined

    console.log(typeof arr) // object

- length
    - 获取数组的长度，实际值就是数组的最大索引 + 1
      console.log(arr)

    - 向数组最后添加元素：==&gt; 数组[数组.length] = 元素
      arr[arr.length] = 55
      arr[arr.length] = 99

    - length是可以修改的
      arr.length = 5 //改大会让数组变大多出很多空元素，改小则会减少多出的元素</code></pre>
<h3 style="" id="%3E%E9%81%8D%E5%8E%86%E6%95%B0%E7%BB%84">&gt;遍历数组</h3>
<blockquote>
 <p style="">遍历数组简单理解，就是获取到数组中的每一个元素</p>
</blockquote>
<pre><code class="language-javascript">// 任何类型的值都可以成为数组中的元素
let arr = [1, "hello", true, null, { name: "孙悟空" }, () =&gt; {}]

// 创建数组时尽量要确保数组中存储的数据的类型是相同
arr = ["孙悟空", "猪八戒", "沙和尚"]

// console.log(arr[0])
// console.log(arr[1])
// console.log(arr[2])

arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"]

for(let i=0; i&lt;arr.length; i++){
    console.log(arr[i])
}

 for (let i = arr.length - 1; i &gt;= 0; i--) {
     console.log(arr[i])
}</code></pre>
<pre><code class="language-javascript">/* 
    定义一个Person类，类中有两个属性name和age,然后创建几个Person对象，
    将其添加到一个数组中,遍历数组，并打印未成年人的信息
*/

class Person {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
}


const personArr = [
    new Person("孙悟空", 18),
    new Person("沙和尚", 38),
    new Person("红孩儿", 8),
]


for(let i=0; i&lt;personArr.length; i++){
    if(personArr[i].age &lt; 18){
        console.log(personArr[i])
    }
}</code></pre>
<h3 style="" id="%3Efor-of%E8%AF%AD%E5%8F%A5">&gt;for-of语句</h3>
<blockquote>
 <h4 style="" id="for-of-%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E9%81%8D%E5%8E%86%E8%BF%AD%E4%BB%A3%E5%AF%B9%E8%B1%A1">for-of 可以用来遍历迭代对象</h4>
</blockquote>
<pre><code class="language-javascript">语法：
    for(变量 of 可迭代的对象){
        语句...
    }

执行流程：
    for-of的循环体会执行多次，数组中有几个元素就会执行几次，
    每次执行时都会将一个元素赋值给变量


const arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"]

for(let value of arr){
    console.log(value)
}

for(let value of "welcome"){
    console.log(value)
}</code></pre>
<h3 style="" id="%3E%E6%95%B0%E7%BB%84%E7%9A%84%E6%96%B9%E6%B3%95(%E9%9D%9E%E7%A0%B4%E5%9D%8F%E6%80%A7)">&gt;数组的方法(非破坏性)</h3>
<p style=""><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array" target="_self">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array</a></p>
<h4 style="" id="array.isarray()-%E2%80%94%E2%80%94-%E6%A3%80%E6%9F%A5%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E6%98%AF%E5%90%A6%E6%98%AF%E6%95%B0%E7%BB%84">Array.isArray() —— 检查一个对象是否是数组</h4>
<pre><code class="language-javascript">/*
    Array.isArray()
        - 用来检查一个对象是否是数组    
*/
 console.log(Array.isArray({ name: "孙悟空" })) // false
 console.log(Array.isArray([1, 2, 3])) // true</code></pre>
<h4 style="" id="at()-%E2%80%94%E2%80%94-%E7%B4%A2%E5%BC%95%E8%8E%B7%E5%8F%96%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E6%8C%87%E5%AE%9A%E5%85%83%E7%B4%A0">at() —— 索引获取数组中的指定元素</h4>
<pre><code class="language-javascript">/*
    at()
        - 可以根据索引获取数组中的指定元素
        - at可以接收负索引作为参数
*/

 const arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"]
 console.log(arr.at(-2))</code></pre>
<ul>
 <li>
  <p style=""><code>arr.at(-2)</code>使用了数组的<code> at() </code>方法，它允许你通过索引来获取数组中的元素。</p>
 </li>
 <li>
  <p style="">在这个例子中，索引是 -2。<code>at() </code>方法中的负索引表示从数组末尾开始计数。</p>
 </li>
 <li>
  <p style="">因此，<code>arr.at(-2) </code>将获取数组中倒数第二个元素。 对于数组<code> ["孙悟空", "猪八戒", "沙和尚", "唐僧"]</code>，倒数第二个元素是 "沙和尚"。</p>
 </li>
 <li>
  <p style="">所以，这行代码将在控制台输出<code>"沙和尚"</code>。</p>
 </li>
</ul>
<pre><code class="language-javascript">console.log(arr[arr.length - 2])</code></pre>
<ul>
 <li>
  <p style=""><code>arr[arr.length - 2]</code> 使用了标准的数组索引方式来获取元素。</p>
 </li>
 <li>
  <p style=""><code>arr.length</code> 返回数组的长度，对于这个数组是 <code>4</code>。</p>
 </li>
 <li>
  <p style=""><code>arr.length - 2</code> 计算得到 <code>2</code>，这是数组中倒数第二个元素的索引。</p>
 </li>
 <li>
  <p style="">因此，<code>arr[arr.length - 2]</code> 将获取数组中索引为 <code>2</code> 的元素，即 <code>"沙和尚"</code>。</p>
 </li>
 <li>
  <p style="">所以，这行代码也将在控制台输出 <code>"沙和尚"</code>。</p>
 </li>
</ul>
<h4 style="" id="concat()-%E2%80%94%E2%80%94-%E8%BF%9E%E6%8E%A5%E4%B8%A4%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AA%E6%95%B0%E7%BB%84">concat() —— 连接两个或多个数组</h4>
<pre><code class="language-javascript">/* 
    concat()
        - 用来连接两个或多个数组
        - 非破坏性方法，不会影响原数组，而是返回一个新的数组
*/

const arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"]
const arr2 = ["白骨精", "蜘蛛精", "玉兔精"]

let result = arr.concat(arr2, ["牛魔王","铁扇公主"])

console.log(result) 
// 输出：["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精", "蜘蛛精", "玉兔精", "牛魔王", "铁扇公主"]
</code></pre>
<ul>
 <li>
  <p style=""><code>const arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"];</code> 定义了一个包含四个字符串元素的数组 <code>arr</code>。</p>
 </li>
 <li>
  <p style=""><code>const arr2 = ["白骨精", "蜘蛛精", "玉兔精"];</code> 定义了另一个包含三个字符串元素的数组 <code>arr2</code>。</p>
 </li>
 <li>
  <p style=""><code>let result = arr.concat(arr2, ["牛魔王","铁扇公主"]);</code> 使用 <code>concat()</code> 方法合并数组 <code>arr</code>、<code>arr2</code> 和一个新数组 <code>["牛魔王","铁扇公主"]</code>。<code>concat()</code> 方法不会改变原有的数组，而是返回一个新的数组，这个新数组包含了所有合并的元素。合并后的数组被赋值给变量 <code>result</code>。</p>
 </li>
 <li>
  <p style=""><code>console.log(result);</code> 打印变量 <code>result</code> 的值，也就是合并后的新数组。</p>
 </li>
</ul>
<h4 style="" id="indexof()-%7C-lastindexof()">indexOf() | lastIndexOf()</h4>
<pre><code class="language-javascript">/*
    indexOf()
        - 获取元素在数组中第一次出现的索引
        - 参数：
            1. 要查询的元素
            2. 查询的其实位置
*/

console.log(result) 
// 输出：["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精", "蜘蛛精", "玉兔精", "牛魔王", "铁扇公主"]
let result = arr.indexOf("沙和尚", 3)</code></pre>
<ul>
 <li>
  <p style=""><code>indexOf()</code> 方法用于查找元素在数组中首次出现的位置。</p>
 </li>
 <li>
  <p style="">它接收两个参数：要查找的元素和（可选的）搜索的起始位置。</p>
 </li>
 <li>
  <p style="">在这个例子中，我们从索引 3 开始搜索 "沙和尚" 在数组 <code>arr</code> 中的位置。</p>
 </li>
 <li>
  <p style="">因为 "沙和尚" 在数组 <code>arr</code> 中的索引是 2，而 2 小于 3，所以 <code>indexOf()</code> 方法会返回 -1，表示未找到。</p>
 </li>
</ul>
<pre><code class="language-javascript">/*
    lastIndexOf()
        - 获取元素在数组中最后一次出现的位置

        - 返回值：
            找到了则返回元素的索引，
            没有找到返回-1
*/

console.log(result) 
// 输出：["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精", "蜘蛛精", "玉兔精", "牛魔王", "铁扇公主"]
result = arr.lastIndexOf("沙和尚", 3)</code></pre>
<ul>
 <li>
  <p style=""><code>lastIndexOf()</code> 方法用于查找元素在数组中最后一次出现的位置。</p>
 </li>
 <li>
  <p style="">它同样接收两个参数：要查找的元素和（可选的）搜索的起始位置。</p>
 </li>
 <li>
  <p style="">在这个例子中，我们从索引 3 开始向前搜索 "沙和尚" 在数组 <code>arr</code> 中的最后一次出现的位置。</p>
 </li>
 <li>
  <p style="">因为 "沙和尚" 在数组 <code>arr</code> 中的索引是 2，而 2 小于等于 3，所以 <code>lastIndexOf()</code> 方法会返回 2。</p>
 </li>
</ul>
<pre><code class="language-javascript">console.log(result) 
// 输出：["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精", "蜘蛛精", "玉兔精", "牛魔王", "铁扇公主"]
result = arr.indexOf("白骨精")</code></pre>
<ul>
 <li>
  <p style="">这里的 <code>indexOf()</code> 方法查找 "白骨精" 在数组 <code>arr</code> 中首次出现的位置。</p>
 </li>
 <li>
  <p style="">因为 "白骨精" 不在数组 <code>arr</code> 中，所以 <code>indexOf()</code> 方法会返回 -1。</p>
 </li>
</ul>
<h4 style="" id="join()-%E2%80%94%E2%80%94-%E5%B0%86%E5%85%83%E7%B4%A0%E8%BF%9E%E6%8E%A5%E4%B8%BA%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2">join() —— 将元素连接为一个字符串</h4>
<pre><code class="language-javascript">/*
    join()
        - 将一个数组中的元素连接为一个字符串
        - ["孙悟空", "猪八戒", "沙和尚", "唐僧", "沙和尚"] -&gt; "孙悟空,猪八戒,沙和尚,唐僧,沙和尚"
        - 参数：
            指定一个字符串作为连接符
*/
result = arr.join()
result = arr.join("@-@")
result = arr.join("")</code></pre>
<h4 style="" id="slice()-%E2%80%94%E2%80%94-%E7%94%A8%E6%9D%A5%E6%88%AA%E5%8F%96%E6%95%B0%E7%BB%84">slice() —— 用来截取数组</h4>
<pre><code class="language-javascript">/*
   slice()
        - 用来截取数组（非破坏性方法）     
        - 参数：
            1. 截取的起始位置（包括该位置）
            2. 截取的结束位置（不包括该位置）   
                - 第二个参数可以省略不写，如果省略则会一直截取到最后
                - 索引可以是负值

            如果将两个参数全都省略，则可以对数组进行浅拷贝（浅复制）
*/
arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"]
result = arr.slice(0, 2) //输出： ["孙悟空", "猪八戒"]
result = arr.slice(1, 3)
result = arr.slice(1, -1)
result = arr.slice()</code></pre>
<ul>
 <li>
  <p style=""><code>result = arr.slice(0, 2);</code></p>
  <ul>
   <li>
    <p style="">这行代码从索引 0 开始提取，直到索引 2（不包括）为止。</p>
   </li>
   <li>
    <p style="">因此，它将返回数组中的前两个元素：<code>["孙悟空", "猪八戒"]</code>。</p>
   </li>
  </ul>
 </li>
 <li>
  <p style=""><code>result = arr.slice(1, 3);</code></p>
  <ul>
   <li>
    <p style="">这行代码从索引 1 开始提取，直到索引 3（不包括）为止。</p>
   </li>
   <li>
    <p style="">因此，它将返回数组中的第二和第三个元素：<code>["猪八戒", "沙和尚"]</code>。</p>
   </li>
  </ul>
 </li>
 <li>
  <p style=""><code>result = arr.slice(1, -1);</code></p>
  <ul>
   <li>
    <p style="">这行代码从索引 1 开始提取，直到数组倒数第一个元素（不包括）为止。</p>
   </li>
   <li>
    <p style="">因此，它将返回数组中除最后一个元素外的所有元素：<code>["猪八戒", "沙和尚", "唐僧"]</code>。</p>
   </li>
  </ul>
 </li>
 <li>
  <p style=""><code>result = arr.slice();</code></p>
  <ul>
   <li>
    <p style="">当不提供任何参数时，<code>slice()</code> 方法将返回数组的一个浅拷贝。</p>
   </li>
   <li>
    <p style="">因此，它将返回原数组的一个副本：<code>["孙悟空", "猪八戒", "沙和尚", "唐僧"]</code>。</p>
   </li>
  </ul>
 </li>
</ul>
<h3 style="" id="%3E%E6%95%B0%E7%BB%84%E7%9A%84%E5%A4%8D%E5%88%B6">&gt;数组的复制</h3>
<blockquote>
 <h4 style="" id="xx.slice()-%3D%3D%3E-%E6%95%B0%E7%BB%84">xx.slice() ==&gt; 数组</h4>
 <h4 style="" id="object.assign-%3D%3D%3E-%E5%AF%B9%E8%B1%A1">Object.assign ==&gt; 对象</h4>
</blockquote>
<pre><code class="language-javascript">const arr = ["孙悟空", "猪八戒", "沙和尚"]
// const arr2 = arr  // 不是复制
// arr2[0] = "唐僧" // 如此修改，在此打印时会显示["唐僧", "猪八戒", "沙和尚"]，且全局更改

// 如何去复制一个对象 复制必须要产生新的对象
// 当调用slice时，会产生一个新的数组对象，从而完成对数组的复制
const arr3 = arr.slice()


// console.log(arr === arr2) 
// console.log(arr2)

arr3[0] = "唐僧"

console.log(arr) // 输出：["孙悟空", "猪八戒", "沙和尚"]
console.log(arr3) // 输出：["唐僧", "猪八戒", "沙和尚"]</code></pre>
<pre><code class="language-javascript">/* 
    浅拷贝（shallow copy）
        - 通常对对象的拷贝都是浅拷贝
        - 浅拷贝顾名思义，只对对象的浅层进行复制（只复制一层）
        - 如果对象中存储的数据是原始值，那么拷贝的深浅是不重要
        - 浅拷贝只会对对象本身进行复制，不会复制对象中的属性（或元素）
*/

// 创建一个数组
const arr = [{name:"孙悟空"}, {name:"猪八戒"}] // 数组里的元素为对象
const arr2 = arr.slice() // 浅拷贝
console.log(arr)

/*
    深拷贝（deep copy）
        - 深拷贝指不仅复制对象本身，还复制对象中的属性和元素
        - 因为性能问题，通常情况不太使用深拷贝
*/

const arr3 = structuredClone(arr) // 专门用来深拷贝的方法
console.log(arr3)</code></pre>
<pre><code class="language-javascript">const arr = ["孙悟空", "猪八戒", "沙和尚"]

const arr2 = arr.slice()

console.log(arr === arr2) // false

/* 
    ... (展开运算符)
        - 可以将一个数组中的元素展开到另一个数组中或者作为函数的参数传递
        - 通过它也可以对数组进行浅复制
*/

// const arr3 = [arr[0], arr[1], arr[2]] 等价于 const arr3 = [...arr]

const arr3 = [...arr]
// console.log(arr) // ["孙悟空", "猪八戒", "沙和尚"]

const arr3 = ["唐僧", ...arr, "白骨精"]
// console.log(arr3)  // ["唐僧", "孙悟空", "猪八戒", "沙和尚", "白骨精"]

/*
function 关键字用于定义函数。在你的代码中，sum 函数接受三个参数 a, b, 和 c，并返回它们的和。
定义了一个数组 arr4，包含三个元素：10, 20, 和 30。

用两种方式调用 sum 函数：

直接传递数组的元素作为参数：sum(arr4[0], arr4[1], arr4[2])。这种方式结果是 60。

使用扩展运算符传递数组中的所有元素：sum(...arr4)。这种方式也是将数组中的元素作为单独的参数传递给函数，结果同样是 60。
*/

function sum(a, b, c) {
    return a + b + c
}

const arr4 = [10, 20, 30]

let result = sum(arr4[0], arr4[1], arr4[2])

    result = sum(...arr4)

// console.log(result)


/* 
    对象的复制
        - Object.assign(目标对象, 被复制的对象)
        - 将被复制对象中的属性复制到目标对象里，并将目标对象返回

    - 也可以使用展开运算符对对象进行复制
*/

const obj = { name: "孙悟空", age: 18 }

// const obj2 = Object.assign({}, obj)
const obj2 = { address: "花果山", age: 28 } // 后复制的优先替换先前的，比如 age

Object.assign(obj2, obj)
// console.log(obj2)  // 输出: { address: "花果山", name: "孙悟空", age: 18 }

const obj3 = { address: "高老庄", ...obj, age: 48 } // 将obj中的属性在新对象中展开
// 输出: { address: "高老庄", name: "孙悟空", age: 48 }</code></pre>
<h3 style="" id="%3E%E6%95%B0%E7%BB%84%E7%9A%84%E6%96%B9%E6%B3%95(%E7%A0%B4%E5%9D%8F%E6%80%A7)">&gt;数组的方法(破坏性)</h3>
<h4 style="" id="push()-%E2%80%94%E2%80%94-%E5%90%91%E6%95%B0%E7%BB%84%E7%9A%84%E6%9C%AB%E5%B0%BE%E6%B7%BB%E5%8A%A0%E5%85%83%E7%B4%A0%EF%BC%8C%E5%B9%B6%E8%BF%94%E5%9B%9E%E6%96%B0%E7%9A%84%E9%95%BF%E5%BA%A6">push() —— 向数组的末尾添加元素，并返回新的长度</h4>
<pre><code class="language-javascript">push()
    - 向数组的末尾添加一个或多个元素，并返回新的长度

let arr = ["孙悟空", "猪八戒", "沙和尚"]
let result = arr.push("唐僧", "白骨精")
console.log(result); // 输出：5</code></pre>
<ul>
 <li>
  <p style=""><code>let arr = ["孙悟空", "猪八戒", "沙和尚"];</code> 定义了一个包含三个字符串元素的数组 <code>arr</code>。</p>
 </li>
 <li>
  <p style=""><code>let result = arr.push("唐僧", "白骨精");</code> 调用了 <code>push()</code> 方法，向数组 <code>arr</code> 的末尾添加了两个新的元素："唐僧" 和 "白骨精"。</p>
  <ul>
   <li>
    <p style=""><code>push()</code> 方法会返回更新后数组的长度。</p>
   </li>
   <li>
    <p style="">在这个例子中，<code>push()</code> 方法将返回 5，因为添加新元素后数组 <code>arr</code> 的长度变成了 5。</p>
   </li>
  </ul>
 </li>
 <li>
  <p style="">变量 <code>result</code> 将被赋值为 5，这是更新后数组 <code>arr</code> 的长度。</p>
 </li>
</ul>
<h4 style="" id="pop()-%E2%80%94%E2%80%94-%E5%88%A0%E9%99%A4%E5%B9%B6%E8%BF%94%E5%9B%9E%E6%95%B0%E7%BB%84%E7%9A%84%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E5%85%83%E7%B4%A0">pop() —— 删除并返回数组的最后一个元素</h4>
<pre><code class="language-javascript">pop()
    - 删除并返回数组的最后一个元素

let arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"]
result = arr.pop() // 输出："白骨精"</code></pre>
<ul>
 <li>
  <p style=""><code>result = arr.pop();</code> 调用了 <code>pop()</code> 方法，它会删除数组 <code>arr</code> 的最后一个元素，并将其值赋给变量 <code>result</code>。</p>
  <ul>
   <li>
    <p style=""><code>pop()</code> 方法会改变原数组，减少其长度。</p>
   </li>
   <li>
    <p style="">在这个例子中，如果 <code>arr</code> 的初始状态如上所述，<code>pop()</code> 方法将删除 "白骨精" 并返回它。</p>
   </li>
  </ul>
 </li>
 <li>
  <p style="">变量 <code>result</code> 将被赋值为 "白骨精"，这是原数组 <code>arr</code> 被删除的最后一个元素。</p>
 </li>
</ul>
<h4 style="" id="unshift()-%7C-shift()">unshift() | shift()</h4>
<pre><code class="language-javascript">unshift()
    - 向数组的开头添加一个或多个元素，并返回新的长度

let arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"]
arr.unshift("牛魔王")
console.log(arr) // 输出: ["牛魔王","孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"]


shift()
    - 删除并返回数组的第一个元素

arr.shift() //输出: “牛魔王”
console.log(arr) // 输出: ["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"]</code></pre>
<h4 style="" id="splice()-%E2%80%94%E2%80%94-%E5%88%A0%E9%99%A4%E3%80%81%E6%8F%92%E5%85%A5%E3%80%81%E6%9B%BF%E6%8D%A2%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0">splice() —— 删除、插入、替换数组中的元素</h4>
<pre><code class="language-javascript">splice()
    - 可以删除、插入、替换数组中的元素
    - 参数：
        1. 删除的起始位置
        2. 删除的数量
        3. 要插入的元素

    - 返回值：
        - 返回被删除的元素

let arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"]
console.log(arr) //输出: ['孙悟空']

result = arr.splice(1, 3) //输出：["猪八戒", "沙和尚", "唐僧"]
//将删除的元素赋值给 result 

result = arr.splice(1,2,'牛魔王')
console.log(result); // 输出：["猪八戒", "沙和尚"]
console.log(arr);    // 输出：["孙悟空", "牛魔王", "唐僧"]</code></pre>
<ul>
 <li>
  <p style=""><code>arr.splice(1, 2, '牛魔王')</code> 调用了 <code>splice()</code> 方法，它接收至少两个参数：</p>
  <ul>
   <li>
    <p style="">第一个参数 <code>1</code> 是开始修改的索引位置。</p>
   </li>
   <li>
    <p style="">第二个参数 <code>2</code> 是要删除的元素数量。</p>
   </li>
   <li>
    <p style="">第三个参数 <code>'牛魔王'</code> 是要添加进数组的元素，它会在删除元素的位置之后插入。</p>
   </li>
  </ul>
 </li>
 <li>
  <p style=""><code>splice()</code> 方法会改变原数组，并返回一个包含被删除元素的新数组。</p>
 </li>
 <li>
  <p style="">在这个例子中，从索引 <code>1</code> 开始，删除 <code>2</code> 个元素（即 "猪八戒" 和 "沙和尚"），然后在相同的位置插入 <code>'牛魔王'</code>。</p>
 </li>
 <li>
  <p style="">变量 <code>result</code> 将被赋值为 <code>["猪八戒", "沙和尚"]</code>，这是被删除的元素组成的数组。</p>
 </li>
</ul>
<p style="">执行这段代码后，原数组 <code>arr</code> 将变为 <code>["孙悟空", "牛魔王", "唐僧"]</code>，并且变量 <code>result</code> 的值是 <code>["猪八戒", "沙和尚"]</code>。</p>
<pre><code class="language-javascript"> result = arr.splice(1, 0, "牛魔王", "铁扇公主", "红孩儿")</code></pre>
<ul>
 <li>
  <p style=""><code>arr.splice(1, 0, "牛魔王", "铁扇公主", "红孩儿")</code> 调用了 <code>splice()</code> 方法，它接收至少两个参数：</p>
  <ul>
   <li>
    <p style="">第一个参数 <code>1</code> 是开始修改的索引位置。</p>
   </li>
   <li>
    <p style="">第二个参数 <code>0</code> 是要删除的元素数量。</p>
   </li>
   <li>
    <p style="">后续的参数（"牛魔王", "铁扇公主", "红孩儿"）是要添加进数组的元素，它们会在删除元素的位置之后插入。</p>
   </li>
  </ul>
 </li>
 <li>
  <p style=""><code>splice()</code> 方法会改变原数组，并返回一个包含被删除元素的新数组。</p>
 </li>
 <li>
  <p style="">在这个例子中，从索引 <code>1</code> 开始，我们不删除任何元素（删除数量为 <code>0</code>），然后在相同的位置插入 "牛魔王", "铁扇公主", "红孩儿" 这三个元素。</p>
 </li>
 <li>
  <p style="">变量 <code>result</code> 将被赋值为 <code>[]</code>，因为没有任何元素被删除。</p>
 </li>
</ul>
<p style="">执行这段代码后，原数组 <code>arr</code> 将变为 <code>["孙悟空", "牛魔王", "铁扇公主", "红孩儿", "猪八戒", "沙和尚", "唐僧"]</code>，并且变量 <code>result</code> 的值是 <code>[]</code>（空数组）。</p>
<h4 style="" id="reverse()-%E2%80%94%E2%80%94-%E5%8F%8D%E8%BD%AC%E6%95%B0%E7%BB%84">reverse() —— 反转数组</h4>
<pre><code class="language-javascript">reverse()
    - 反转数组

let arr = ["a", "b", "c", "d"]
arr.reverse() //输出：['d', 'c', 'b', 'a']</code></pre>
<h3 style="" id="%3E%E6%95%B0%E7%BB%84%E7%9A%84%E5%8E%BB%E9%87%8D">&gt;数组的去重</h3>
<blockquote>
 <p style="">有如下一个数组<code>arr = [1,2,1,3,2,4,5,5,6,7],</code>编写代码，去除数组中重复的元素。</p>
 <pre><code class="language-javascript">// 定义一个包含重复数字的数组
const arr = [1, 2, 1, 3, 2, 2, 4, 5, 5, 6, 7];

// 外层循环：遍历数组中的每个元素
for (let i = 0; i &lt; arr.length; i++) {
    // 内层循环：从当前元素的下一个元素开始，检查后面的所有元素
    for (let j = i + 1; j &lt; arr.length; j++) {
        // 如果发现外层循环的元素与内层循环的元素相等，说明找到了一个重复的元素
        if (arr[i] === arr[j]) {
            // 使用 splice 方法删除重复的元素
            arr.splice(j, 1);
            // 因为删除了一个元素，后面的元素会向前移动一位，所以需要将 j 退回一位，以确保不会漏掉任何一个元素
            j--;
        }
    }
}

// 打印处理后的数组，此时数组中不再包含重复的元素
console.log(arr); // 输出：[1, 2, 3, 4, 5, 6, 7]
</code></pre>
 <pre><code class="language-javascript">// 定义一个包含重复数字的数组
const arr = [1, 2, 1, 3, 2, 2, 4, 5, 5, 6, 7];

// 遍历数组中的每个元素
for (let i = 0; i &lt; arr.length; i++) {
    // 查找当前元素在数组中从当前位置之后的第一次出现的位置
    const index = arr.indexOf(arr[i], i + 1);
    // 如果找到了重复元素（index不等于空值）
    if (index !== -1) {
        // 删除数组中该重复元素
        arr.splice(index, 1);
        // 由于删除了一个元素，数组的长度减少，需要调整循环变量以避免跳过元素
        i--;
    }
}

// 打印处理后的数组，此时数组中不再包含重复的元素
console.log(arr); // 输出：[1, 2, 3, 4, 5, 6, 7]</code></pre>
 <pre><code class="language-javascript">// 定义一个包含重复数字的数组
const arr = [1, 2, 1, 3, 2, 2, 4, 5, 5, 6, 7];

// 创建一个空数组，用于存储非重复的元素
const newArr = [];

// 遍历原始数组中的每个元素
for (let ele of arr) {
    // 检查当前元素是否已经在 newArr 中
    if (newArr.indexOf(ele) === -1) {
        // 如果当前元素不在 newArr 中，则将其添加到 newArr
        newArr.push(ele);
    }
}

// 打印包含非重复元素的新数组
console.log(newArr); // 输出：[1, 2, 3, 4, 5, 6, 7]
</code></pre>
</blockquote>
<h3 style="" id="%3E%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F">&gt;冒泡排序</h3>
<pre><code class="language-javascript">9, 1, 3, 2, 8, 0, 5, 7, 6, 4

- 比较相邻的两个元素，然后根据大小来决定是否交换它们的位置
- 例子：
    第一次排序：1, 3, 2, 8, 0, 5, 7, 6, 4, 9
    第二次排序：1, 2, 3, 0, 5, 7, 6, 4, 8, 9
    第三次排序：1, 2, 0, 3, 5, 6, 4, 7, 8, 9
    ...
    倒数第二次 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

const arr = [9, 1, 3, 2, 8, 0, 5, 7, 6, 4]

/*
for (let j = 0; j &lt; arr.length - 1; j++) {
    for (let i = 0; i &lt; arr.length - 1; i++) {
        // arr[i] 前边的元素 arr[i+1] 后边元素
        if (arr[i] &lt; arr[i + 1]) {
            // 大数在前，小数在后，需要交换两个元素的位置
            let temp = arr[i] // 临时变量用来存储arr[i]的值
            arr[i] = arr[i + 1] // 将arr[i+1]的值赋给arr[i]
            arr[i + 1] = temp // 修改arr[i+1]的值
        }
    }
}
*/
优化代码：
for (let j = 0; j &lt; arr.length - 1; j++) {
    for (let i = 0; i &lt; arr.length - 1 - j; i++) {
        // arr[i] 前边的元素 arr[i+1] 后边元素
        if (arr[i] &lt; arr[i + 1]) {
            // 大数在前，小数在后，需要交换两个元素的位置
            let temp = arr[i] // 临时变量用来存储arr[i]的值
            arr[i] = arr[i + 1] // 将arr[i+1]的值赋给arr[i]
            arr[i + 1] = temp // 修改arr[i+1]的值
        }
    }
}
console.log(arr)

- 这种排序方式，被称为冒泡排序，冒泡排序是最慢的排序方式，
  数字少还可以凑合用，不适用于数据量较大的排序</code></pre>
<h3 style="" id="%3E%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F">&gt;选择排序</h3>
<pre><code class="language-javascript">- 取出一个元素，然后将其他元素和该元素进行比较，如果其他元素比该元素小则交换两个元素的位置
- 例子：
    第一次排序：0, 9, 3, 2, 8, 1, 5, 7, 6, 4
    第二次排序：0, 1, 9, 3, 8, 2, 5, 7, 6, 4
    第二次排序：0, 1, 2, 9, 8, 3, 5, 7, 6, 4
    ...

console.log(arr)

// 遍历原始数组中的每个元素
for(let i=0; i&lt;arr.length; i++){
    for(let j=i+1; j&lt;arr.length; j++){
        if(arr[i] &gt; arr[j]){
            // 交换两个元素的位置
            let temp = arr[i] // 临时变量用来存储arr[i]的值
            arr[i] = arr[j] // 将arr[i]的值赋给arr[j]
            arr[j] = temp   // 修改arr[j]的值
        }
        }
    }
}

console.log(arr)

  选择排序
    - 取出一个元素，然后将其他元素和该元素进行比较，如果其他元素比该元素小则交换两个元素的位置</code></pre>
<h3 style="" id="%3E%E5%B0%81%E8%A3%85%E5%87%BD%E6%95%B0">&gt;封装函数</h3>
<pre><code class="language-javascript">const arr = [9, 1, 3, 2, 8, 0, 5, 7, 6, 4]
const arr2 = [9, 8, 7, 6, 5, 4, 3, 2, 1]

function sort(array) {
    const arr = [...array]
    for (let i = 0; i &lt; arr.length; i++) {
        for (let j = i + 1; j &lt; arr.length; j++) {
            if (arr[i] &gt; arr[j]) {
                // 交换两个元素的位置
                let temp = arr[i]
                arr[i] = arr[j]
                arr[j] = temp
            }
        }
    }
    return arr
}

let result = sort(arr2)

// console.log(arr2)
// console.log(result)</code></pre>
<pre><code class="language-javascript">class Person {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
}

const personArr = [
    new Person("孙悟空", 18),
    new Person("沙和尚", 38),
    new Person("红孩儿", 8),
    new Person("白骨精", 16),
]


// filter()函数用来对数组进行过滤
function filter(arr) {

    const newArr = []

    for (let i = 0; i &lt; arr.length; i++) {
        if (arr[i].age &lt; 18) {
            newArr.push(arr[i])
        }
    }

    return newArr
}

result = filter(personArr)
console.log(result)


- - - - - - - - - - - - - - - - - 

目前我们的函数只能过滤出数组中age属性小于18的对象，
    - 我们希望过滤更加灵活：
        比如：过滤数组中age大于18的对象
             过滤数组中age大于60的对象
             过滤数组中age大于n的对象
             过滤数组中name为xxx的对象
             过滤数组中的偶数
             ...</code></pre>
<h3 style="" id="%3E%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0">&gt;回调函数</h3>
<blockquote>
 <p style="">如果将函数作为参数传递，那么我们就称这个函数为回调函数（callback）</p>
 <p style="">请注意！一个函数的参数也可以是函数</p>
</blockquote>
<pre><code class="language-javascript">class Person {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
}

const personArr = [
    new Person("孙悟空", 18),
    new Person("沙和尚", 38),
    new Person("红孩儿", 8),
    new Person("白骨精", 16),

function filter(arr, cb) {
    const newArr = []  // 创建一个空数组用于存放符合条件的元素

    //遍历并获取里面的元素
    for (let i = 0; i &lt; arr.length; i++) {
          
         // 当前数组元素 arr[i] 的 name 是否等于 '孙悟空'？”
        if (cb(arr[i])) {  // 这里的 cb 实际上就是 fn

        // 如果是 true（即当前元素符合条件），则将这个元素添加到结果数组中
            newArr.push(arr[i])  // 将符合条件的元素加入 newArr
        }
    }

    return newArr  // 返回新数组
}


function fn(a) {
    return a.name === "孙悟空" // a.name 是数组元素的 name 属性
}

// 调用 filter 函数，传递 personArr 数组和回调函数 fn 作为参数
let result = filter(personArr, fn)

// 打印 filter 函数的返回值，即满足条件的元素组成的数组
console.log(result)</code></pre>
<h3 style="" id="%3E%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0">&gt;高阶函数</h3>
<p style="">如果一个函数的参数或返回值是函数，则这个函数就称为<a href="https://w-flac.org.cn/2024/Higher-Function" target="_blank">高阶函数</a></p>
<blockquote>
 <pre><code class="language-javascript">class Person {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
}

const personArr = [
    new Person("孙悟空", 18),
    new Person("沙和尚", 38),
    new Person("红孩儿", 8),
    new Person("白骨精", 16),
]

function filter(arr, cb) {
    const newArr = [] // 创建一个空数组newArr

    for (let i = 0; i &lt; arr.length; i++) { // 遍历数组中的每个元素
        if (cb(arr[i])) {                 // 如果回调函数对当前元素返回 true
            newArr.push(arr[i])          // 将当前元素添加到 newArr 中
        }
    }

    return newArr // 返回包含所有通过测试的元素的新数组
}

// 我们这种定义回调函数的形式比较少见，通常回调函数都是匿名函数

// function fn(a) {
//     return a.name === "孙悟空"
// }


result = filter(personArr, a =&gt; a.name === "孙悟空")  // 过滤出名字为 "孙悟空" 的 Person 对象
result = filter(personArr, a =&gt; a.age &gt;= 18)

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = filter(arr, a =&gt; a % 2 === 0)

console.log(result)</code></pre>
 <pre><code class="language-javascript">/*
    希望在someFn()函数执行时，可以记录一条日志

    在不修改原函数的基础上，为其增加记录日志的功能

    可以通过高阶函数，来动态的生成一个新函数
*/

function someFn() {
    return "hello"
}

function outer(cb){
    return () =&gt; {
        console.log("记录日志~~~~~")
        const result = cb()
        return result
    }
}

let result = outer(someFn)

// console.log(result)


function test(){
    console.log("test~~~~")
    return "test"
}

let newTest = outer(test)

newTest()</code></pre>
</blockquote>
<h3 style="" id="%3E%E9%97%AD%E5%8C%85%E7%AE%80%E4%BB%8B">&gt;闭包简介</h3>
<p style="">闭包就是能访问到外部函数作用域中变量的函数。</p>
<blockquote>
 <p style="">使用场景：</p>
 <ul>
  <li>
   <p style="">当我们需要隐藏一些不希望被别人访问的内容时就可以使用闭包。</p>
  </li>
 </ul>
 <p style="">构成闭包的要件：</p>
 <ol>
  <li>
   <p style="">函数的嵌套</p>
  </li>
  <li>
   <p style="">内部函数要引用外部函数中的变量</p>
  </li>
  <li>
   <p style="">内部函数要作为返回值返回</p>
  </li>
 </ol>
</blockquote>
<pre><code class="language-javascript">/* 
创建一个函数，第一次调用时打印1，第二次调用打印2，以此类推
可以利用函数，来隐藏不希望被外部访问到的变量
*/

function outer(){
    let num = 0 // 位于函数作用域中

    return () =&gt; {
        num++
        console.log(num)
    }
}

    const newFn = outer()

    // console.log(newFn)
    newFn()</code></pre>
<h3 style="" id="%3E%E9%97%AD%E5%8C%85%E5%8E%9F%E7%90%86">&gt;闭包原理</h3>
<p style="">函数在作用域，在函数创建时就已经确定的（词法作用域），和调用的位置无关。</p>
<p style="">闭包利用的就是词法作用域。</p>
<pre><code class="language-javascript">function fn(){
    console.log(a)
}


function fn2(){
    let a = "fn2中的a"

    fn()
}

// fn2()


function fn3(){
    let a = "fn3中的a"

    function fn4(){
        console.log(a)
    }

    return fn4
}

let fn4 = fn3()

fn4()</code></pre>
<h3 style="" id="%3E%E9%97%AD%E5%8C%85%E7%9A%84%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9">&gt;闭包的注意事项</h3>
<blockquote>
 <p style="">闭包的生命周期：</p>
 <ul>
  <li>
   <p style="">闭包在外部函数调用时产生，外部函数每次调用都会产生一个全新的闭包。</p>
  </li>
  <li>
   <p style="">在内部函数丢失时销毁（内部函数被垃圾回收了，闭包才会消失）。</p>
  </li>
 </ul>
 <p style="">注意事项：</p>
 <ul>
  <li>
   <p style="">闭包主要用来隐藏一些不希望被外部访问的内容，这就意味着闭包需要占用一定的内存空间。</p>
  </li>
  <li>
   <p style="">相对于类来说，闭包比较浪费内存空间（类可以使用原型而闭包不能），
    <br>
    需要执行次数较少时，使用闭包，需要大量创建实例时，使用类。</p>
  </li>
 </ul>
</blockquote>
<pre><code class="language-javascript">function outer2(){
    let num = 0
    return () =&gt; {
        num++
        console.log(num)
    }
}

let fn1 = outer2() // 独立闭包
let fn2 = outer2() // 独立闭包

fn1()
fn2()

fn1 = null
fn2 = null</code></pre>
<h3 style="" id="%3E%E9%80%92%E5%BD%92">&gt;递归</h3>
<blockquote>
 <p style="">调用自身函数称为递归函数，递归的作用和循环是基本一致的.</p>
 <p style="">编写递归函数，一定要包含两个要件：</p>
 <ul>
  <li>
   <p style="">基线条件 —— 递归的终止条件</p>
  </li>
  <li>
   <p style="">递归条件 —— 如何对问题进行拆分</p>
  </li>
 </ul>
</blockquote>
<pre><code class="language-javascript">// 创建一个函数，可以用来求任意数的阶乘
/* 
    1! 1
    2! 1 x 2 = 2
    3! 1 x 2 x 3 = 6
    ...
    10! 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 10 = xxx

    如果用递归来解决阶乘的问题？
        5! = 4! x 5
        4! = 3! x 4
        3! = 2! x 3
        2! = 1! x 2
        1! = 1
*/

function jieCheng(num){
    // 创建一个变量用了记录结果
    let result = 1

    for(let i=2; i&lt;=num; i++){
        result *= i
    }

    return result
}

let result = jieCheng(3)


/*
    递归的作用和循环是一致的，不同点在于，递归思路的比较清晰简洁，循环的执行性能比较好
        在开发中，一般的问题都可以通过循环解决，也是尽量去使用循环，少用递归
        只在一些使用循环解决比较麻烦的场景下，才使用递归
*/


function jieCheng2(num){

    // 基线条件
    if(num === 1){
        return 1
    }

    // 递归条件
    // num! = (num-1)! * num
    return jieCheng2(num-1) * num

}

result = jieCheng2(5)
/* 
    jieCheng2(5)
        - return jieCheng2(4) * 5
            - return jieCheng2(3) * 4
            - return jieCheng2(2) * 3
            - return jieCheng2(1) * 2
                - return 1
*/

console.log(result)</code></pre>
<h3 style="" id="%3E%E9%80%92%E5%BD%92%E7%BB%83%E4%B9%A0">&gt;递归练习</h3>
<pre><code class="language-javascript">/* 
    一对兔子出生后的两个月后每个月都能生一对小兔子
        - 编写一个函数，可以用来计算第n个月的兔子的数量

    1   2   3   4   5   6   7   8   9   10  11  12
    1   1   2   3   5   8   13  21  34 ....
    - 规律，当前数等于前两个数之和（斐波那契数列）
*/

// 求斐波那契数列中的第n个数
function fib(n) {
    // 确定基线条件
    if (n &lt; 3) {
        return 1
    }

    // 设置递归条件
    // 第n个数 = 第n-1个数 + 第n-2个数
    return fib(n - 1) + fib(n - 2)
}

let result = fib(10)

console.log(result)</code></pre>
<h3 style="" id="%3E%E6%95%B0%E7%BB%84%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%88%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%EF%BC%89">&gt;数组的方法（高阶函数）</h3>
<h4 style="" id="sort()-%E2%80%94%E2%80%94-%E6%8E%92%E5%BA%8F%5B%E7%A0%B4%E5%9D%8F%E6%80%A7%5D">sort() —— 排序[破坏性]</h4>
<blockquote>
 <p style="">sort用来对数组进行排序（会改变原数组）。</p>
 <p style="">sort默认会按照 Unicode 编码进行排序，所以如果直接通过 sort 对数字进行排序，可能会得到一个不正确的结果。</p>
</blockquote>
<pre><code class="language-javascript">/* 
    参数：
      - 可以传递一个回调函数作为参数，通过回调函数来指定排序规则
      - (a, b) =&gt; a - b 升序排列
      - (a, b) =&gt; b - a 降序排列  
*/ 

let arr = ["a", "c", "e", "f", "d", "b"]
arr = [2, 3, 1, 9, 0, 4, 5, 7, 8, 6, 10]
arr.sort()</code></pre>
<h4 style="" id="foreach()-%E2%80%94%E2%80%94-%E7%94%A8%E6%9D%A5%E9%81%8D%E5%8E%86%E6%95%B0%E7%BB%84">forEach() —— 用来遍历数组</h4>
<blockquote>
 <p style="">forEach 需要一个回调函数作为参数。</p>
 <p style="">数组中有几个元素，就会被调用几次；每次调用，都会将数组中的数据作为参数传递。</p>
</blockquote>
<pre><code class="language-javascript">/* 
    参数：
      - element 当前的元素
      - index 当前元素的索引
      - array 当前的数组
*/ 

arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"]

arr.forEach((element, index, array) =&gt; {
    console.log(array)
})

arr.forEach((element, index) =&gt; console.log(index, element))</code></pre>
<h4 style="" id="filter()-%E2%80%94%E2%80%94-%E5%B0%86%E7%AC%A6%E5%90%88%E6%9D%A1%E4%BB%B6%E7%9A%84%E6%95%B0%E7%BB%84%E4%BF%9D%E5%AD%98%E5%88%B0%E6%96%B0%E6%95%B0%E7%BB%84%E5%B9%B6%E8%BF%94%E5%9B%9E">filter() —— 将符合条件的数组保存到新数组并返回</h4>
<blockquote>
 <p style="">filter 需要一个回调函数作为参数。</p>
 <p style="">会为每一个元素去调用回调函数，并根据返回值来决定是否将元素添加到新数组中。</p>
 <p style="">filter()是一个非破坏性方法，不会影响原数组。</p>
</blockquote>
<pre><code class="language-javascript">/* 
    参数：
      - element 当前的元素
      - index 当前元素的索引
      - array 当前的数组
*/ 

arr = [1, 2, 3, 4, 5, 6, 7, 8]

// 获取数组中的所有偶数
let result = arr.filter((ele) =&gt; ele % 2 === 0)

result = arr.map((ele) =&gt; ele * 2)</code></pre>
<h4 style="" id="map()-%E2%80%94%E2%80%94-%E6%A0%B9%E6%8D%AE%E5%BD%93%E5%89%8D%E6%95%B0%E7%BB%84%E7%94%9F%E6%88%90%E4%B8%80%E4%B8%AA%E6%96%B0%E6%95%B0%E7%BB%84">map() —— 根据当前数组生成一个新数组</h4>
<blockquote>
 <p style="">map() 需要一个回调函数作为参数。</p>
 <p style="">回调函数的返回值会成为新数组中的元素。</p>
 <p style="">map() 是一个非破坏性方法，不会影响原数组。</p>
</blockquote>
<pre><code class="language-javascript">/* 
    参数：
      - element 当前的元素
      - index 当前元素的索引
      - array 当前的数组
*/ 

result = arr.map((ele) =&gt; ele * 2)

arr = ["孙悟空", "猪八戒", "沙和尚"]

result = arr.map((ele) =&gt; "&lt;li&gt;" + ele + "&lt;/li&gt;")</code></pre>
<h4 style="" id="reduce()-%E2%80%94%E2%80%94-%E5%B0%86%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0%E6%95%B4%E5%90%88%E6%88%90%E4%B8%80%E4%B8%AA%E5%80%BC">reduce() —— 将数组中的元素整合成一个值</h4>
<blockquote>
 <p style="">reduce()需要一个回调函数作为参数。</p>
 <p style="">reduce()需要两个参数：</p>
 <ol>
  <li>
   <p style="">回调函数，通过回调函数来指定合并的规则</p>
  </li>
  <li>
   <p style="">可选参数，初始值</p>
  </li>
 </ol>
</blockquote>
<pre><code class="language-javascript">arr = [1, 2, 3, 4, 5, 6, 7, 8]

result = arr.reduce((a, b) =&gt; {
    /* 
        1, 2
        3, 3
        6, 4
        10, 5
    
    */
    // console.log(a, b)

    return a * b
})

// result = arr.reduce((a, b) =&gt; a + b, 10)


console.log(result)</code></pre>
<h3 style="" id="%3E%E5%8F%AF%E5%8F%98%E5%8F%82%E6%95%B0">&gt;可变参数</h3>
<blockquote>
 <p style="">arguments 是函数中有一个隐含参数。</p>
</blockquote>
<pre><code class="language-javascript">   /* 
        arguments
            - arguments是函数中又一个隐含参数
            - arguments是一个类数组对象（伪数组）
                和数组相似，可以通过索引来读取元素，也可以通过for循环变量，但是它不是一个数组对象，不能调用数组的方法
            - arguments用来存储函数的实参，
                无论用户是否定义形参，实参都会存储到arguments对象中
                可以通过该对象直接访问实参
    */

    // console.log(arguments[2])
    // console.log(Array.isArray(arguments))
    // for (let i = 0; i &lt; arguments.length; i++) {
    //     console.log(arguments[i])
    // }

    // for(let v of arguments){
    //     console.log(v)
    // }

    arguments.forEach((ele) =&gt; console.log(ele))
}

// fn(1, 10, 33)

// 定义一个函数，可以求任意个数值的和
function sum() {
    // 通过arguments，可以不受参数数量的限制更加灵活的创建函数
    let result = 0

    for (let num of arguments) {
        result += num
    }

    return result
}</code></pre>
<blockquote>
 <p style="">可变参数可以接收任意数量实参，并将他们统一存储到一个数组中返回。</p>
</blockquote>
<pre><code class="language-javascript">/* 
    可变参数，在定义函数时可以将参数指定为可变参数
        - 可变参数可以接收任意数量实参，并将他们统一存储到一个数组中返回
        - 可变参数的作用和arguments基本是一致，但是也具有一些不同点：
            1. 可变参数的名字可以自己指定
            2. 可变参数就是一个数组，可以直接使用数组的方法
            3. 可变参数可以配合其他参数一起使用
*/

function fn2(...abc) {
    console.log(abc)
}

function sum2(...num) {
    return num.reduce((a, b) =&gt; a + b, 0)
}

// 当可变参数和普通参数一起使用时，需要将可变参数写到最后
function fn3(a, b, ...args) {
    // for (let v of arguments) {
    //     console.log(v)
    // }

    console.log(args)
}

fn3(123, 456, "hello", true, "1111")</code></pre>
<h3 style="" id="%3E%E5%87%BD%E6%95%B0%E8%A1%A5%E5%85%85">&gt;函数补充</h3>
<blockquote>
 <p style="">根据函数调用方式的不同，this的值也不同：</p>
 <ul>
  <li>
   <p style="">以函数形式调用，this是window</p>
  </li>
  <li>
   <p style="">以方法形式调用，this是调用方法的对象</p>
  </li>
  <li>
   <p style="">构造函数中，this是新建的对象</p>
  </li>
  <li>
   <p style="">箭头函数没有自己的this，由外层作用域决定</p>
  </li>
  <li>
   <p style="">通过call和apply调用的函数，它们的第一个参数就是函数的this</p>
  </li>
  <li>
   <p style="">通过bind返回的函数，this由bind第一个参数决定（无法修改）</p>
  </li>
 </ul>
</blockquote>
<pre><code class="language-javascript">function fn() {
    console.log("函数执行了~", this)
}

const obj = { name: "孙悟空", fn }

/* 
    调用函数除了通过 函数() 这种形式外，还可以通过其他的方式来调用函数
        比如，我们可以通过调用函数的call()和apply()来个方法来调用函数
            函数.call()
            函数.apply()
            - call 和 apply除了可以调用函数，还可以用来指定函数中的this
            - call和apply的第一个参数，将会成为函数的this
            - 通过call方法调用函数，函数的实参直接在第一个参数后一个一个的列出来
            - 通过apply方法调用函数，函数的实参需要通过一个数组传递
*/

// fn.call(obj)
// fn.apply(console)

function fn2(a, b) {
    console.log("a =", a, "b =", b, this)
}

// fn2.call(obj, "hello", true)
fn2.apply(obj, ["hello", true])</code></pre>
<pre><code class="language-javascript">/* 
    bind() 是函数的方法，可以用来创建一个新的函数
        - bind可以为新函数绑定this
        - bind可以为新函数绑定参数

    箭头函数没有自身的this，它的this由外层作用域决定，
        - 也无法通过call apply 和 bind修改它的this 
        - 箭头函数中没有arguments
*/

function fn(a, b, c) {
    console.log("fn执行了~~~~", this)
    console.log(a, b, c)
}

const obj = {name:"孙悟空"}

const newFn = fn.bind(obj, 10, 20, 30)

// newFn()


const arrowFn = () =&gt; {
    console.log(this)
}

// arrowFn.call(obj)

const newArrowFn = arrowFn.bind(obj)

// newArrowFn()

class MyClass{
    fn = () =&gt; {
        console.log(this)
    }
}

const mc = new MyClass()

// mc.fn.call(window)</code></pre>
<p style=""></p>]]></description><guid isPermaLink="false">/2024/javascript-4</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fbanner-%25E5%2589%258D%25E7%25AB%25AF-fyjy.png&amp;size=m" type="image/jpeg" length="26871"/><category>JavaScript</category><pubDate>Wed, 25 Dec 2024 19:20:23 GMT</pubDate></item><item><title><![CDATA[Banner模块代码修改]]></title><link>https://w-flac.org.cn/2024/banner-tailwind</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=Banner%E6%A8%A1%E5%9D%97%E4%BB%A3%E7%A0%81%E4%BF%AE%E6%94%B9&amp;url=/2024/banner-tailwind" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">引入必要的文件</p>
</blockquote>
<pre><code>    &lt;script src="https://cdn.jsdelivr.net/npm/swiper@9/swiper-bundle.min.js"&gt;&lt;/script&gt;
    &lt;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@9/swiper-bundle.min.css" /&gt;</code></pre>
<blockquote>
 <p style="">修改样式</p>
</blockquote>
<pre><code> &lt;style&gt;
   .swiper-pagination-bullet {
            width: 25px;
            height: 5px;
            border-radius: 5px;
            background-color: rgba(255, 255, 255, 0.5);
            transition: all 0.3s ease;
        }
        .swiper-pagination-bullet-active {
            background-color: #3B82F6 !important;
            width: 35px;
        }
    &lt;/style&gt;</code></pre>
<blockquote>
 <p style="">html代码</p>
</blockquote>
<pre><code>       &lt;div class="swiper mySwiper mb-12 rounded-lg overflow-hidden shadow-lg"&gt;
            &lt;div class="swiper-wrapper"&gt;
                &lt;div class="swiper-slide"&gt;
                    &lt;img src="https://source.unsplash.com/random/1200x400?nature" alt="Banner 1" class="w-full h-64 object-cover"&gt;
                    &lt;div class="absolute inset-0 bg-black bg-opacity-40 flex items-center justify-center"&gt;
                        &lt;div class="text-center"&gt;
                            &lt;h2 class="text-3xl font-bold text-white mb-2"&gt;探索自然之美&lt;/h2&gt;
                            &lt;p class="text-xl text-gray-200"&gt;让我们一起领略大自然的魅力&lt;/p&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
                &lt;div class="swiper-slide"&gt;
                    &lt;img src="https://source.unsplash.com/random/1200x400?technology" alt="Banner 2" class="w-full h-64 object-cover"&gt;
                    &lt;div class="absolute inset-0 bg-black bg-opacity-40 flex items-center justify-center"&gt;
                        &lt;div class="text-center"&gt;
                            &lt;h2 class="text-3xl font-bold text-white mb-2"&gt;科技改变生活&lt;/h2&gt;
                            &lt;p class="text-xl text-gray-200"&gt;了解最新科技趋势&lt;/p&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
                &lt;div class="swiper-slide"&gt;
                    &lt;img src="https://source.unsplash.com/random/1200x400?travel" alt="Banner 3" class="w-full h-64 object-cover"&gt;
                    &lt;div class="absolute inset-0 bg-black bg-opacity-40 flex items-center justify-center"&gt;
                        &lt;div class="text-center"&gt;
                            &lt;h2 class="text-3xl font-bold text-white mb-2"&gt;环游世界&lt;/h2&gt;
                            &lt;p class="text-xl text-gray-200"&gt;分享精彩的旅行故事&lt;/p&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class="swiper-pagination"&gt;&lt;/div&gt;
        &lt;/div&gt;</code></pre>
<blockquote>
 <p style="">js代码</p>
</blockquote>
<pre><code>    &lt;script&gt;
        var swiper = new Swiper(".mySwiper", {
            spaceBetween: 30,
            centeredSlides: true,
            autoplay: {
                delay: 2500,
                disableOnInteraction: false,
            },
            pagination: {
                el: ".swiper-pagination",
                clickable: true,
                renderBullet: function (index, className) {
                    return '&lt;span class="' + className + '"&gt;&lt;/span&gt;';
                },
            },
        });
    &lt;/script&gt;</code></pre>
<blockquote>
 <p style="">最终样式</p>
</blockquote>
<p style=""><img src="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fimage-rhlh.png&amp;size=m" width="100%" height="100%" style="display: inline-block"></p>
<p style=""></p>]]></description><guid isPermaLink="false">/2024/banner-tailwind</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Ftailwind.png&amp;size=m" type="image/jpeg" length="70572"/><category>CSS</category><pubDate>Tue, 24 Dec 2024 09:16:30 GMT</pubDate></item><item><title><![CDATA[JavaScript之继承？]]></title><link>https://w-flac.org.cn/2024/JavaScript-ji-cheng</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=JavaScript%E4%B9%8B%E7%BB%A7%E6%89%BF%EF%BC%9F&amp;url=/2024/JavaScript-ji-cheng" width="1" height="1" alt="" style="opacity:0;">
<h3 style="" id="%E4%BB%80%E4%B9%88%E6%98%AF%E7%BB%A7%E6%89%BF%EF%BC%9F">什么是继承？</h3>
<p style="">继承是面向对象编程中的一个概念，它允许我们创建一个基于另一个类的新类。新类（子类）继承了父类的属性和方法，并且可以添加或修改这些属性和方法。</p>
<h3 style="" id="%E4%BB%80%E4%B9%88%E6%98%AF-super%EF%BC%9F">什么是 <code>super</code>？</h3>
<p style=""><code>super</code> 是一个关键字，用于访问和调用父类的函数。在子类的构造函数中，<code>super()</code> 调用父类的构造函数。在子类的方法中，<code>super.methodName()</code> 调用父类的 <code>methodName</code> 方法。</p>
<h3 style="" id="%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E7%94%A8-super%EF%BC%9F">为什么要用 <code>super</code>？</h3>
<ul>
 <li>
  <p style=""><strong>初始化父类的属性</strong>：父类的构造函数通常用于初始化父类的属性。如果子类没有调用父类的构造函数，父类的属性就不会被初始化，可能会导致错误。</p>
 </li>
 <li>
  <p style=""><strong>使用父类的方法</strong>：子类可以调用父类的方法，并在此基础上添加新的行为。</p>
 </li>
</ul>
<hr>
<h3 style="" id="%E4%BE%8B%E5%AD%90">例子</h3>
<p style="">假设我们有一个 <code>Animal</code> 类，它有一个构造函数来设置动物的名字：</p>
<pre><code>class Animal {
  constructor(name) {
    this.name = name;
  }
}</code></pre>
<p style="">现在，我们想要创建一个 <code>Dog</code> 类，它继承自 <code>Animal</code>：</p>
<pre><code>class Dog extends Animal {
  constructor(name, breed) {
    super(name); // 调用父类的构造函数，设置名字
    this.breed = breed; // 设置狗的品种
  }
}
</code></pre>
<p style="">在这个例子中，<code>Dog</code> 类的构造函数接受两个参数：<code>name</code> 和 <code>breed</code>。我们使用 <code>super(name)</code> 来调用 <code>Animal</code> 类的构造函数，这样我们就可以设置 <code>Dog</code> 的 <code>name</code> 属性。然后，我们设置 <code>Dog</code> 特有的属性 <code>breed</code>。</p>
<p style="">如果我们不使用 <code>super(name)</code>，那么 <code>Dog</code> 的 <code>name</code> 属性就不会被设置，因为 <code>Animal</code> 类的构造函数没有被调用。</p>
<h3 style="" id="%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E8%83%BD%E7%9B%B4%E6%8E%A5%E8%BF%99%E6%A0%B7%E5%86%99%EF%BC%9F">为什么不能直接这样写？</h3>
<pre><code>class Cat extends Animal {
  constructor() {
    this.age = age;
  }
}
</code></pre>
<p style="">在这个例子中，你尝试直接在 <code>Cat</code> 的构造函数中给 <code>this.age</code> 赋值，但是没有调用 <code>super()</code>。这样做会导致错误，因为：</p>
<ol>
 <li>
  <p style="">JavaScript 要求在访问 <code>this</code> 之前必须调用 <code>super()</code>。</p>
 </li>
 <li>
  <p style="">没有调用 <code>Animal</code> 类的构造函数，所以 <code>Animal</code> 类中定义的属性（如 <code>name</code>）不会被初始化。</p>
 </li>
</ol>
<h3 style="" id="%E6%80%BB%E7%BB%93">总结</h3>
<p style=""><code>super</code> 关键字是 JavaScript 中实现继承的重要工具。它确保父类的构造函数被正确地调用，以便初始化继承的属性，并且它允许子类调用父类的方法。</p>]]></description><guid isPermaLink="false">/2024/JavaScript-ji-cheng</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2FJavaScript.jpg&amp;size=m" type="image/jpeg" length="14553"/><category>日志</category><pubDate>Tue, 17 Dec 2024 19:29:58 GMT</pubDate></item><item><title><![CDATA[JavaScript - 面相对象]]></title><link>https://w-flac.org.cn/2024/JavaScript-3</link><description><![CDATA[<img src="https://w-flac.org.cn/plugins/feed/assets/telemetry.gif?title=JavaScript%20-%20%E9%9D%A2%E7%9B%B8%E5%AF%B9%E8%B1%A1&amp;url=/2024/JavaScript-3" width="1" height="1" alt="" style="opacity:0;">
<blockquote>
 <p style="">JavaScript 中的面向对象编程（OOP）是一种编程范式，它通过对象来模拟现实世界的事物和概念。对象可以包含属性（状态）和方法（行为）。JavaScript 支持构造函数、原型链、继承和类等 OOP 特性，使得代码组织更加结构化和模块化。通过这些特性，开发者可以创建可重用、易于维护和扩展的代码。</p>
</blockquote>
<hr>
<div class="html-edited">
 <br>
</div>
<blockquote>
 <h3 style="" id="%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1">面向对象</h3>
 <h4 style="" id="%3E%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B(oop)">&gt;面向对象编程(OOP)</h4>
 <pre><code class="language-javascript">1. 程序是干嘛的？
 - 程序就是对现实世界的抽象（照片就是对人的抽象）

2. 对象是干嘛的？
 - 一个事物抽象到程序中后就变成了对象
 - 在程序的世界中，一切皆对象

例如：（ ）
心仪的女人：王老五
  - 一个事物通常由两部分组成：数据和功能
  - 一个对象由两部分组成：属性和方法
  - 事物的数据到了对象中，体现为属性
  - 事物的功能到了对象中，体现为方法

  - 数据：
        姓名
        年龄
        身高
        体重

  - 功能：
        睡
        吃  

const five = {
    //添加属性
    name:"王老五",
    age:48,
    height:180,
    weight:100,

    //添加方法
    eat(){
      console.log(this.name + "吃饭了")
    },
    
    sleep(){
      console.log(this.name + "睡觉了")
    }
    
}

3. 面向对象的编程
 - 面向对象的编程指，程序中的所有操作都是通过对象来完成
 - 做任何事情之前都需要先找到它的对象，然后通过对象来完成各种操作</code></pre>
 <h4 style="" id="%3E%E7%B1%BB">&gt;类</h4>
 <blockquote>
  <p style="">使用object创建的问题</p>
 </blockquote>
 <ul>
  <li>
   <p style="">无法区分不同类型的对象</p>
  </li>
  <li>
   <p style="">不方便批量创建对象</p>
  </li>
 </ul>
 <pre><code class="language-javascript">- 在JS中可以通过类(class)来解决这个问题

    1. 类是对象模板，可以将对象中的属性和方法直接定义在类中，
       定义后，就可以直接通过类来创建对象

    2. 通过同一个类创建的对象，我们称为同类对象
       可以使用instanceof来检查一个对象是否是由某个类创建
       如果某个对象是由某个类所创建，则我们称该对象是这个类的实例

    语法：
        class 类名 {} // 类名要使用大驼峰命名
        const 类名 = class {}  
                    
    通过类创建对象
        new 类()

    // const Person = class {}

    // Person类专门用来创建人的对象
    class Person{

    }

    // Dog类式专门用来创建狗的对象
    class Dog{

    }

    const p1 = new Person()  // 调用构造函数创建对象
    const p2 = new Person()

    const d1 = new Dog()
    const d2 = new Dog()

    console.log(p1 instanceof Person) // true
    console.log(d1 instanceof Person) // false

    const five = {
        // 添加属性
        name: "王老五",
        age: 48,
        height: 180,
        weight: 100,

        // 添加方法
        sleep() {
            console.log(this.name + "睡觉了~")
        },

        eat() {
            console.log(this.name + "吃饭了~")
        },
    }

    const yellow = {
        name: "大黄",
        age: 3,
        sleep() {
            console.log(this.name + "睡觉了~")
        },

        eat() {
            console.log(this.name + "吃饭了~")
        },
    }

five.sleep(); // 输出: 王老五睡觉了~
five.eat();   // 输出: 王老五吃饭了~

yellow.sleep(); // 输出: 大黄睡觉了~
yellow.eat();   // 输出: 大黄吃饭了~
</code></pre>
 <h4 style="" id="%3E%E5%B1%9E%E6%80%A7">&gt;属性</h4>
 <p style="">类是创建对象的模板，要创建第一件事就是定义类</p>
 <pre><code class="language-javascript">class Person{
    /* 
        类的代码块，默认就是严格模式，
        类的代码块是用来设置对象的属性的，不是什么代码都能写
    */
    name = "孙悟空" // Person的实例属性name p1.name
    age = 18       // 实例属性只能通过实例访问 p1.age

    static test = "test静态属性" // 使用static声明的属性，是静态属性（类属性） Person.test
    static hh = "静态属性"   // 静态属性只能通过类去访问 Person.hh
}

// 创建Person类的实例
const p1 = new Person()
const p2 = new Person()

console.log(p1)
console.log(p2)

// 访问实例属性
console.log(p1.name); // 输出: 孙悟空
console.log(p1.age);  // 输出: 18

// 访问静态属性
console.log(Person.test); // 输出: test静态属性
console.log(Person.hh);   // 输出: 静态属性</code></pre>
 <h4 style="" id="%3E%E6%96%B9%E6%B3%95">&gt;方法</h4>
 <pre><code class="language-javascript">class person {
    name = "孙悟空"

     sayHello == function(){

     }  添加方法的一种方式

    sayHello(){
        console.log(‘大家好，我是’ + this.name)
    } // 添加方法(实例方法)，实例方法中的this就是当前实例！ 谁调用了就是谁的this，例如P1调用，则this指向P1

    static test(){
      console.log('我是静态方法'，this)
    } // 静态方法（类方法）通过类来调用，静态方法中this 指向的是当前类，例如Person.test调用，则指向Person
} 

const p1 = new Person()
//console.log(P1)

// 调用实例方法
p1.sayHello(); // 输出: 大家好，我是孙悟空

// 调用静态方法
Person.test(); // 输出: 我是静态方法 [class Person]</code></pre>
 <h4 style="" id="%3E%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0">&gt;构造函数</h4>
</blockquote>
<pre><code class="language-javascript">// class Person{
//     name="孙悟空" // 当我们在类中直接指定实例属性的值时，
//                 // 意味着我们创建的所有对象的属性都是这个值
//     age=18
//     gender="男"

//     sayHello(){
//         console.log(this.name)
//     }
// }

// 创建一个Person的实例
// const p1 = new Person("孙悟空", 18, "男")
// const p2 = new Person("猪八戒", 28, "男")
// const p3 = new Person("沙和尚", 38, "男")

// console.log(p1)
// console.log(p2)
// console.log(p3)

class Person{
            
    // 在类中可以添加一个特殊的方法constructor
    // 该方法我们称为构造函数（构造方法）
    // 构造函数会在我们调用类创建对象时执行

    constructor(name, age, gender){

        // console.log("构造函数执行了~", name, age, gender)
        // 可以在构造函数中，为实例属性进行赋值
        // 在构造函数中，this表示当前所创建的对象

        this.name = name
        this.age = age
        this.gender = gender
    }
}

const p1 = new Person("孙悟空", 18, "男")
const p2 = new Person("猪八戒", 28, "男")
const p3 = new Person("沙和尚", 38, "男")

console.log(p1) //输出: Person { name: '孙悟空', age: 18, gender: '男' }
console.log(p2) //输出: Person { name: ' 猪八戒', age: 28, gender: '男' }
console.log(p3) //输出: Person { name: '沙和尚', age: 38, gender: '男' }</code></pre>
<h4 style="" id="%3E%E5%B0%81%E8%A3%85">&gt;封装</h4>
<blockquote>
 <p style="">面向对象的特点：封装、继承、多态。</p>
 <pre><code class="language-javascript">/* 

1、封装
  - 对象就是一个用来存储不同属性的容器
  - 对象不仅负责存储属性，还要负责数据的安全 例如 P1.name = -11 / haha 数据被修改，不安全
  - 直接添加到对象中的属性并不安全，因为它们可以被任意的修改

  - 如何确保数据的安全？
    ① 私有化数据 :  将需要保护的数据设置为私有，只能在类内部使用
    ② 提供 setter 和 getter 方法来开放对数据的操作 
       - 属性设置私有，通过 getter 和 setter 方法操作属性带来的好处？
         ？可以控制属性的读写权限
         ？可以在方法中对我们的属性值进行验证

  封装为了保护数据的安全，实现封装的方式：！私有化，！getter 及 setter 方法！
  
  get 属性名(){
    return this.#属性
  }
  
  set 属性名(参数){
    可以添加验证逻辑...
    this.#属性 = 参数
  
  }

*/ 

class Person{ 

   // #address = ”花果山“ //实例使用#开头就变成了私有属性，私有属性只能在类内部访问

  #name
  #age
  #gender //私有化属性必须要先声明

  constructor(name,age,gender){
    this.name = name 
    this.age = age 
    this.gender = gender
  } 

  sayHello(){
    console.log(this.#name)
  }
/*
  //getter方法用来读取属性
  getName(){
    return this.#name
  }

  //setter方法用来设置属性
  setName(name){
    this.#name = name
  }

  getAge {
    return this.#age
  }

  setAge(age){
    this.#age = age
  }

  //对属性进行验证
  setAge(age){
    if(age &gt;= 0){
        this.#age = age
    }
  }
*/

  // js中的标准写法，使用属性来调用
  get gender(){
    console.log('getter执行了')
    return this.#gender
  }
  
  set gender(gender){
    this.#gender = gender 
  } // 此处调用则需要p1.gender = "女"
}
  
const p1 = new Person("孙悟空"，18，”男“)

// p1.name = "hello"

// p1.getName()
p1.setAge(-11) // p1.age = 11 // p1.age
p1.setName('猪八戒')

console.log(p1.gender)</code></pre>
 <h4 style="" id="%3E%E5%A4%9A%E6%80%81">&gt;多态</h4>
 <pre><code class="language-javascript">class Person {
    constructor(name) {
        this.name = name
    }
}

class Dog {
    constructor(name) {
        this.name = name
    }
}

class Test {

}

const dog = new Dog('旺财')
const person = new Person("孙悟空")
const test = new Test()

// console.log(dog)
// console.log(person)

/* 
    定义一个函数，这个函数将接收一个对象作为参数，他可以输出hello并打印对象的name属性


    多态
        - 在JS中不会检查参数的类型，所以这就意味着任何数据都可以作为参数传递
        - 要调用某个函数，无需指定的类型，只要对象满足某些条件即可
        - 如果一个东西走路像鸭子，叫起来像鸭子，那么它就是鸭子
        - 多态为我们提供了灵活性
*/
function sayHello(obj) {
    // if(obj instanceof Person){
    console.log("Hello," + obj.name)
    // }
}

sayHello(dog) //输出：你好，旺财！</code></pre>
 <h4 style="" id="%3E%E7%BB%A7%E6%89%BF-(%E8%AF%A6%E8%A7%A3)">&gt;继承 (<a href="https://w-flac.org.cn/JavaScript-ji-cheng" target="_blank">详解</a>)</h4>
 <pre><code class="language-javascript">/* 
    继承
        - 可以通过extends关键来完成继承
        - 当一个类继承另一个类时，就相当于将另一个类中的代码复制到了当前类中（简单理解）
        - 继承发生时，被继承的类称为 父类（超类），继承的类称为 子类
        - 通过继承可以减少重复的代码，并且可以在不修改一个类的前提对其进行扩展

        封装 —— 安全性
        继承 —— 扩展性
        多态 —— 灵活性
*/

class Animal{
    constructor(name){
        this.name = name
    }

    sayHello(){
        console.log("动物在叫~")
    }
}

class Dog extends Animal{

    // 在子类中，可以通过创建同名方法来重写父类的方法
    sayHello(){
        console.log("汪汪汪")
    }
    
}

class Cat extends Animal{

    // 重写构造函数
    constructor(name, age){
        // 重写构造函数时，构造函数的第一行代码必须为super()
        super(name) // 调用父类的构造函数

        this.age = age

    }
            
    sayHello(){

        // 调用一下父类的sayHello
        super.sayHello() // 在方法中可以使用super来引用父类的方法

        console.log("喵喵喵")
    }
}

const dog = new Dog('旺财')
const cat = new cat('汤姆')
dog.sayHello()
cat.sayHello()
console.log(dog)
console.log(cat)</code></pre>
 <h4 style="" id="%3E%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%BB%93%E6%9E%84">&gt;对象的结构</h4>
 <pre><code class="language-javascript">/* 
    对象中存储属性的区域实际有两个：

        1. 对象自身
            - 直接通过对象所添加的属性，位于对象自身中
            - 在类中通过 x = y 的形式添加的属性，位于对象自身中

        2. 原型对象（prototype）
            - 对象中还有一些内容，会存储到其他的对象里（原型对象）
            - 在对象中会有一个属性用来存储原型对象，这个属性叫做__proto__

            - 原型对象也负责为对象存储属性，
                当我们访问对象中的属性时，会优先访问对象自身的属性，
                对象自身不包含该属性时，才会去原型对象中寻找

            - 会添加到原型对象中的情况：
                1. 在类中通过xxx(){}方式添加的方法，位于原型中
                2. 主动向原型中添加的属性或方法

*/

class Person {
    name = "孙悟空"
    age = 18

    // constructor(){
    //     this.gender = "男"
    // }

    sayHello() {
        console.log("Hello，我是", this.name)
    } //此处的方法添加在原型对象中
}

const p = new Person()

// p.address = "花果山"
// p.sayHello = "hello"

console.log(p.sayHello)</code></pre>
 <h4 style="" id="%3E%E5%8E%9F%E5%9E%8B%E5%AF%B9%E8%B1%A1">&gt;原型对象</h4>
 <pre><code class="language-javascript">class Person {
    name = "孙悟空"
    age = 18

    sayHello() {
        console.log("Hello，我是", this.name)
    }
}

const p = new Person()

// console.log(p)
// console.log(p.constructor) 打印p的构造函数，

/* 
    访问一个对象的原型对象
        1.对象.__proto__  
        ==&gt; console.log(p.__proto__)

        2.Object.getPrototypeOf(对象) 
        ==&gt; console.log(Object.getPrototypeOf(p)) 

        ==&gt; console.log(Object.getPrototypeOf(p) === p.__proto__) // 判断是否全等 输出：true
            
    原型对象中的数据：
        1. 对象中的数据（属性、方法等）
        2. constructor（对象的构造函数）

    注意：
        原型对象也有原型，这样就构成了一条原型链，根据对象的复杂程度不同，原型链的长度也不同
            p对象的原型链：p对象 --&gt; 原型 --&gt; 原型 --&gt; null
            obj对象的原型链：obj对象 --&gt; 原型 --&gt; null
*/

const obj = {} // obj.__proto__
console.log(p.__proto__.__proto__) 
console.log(p.__proto__.__proto__.__proto__) // 输出：null</code></pre>
 <pre><code class="language-javascript">class Person {
    name = "孙悟空"
    age = 18

    sayHello() {
        console.log("Hello，我是", this.name)
    }
}

const p = new Person()
const p2 = new Person()

// 所有的同类型对象它们的原型对象都是同一个，也就意味着，同类型对象的原型链是一样的.
console.log(p)
console.log(p2)
console.log(p.__proto__ === p2.__proto__) // 输出：ture


/* 
  原型的作用：
    - 原型就相当于是一个公共的区域，可以被所有该类实例访问，也可以将该类实例中，所有的公共属性（方法）统一存储到原型中,
      这样我们只需要创建一个属性，即可被所有实例访问.

    - 在对象中有些值是对象独有的，像属性（name，age，gender）每个对象都应该有自己值，
      但是有些值对于每个对象来说都是一样的，像各种方法，对于一样的值没必要重复的创建

      p.sayHello = hello
      console.log(p.sayHello) // 输出：hello
      console.log(p2.sayHello) // 输出： sayHello() {console.log("Hello，我是", this.name)}

*/

      // JS中继承就是通过原型来实现的,当继承时，子类的原型就是一个父类的实例
 
class Animal {
      
}

class Cat extends Animal {

}
  
const cat = new Cat()

// cat --&gt; Amimal --&gt; object --&gt;Object原型 --&gt; null 
console.log(cat.__proto__) //输出： Animal {}

/* 
  原型链：
    - 读取对象属性时，会优先对象自身属性，
      如果对象中有，则使用，没有则去对象的原型中寻找
      如果原型中有，则使用，没有则去原型的原型中寻找
      直到找到Object对象的原型（Object的原型没有原型（为null））
      如果依然没有找到，则返回undefined

    - 作用域链，是找变量的链，找不到会报错
    - 原型链，是找属性的链，找不到会返回undefined
*/</code></pre>
 <pre><code class="language-javascript">尝试：
  - 函数的原型链是什么样子的？

  function Person2() {

}
  // Person2 --&gt; 原型 --&gt; Object原型 --&gt; null
  console.log(Person2.__proto__) //输出：原型
  console.log(Person2.__proto__.__proto__) //输出：obj原型
  console.log(Person2.__proto__.__proto__.__proto__) //输出：null

  - Object的原型链是什么样子的？
  
  const Person3 = Object()
  
  // Person3 --&gt; Object原型 --&gt; null
  console.log(Person3.__proto__) //输出：原型
  console.log(Person3.__proto__.__proto__) //输出：obj原型
 </code></pre>
 <h4 style="" id="%3E%E4%BF%AE%E6%94%B9%E5%8E%9F%E5%9E%8B">&gt;修改原型</h4>
 <pre><code class="language-javascript">// 大部分情况下，我们是不需要修改原型对象

class Person {
    name = "孙悟空";
    age = 18;

    sayHello() {
        console.log("Hello，我是", this.name);
    }
}

const p = new Person();
const p2 = new Person();

//通过对象修改原型，向原型中添加方法，修改后所有同类实例都能访问该方法 不要这么做
p.__proto__.run = () =&gt; { 
    console.log('我在跑~');
}

p.run(); // 输出: "我在跑~"
p2.run(); // 输出: "我在跑~"


/*   注意：千万不要通过类的实例去修改原型。
          1. 通过一个对象影响所有同类对象，这么做不合适
          2. 修改原型先得创建实例，麻烦
          3. 危险
*/

class Dog{

}

p.__proto__ = new Dog() //直接为对象赋值了一个新的原型  不要这么做
p.run(); //直接报错，因为原来的原型已经被覆盖</code></pre>
 <pre><code class="language-javascript">/* 
    处理通过__proto__能访问对象的原型外，还可以通过类的prototype属性，来访问实例的原型.
    修改原型时，最好通过通过类去修改.
    
    好处：
        1. 一修改就是修改所有实例的原型
        2. 无需创建实例即可完成对类的修改

    原则：
        1. 原型尽量不要手动改
        2. 要改也不要通过实例对象去改
        3. 通过 类.prototype 属性去修改
        4. 最好不要直接给prototype去赋值
*/ 

console.log(Person.prototype) // 访问Person实例的原型对象
console.log(Person.prototype === p.__proto__) // 输出: true

Person.prototype.fly = () =&gt; {
  console.log("我在飞！")
}

p.fly()
p2.fly()</code></pre>
 <h4 style="" id="%3E_instanceof%E5%92%8Chasown">&gt;_instanceof和hasOwn</h4>
 <ul>
  <li>
   <p style="">instanceof检查的是对象的原型链上是否有该类实例</p>
  </li>
  <li>
   <p style="">Object.hasOwn(对象, 属性名)，用来检查一个对象的自身是否含有某个属性</p>
  </li>
 </ul>
 <pre><code class="language-javascript">// instanceof 用来检查一个对象是否是一个类的实例

class Animal {}

class Dog extends Animal {}

const dog = new Dog()

/* 
  - instanceof检查的是对象的原型链上是否有该类实例，只要原型链上有该类实例，就会返回true

console.log(dog instanceof Dog) // true 

  - dog -&gt; Animal的实例 -&gt; Object实例 -&gt; Object原型

console.log(dog instanceof Animal) // true

 - Object是所有对象的原型，所以任何和对象和Object进行instanceof运算都会返回true

console.log(dog instanceof Object) // true
*/

//获取OBJ实例  
const obj = new Object()
console.log(obj.__proto__)  
console.log(Object.prototype)
dog.__proto__ / Dog.prototype


class Person {
    name = "孙悟空";
    age = 18;

    sayHello() {
        console.log("Hello，我是", this.name);
    }
}

// 使用in运算符检查属性时，无论属性在对象自身还是在原型中，都会返回true
console.log("sayHello" in p)

// 对象.hasOwnProperty(属性名) (不推荐使用)，用来检查一个对象的自身是否含有某个属性
console.log(p.hasOwnProperty("sayHello")) //输出：false

// Object.hasOwn(对象, 属性名)（推介的方法），用来检查一个对象的自身是否含有某个属性
 console.log(Object.hasOwn(p, "name"))</code></pre>
 <h4 style="" id="%3E%E6%97%A7%E7%B1%BB">&gt;旧类</h4>
 <ul>
  <li>
   <p style="">一个函数如果直接调用 xxx() 那么这个函数就是一个普通函数</p>
  </li>
  <li>
   <p style="">一个函数如果通过new调用 new xxx() 那么这个函数就是一个构造函数</p>
  </li>
 </ul>
 <pre><code class="language-javascript">/* 
    等价于：
        class Person{

        }
    
*/

var Person = (function () {
    function Person(name, age) {
        // 在构造函数中，this表示新建的对象
        this.name = name
        this.age = age

        // this.sayHello = function(){
        //     console.log(this.name)
        // }
    }

    // 向原型中添加属性（方法）
    Person.prototype.sayHello = function () {
        console.log(this.name)
    }

    // 静态属性
    Person.staticProperty = "xxx"
    // 静态方法
    Person.staticMethod = function () {}

    return Person
})()

const p = new Person("孙悟空", 18)

// console.log(p)


var Animal = (function(){
    function Animal(){

    }

    return Animal
})()


var Cat = (function(){
    function Cat(){

    }

    // 继承Animal
    Cat.prototype = new Animal()

    return Cat
})()

var cat = new Cat()

console.log(cat)</code></pre>
 <h4 style="" id="%3Enew%E8%BF%90%E7%AE%97%E7%AC%A6">&gt;new运算符</h4>
 <ul>
  <li>
   <p style="">new运算符是创建对象时要使用的运算符</p>
  </li>
 </ul>
 <pre><code class="language-javascript">当使用new去调用一个函数时，这个函数将会作为构造函数调用，
使用new调用函数时，将会发生这些事：


function MyClass(){

1. 创建一个普通的JS对象（Object对象 {}）, 为了方便，称其为新对象
    // var newInstance = {}

2. 将构造函数的prototype属性设置为新对象的原型
    // newInstance.__proto__ = MyClass.prototype
}

3. 使用实参来执行构造函数，并且将新对象设置为函数中的this
 var mc = new MyClass()


4. 如果构造函数返回的是一个非原始值，则该值会作为new运算的返回值返回（千万不要这么做）
   如果构造函数的返回值是一个原始值或者没有指定返回值，则新的对象将会作为返回值返回
   通常不会为构造函数指定返回值

class Person{

    constructor(){

    }

}

new Person()</code></pre>
 <h4 style="" id="%3E%E6%80%BB%E7%BB%93">&gt;总结</h4>
 <pre><code class="language-html">面向对象本质就是，编写代码时所有的操作都是通过对象来进行的。

    面向对象的编程的步骤：
        1. 找对象
        2. 搞对象
    
    学习对象：
        1. 明确这个对象代表什么，有什么用    
        2. 如何获取到这个对象
        3. 如何使用这个对象（对象中的属性和方法）

    对象的分类：
        内建对象
            - 由ES标准所定义的对象
            - 比如 Object Function String Number ....

        宿主对象
            - 由浏览器提供的对象
            - BOM、DOM

        自定义对象
            - 由开发人员自己创建的对象</code></pre>
</blockquote>
<p style=""></p>]]></description><guid isPermaLink="false">/2024/JavaScript-3</guid><dc:creator>無.Flac</dc:creator><enclosure url="https://w-flac.org.cn/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=%2Fupload%2Fbanner-%E5%89%8D%E7%AB%AF-fyjy.png&amp;size=m" type="image/jpeg" length="26871"/><category>JavaScript</category><pubDate>Tue, 17 Dec 2024 08:15:00 GMT</pubDate></item></channel></rss>