01-前端三剑客

前端三剑客

文章目录

一:学前端前需要了解的

1:C/S架构和B/S架构

C/S架构就是"需要安装的,偶尔更新的,不跨平台"的软件,例如哔哩哔哩,英雄联盟等等,C/S架构安全性高

B/S架构就是网页,"无需安装,无需更新,可跨平台",前端开发主要写的是C/S架构

2:浏览器内核

内核名称 主要使用浏览器 渲染引擎 JS引擎 市场份额 特点
Blink Chrome Edge(新版) Opera Brave Blink V8 ~70% 性能最强 DevTools完善 PWA支持好
WebKit Safari iOS所有浏览器 macOS Safari WebCore JavaScriptCore(Nitro) ~18% 移动端优化好 系统级集成 隐私保护强
Gecko Firefox Tor Browser Gecko (含WebRender) SpiderMonkey ~4% 开源独立 隐私最强 CSS Grid调试工具好
Trident IE 6-11(已淘汰) 旧版360/QQ浏览器 Trident Chakra(旧) <1% 兼容模式需要 已停止维护
EdgeHTML Edge(2015-2019) EdgeHTML ChakraCore 已废弃 微软过渡产品 已转向Blink

前端后续开发需要关注的是:

内核 CSS前缀 JS API差异 调试工具 兼容性处理
Blink/Chrome -webkit-(部分) 新API最先支持 Chrome DevTools 测试最新特性
WebKit/Safari -webkit-(多) iOS限制多(如PWA) Safari Web Inspector iOS真机测试必须
Gecko/Firefox -moz-(少) 某些API实现不同 Firefox DevTools CSS Grid调试最佳
Trident/IE -ms-(旧) ES6+不支持 IE F12工具(差) 需要polyfill

主攻Chrome(Blink),必测Safari(WebKit),了解Firefox(Gecko),放弃IE(Trident)。

注意这里,在css3布局中,这些css前缀很有用

🚀网页的构成 - 结构(HTML)+ 表现(CSS)+ 行为(JS)

二:HTML

b站相关视频

1:标签和标签属性

HTML标签分为单标签和双标签,标签名称不区分大小写,但是最好小写,规范,标签可嵌套

标签属性用于给标签提供附加信息。可以写在起始标签或者单标签中

有些特殊的属性,没有属性名称,只有属性的值(例如disabled)

网页的构造 - HTML标准结构

html 复制代码
<!-- 这是一个文档说明 -->
<!DOCTYPE html>
<html lang="zh-CN"> <!-- 指定当前的页面是一个简体中文界面 -->
    <!-- head标签中的内容不会出现在网页中 -->
    <!-- head标签中的title标签可以指定网页的标题 -->
    <head>
        <title>...</title>
    </head>
    
    <!-- 想要呈现在网页中的内容写在body标签中 -->
    <body>
        ....
    </body>
</html>

网页中的源代码查看

点击鼠标右键,选择"检查"或者"查看源代码"

  • 【查看网页源代码】看到的是:程序员编写的源代码。
  • 【检查】看到的是:经过浏览器"处理"后的源代码。

2:各个常用标签(⭐️⭐️⭐️⭐️⭐️)

所有标签在这里

但是没必要都学会,这些常用的会了就可以了

标签默认的效果不重要,语义化最重要!!!,就是这个标签设计出来是干啥的最重要,效果由css控制调整

标签分为块级标签和行内标签:

  • 块级标签:独占一行,排版标签都是块级标签,块级元素中能写行内元素和块级元素

  • 行内标签:不独占一行,例如(input, span),行内元素中只能写行内元素

  • 行内块元素:行内元素的一种,不换行但可设宽高 基线对齐

类型 特点 是否可设宽高 是否独占一行
块级元素 默认100%宽度 独占一行
行内元素 宽度由内容决定 不换行
行内块元素 不换行但可设宽高 基线对齐
替换元素 内容可被替换 有内在尺寸
表格元素 特殊布局模型 ✅/❌
2.1:块级元素(block)

口诀 - "分节标题列表单,表格表单结构全"

  • 分:div ⭐⭐⭐⭐⭐
  • 节:section/article/aside/nav
  • 标题:h1-h6 ⭐⭐⭐⭐⭐
  • 列表:ul/ol/li/dl ⭐⭐⭐⭐⭐
  • 表单:form ⭐⭐⭐⭐⭐
  • 表格:table/tr/td ⭐⭐⭐⭐⭐
  • 结构:header/footer/main
标签 语义 单双标签 常用属性 说明
<div> 无语义容器 双标签 class, id, style 最常用布局容器
<p> 段落 双标签 class, id, style 文本段落
<h1> ~ <h6> 标题(1-6级) 双标签 class, id, style 标题标签,h1最重要
<ul> 无序列表 双标签 class, id, style 列表容器
<ol> 有序列表 双标签 type, start, reversed 带序号列表
<li> 列表项 双标签 value, type 必须放在ul/ol内
<table> 表格 双标签 border, cellpadding, cellspacing 表格容器
<tr> 表格行 双标签 - 表格中的行
<th> 表头单元格 双标签 colspan, rowspan 表格头部单元格
<td> 表格数据单元格 双标签 colspan, rowspan 表格数据单元格
<form> 表单 双标签 action, method, target 表单容器
<header> 页面/区块头部 双标签 class, id HTML5语义标签
<footer> 页面/区块尾部 双标签 class, id HTML5语义标签
<nav> 导航 双标签 class, id HTML5语义标签
2.2:行内元素(inline)

口诀 - "文本修饰链媒体,代码引用注音义"

  • 文本:span ⭐⭐⭐⭐⭐
  • 修饰:em/strong/i/b/u
  • 链:a(实际上是inline)⭐⭐⭐⭐⭐
  • 媒体:img(特殊)⭐⭐⭐⭐⭐
  • 代码:code/kbd/samp
  • 引用:q/cite
  • 注音:ruby/rt
标签 语义 单双标签 常用属性 说明
<span> 无语义容器 双标签 class, id, style 最常用的行内容器
<a> 链接 单标签 href, style 链接跳转标签
2.3:行内块元素(inline-block)

口诀 - "表单控件多媒体,按钮输入选择器"

  • 表单控件:input全系列 ⭐⭐⭐⭐⭐
  • 按钮:button ⭐⭐⭐⭐⭐
  • 输入:textarea ⭐⭐⭐⭐⭐
  • 选择:select/option ⭐⭐⭐⭐⭐
  • 媒体:img/video/audio/canvas ⭐⭐⭐⭐⭐
标签 语义 单双标签 常用属性 说明
<img> 图像 单标签 src, alt, width, height 行内替换元素
<input> 输入控件 单标签 type, name, value, placeholder 类型多样,都是inline-block
<button> 按钮 双标签 type, disabled, name 可包含文本或HTML
<textarea> 多行文本输入 双标签 rows, cols, placeholder 多行文本框
<select> 下拉选择 双标签 name, multiple, size 下拉列表
<option> 下拉选项 双标签 value, selected, disabled select的子元素
<label> 表单标签 双标签 for 关联表单控件
<progress> 进度条 双标签 value, max HTML5进度指示器
<video> 视频 双标签 src, controls, width, height HTML5视频播放器
<audio> 音频 双标签 src, controls HTML5音频播放器
<iframe> 内联框架 双标签 src, width, height 嵌入其他页面
2.4:表格元素(table)
标签 语义 块级/行内 默认样式 特殊作用
<table> 表格容器 块级 无特殊 整个表格的根元素
<thead> 表头区域 块级 通常加粗居中 语义化表头,打印时每页重复
<tbody> 表格主体 块级 正常文本 主要数据区域,可以有多个
<tfoot> 表尾区域 块级 可能加粗 汇总行,打印时每页底部重复
<tr> 表格行 块级 水平排列单元格 组织水平方向的数据
<th> 表头单元格 表格单元格 加粗、居中 列或行的标题,有scope属性
<td> 表格数据单元格 表格单元格 正常左对齐 实际数据单元格
复制代码
<table> (表格容器)
├── <caption> (表格标题 - 可选)
├── <colgroup> (列分组 - 可选)
├── <thead> (表头区域 - 语义化)
│   └── <tr> (表头行)
│       ├── <th> (标题单元格1)
│       ├── <th> (标题单元格2)
│       └── <th> (标题单元格3)
├── <tbody> (表格主体 - 可以有多个)
│   ├── <tr> (数据行1)
│   │   ├── <td> (数据单元格1)
│   │   ├── <td> (数据单元格2)
│   │   └── <td> (数据单元格3)
│   └── <tr> (数据行2)
│       ├── <td> (数据单元格4)
│       ├── <td> (数据单元格5)
│       └── <td> (数据单元格6)
└── <tfoot> (表尾区域 - 可选)
    └── <tr> (汇总行)
        ├── <td> (汇总数据1)
        ├── <td> (汇总数据2)
        └── <td> (汇总数据3)
2.5:交互和媒体(media)
标签 语义 单双标签 常用属性 说明
<details> 细节控件 双标签 open 可展开/折叠的内容
<summary> details标题 双标签 - details的可见标题
<dialog> 对话框 双标签 open HTML5对话框
<menu> 菜单列表 双标签 type 命令菜单
<menuitem> 菜单项 单标签 type, label menu的命令项

3:常用标签的特殊说明

标签 必须属性 推荐属性 禁止/避免 特殊说明
<img> src, alt width, height, loading 无alt alt即使为空也要写
<a> href(内部锚点可空) target="_blank"时加rel href="javascript:..." 外部链接要安全
<input> type, name(表单时) id, placeholder 无label radio/checkbox需分组
<form> - method, action, enctype 无提交按钮 文件上传需enctype
<table> - scope(th用) 用表格布局 要有caption或aria-label
<label> for或包裹控件 - 无关联控件 提升可访问性
<button> type disabled, aria-label 无type type默认submit(表单内)
<meta> charsetname+content viewport - 移动端必须viewport
<iframe> title sandbox, allow 无title 安全考虑加sandbox
<video> - controls, preload 无后备内容 提供多个source格式
<textarea> name rows, cols, maxlength - 用CSS控制大小更佳
<select> name multiple, size 无option 选项用<option>
<option> value selected, disabled - 显示文本在标签间

4:HTML其他说明

4.1:字符实体

所谓字符实体就是用一个形式表示某种符号,HTML认这种符号。

字符实体由三部分组成:一个&和一个实体名称(或者一个#和一个实体编号),最后加上一个分号;

可以看这里

4.2:全局属性

常见的全局属性(大部分的标签都可以写的属性叫做全局属性)

属性 描述
id 为元素指定唯一标识符。
class 为元素指定一个或多个类名(用空格分隔)。
style 为元素指定行内CSS样式。
title 提供元素的额外提示信息(鼠标悬停时显示)。
lang 定义元素内容的语言代码(如 enzh-CN)。
dir 设置文本方向:ltr(从左到右)或 rtl(从右到左)。
hidden 隐藏元素(布尔属性,无需值)。

可访问性和交互

属性 描述
tabindex 控制Tab键导航顺序(0为自然顺序,-1为可聚焦但不可通过Tab导航)。
accesskey 为元素指定键盘快捷键(如 accesskey="s")。
contenteditable 允许用户编辑元素内容(布尔属性)。
spellcheck 启用拼写检查(true/false)。
draggable 控制元素是否可拖放(true/false)。
role 定义元素的ARIA角色(增强可访问性)。
aria-* ARIA属性,用于描述元素的无障碍信息(如 aria-label)。
4.3:meta元信息
html 复制代码
<!-- 配置字符编码 -->
<meta charset="utf-8">

<!-- 针对IE浏览器的兼容性配置(IE8+ 尝试使用 Edge内核渲染) -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- 针对移动端的配置 -->
<meta name="viewport"content="width=device-width,initial-scale=1.0">

<!-- 配置网页关键字 -->
<meta name="keywords" content="8-12个以英文逗号隔开的单词/词语">

<!-- 配置网页的描述信息 -->
<meta name="description" content="80字以内的一段话,与网站内容相关">

<!-- 针对搜索引擎爬虫配置, robots协议 -->
<meta name="robots" content="?">

<!-- 配置网页作者 -->
<meta name="author" content="tony">

<!-- 配置网页生成工具 -->
<meta name="generator" content="Visual Studio Code">

<!-- 配置网页版权信息 -->
<meta name="copyright" content="2023-2027©版权所有">

<!-- 配置网页自动刷新 -->
<!-- 10s钟后去哪? 如果后面不配置网址,将会原地刷新 -->
<meta http-equiv="refresh" content="10;url=http://www.baidu.com">

所以项目中,html的header一般是这样的...

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <!-- 字符编码(必须放在最前面) -->
        <meta charset="UTF-8">
        <!-- 视口设置(响应式必备) -->
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <!-- 浏览器兼容性 -->
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <!-- 页面标题 -->
        <title>页面标题 | 公司/品牌名</title>
        <!-- 页面描述(SEO重要) -->
        <meta name="description" content="150-160字符的页面描述">
        <!-- 引入CSS -->
        <link rel="stylesheet" href="styles/main.css">
        <!-- 网站图标 -->
        <link rel="icon" href="/favicon.ico" type="image/x-icon">
        <link rel="apple-touch-icon" href="/apple-touch-icon.png">
    </head>

    <body>
    	...
    </body>

</html>
4.4:父、子、祖先、后代、兄弟

其实就是族谱树的概念延伸...

父元素:直接包裹某一个元素的元素,就是该元素的父元素

子元素:被父元素直接包含的元素叫做子元素

html 复制代码
<!-- div是h1和ul的父元素,不是li的父元素 -->
<!-- ul是li的父元素 -->

<!-- 反过来同理 -->

<!-- h1和ul是div的子元素,li不是div的子元素 -->
<!-- li是ul的子元素 -->
<div>
    <h1>你好,这里是前端三剑客</h1>
    <ul>
        <li>html</li>
        <li>css</li>
        <li>javascript</li>
    </ul>
</div>

祖先元素:父亲的父亲...,一直往外找,都是祖先,父元素也是祖先的一种,但是一般还是称呼为父元素

后代元素:儿子的儿子...,一直往里找,都是后代,子元素也是后代的一种,但是一般还是称呼为子元素

兄弟元素,具有相同父元素的元素,互为兄弟元素

html 复制代码
<!-- div就是li的祖先,li就是div的后代 -->
<!-- h1和ul是兄弟元素,因为他们有相同的父元素div, 这几个li是兄弟元素,因为他们有相同的父元素ul -->
<div>
    <h1>你好,这里是前端三剑客</h1>
    <ul>
        <li>html</li>
        <li>css</li>
        <li>javascript</li>
    </ul>
</div>

三:CSS

1:CSS的编写位置

优先级规则:行内样式 > 内部样式 = 外部样式

行内样式

  • style属性的值不能随便写,写要符合CSS语法规范,是key:value;的形式。
  • 行内样式表,只能控制当前标签的样式,对其他标签无效。

不推荐大量使用,只有对当前元素添加简单样式时,才偶尔使用。

html 复制代码
<body>
    <h1 style="color: rebeccapurple; font-size: 99px;"></h1>
</body>

内部样式

写在html页面内部,将所有的CSS代码提取出来,单独放在<style>标签中

只有当前文件能用,一般放在header中

html 复制代码
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!-- 内部样式,控制当前页面的指定选择器的样式信息 -->
    <style>
        h1 {
            color: rebeccapurple;
            font-size: 40px;
        }
    </style>
</head>

外部样式

写在单独.css文件中,随后在HTML文件中引入使用。

link必须在header中,rel指定的是引入的文档与当前文档之间的关系,都写stylesheet, href是文件相对位置

实际开发中,几乎都使用外部样式,这是最推荐的使用方式!

html 复制代码
<head>
    <!-- 字符编码(必须放在最前面) -->
    <meta charset="UTF-8">
    <!-- 引入CSS -->
    <link rel="stylesheet" href="styles/main.css">
    <!-- 网站图标 -->
    <link rel="icon" href="/favicon.ico" type="image/x-icon">
    <link rel="apple-touch-icon" href="/apple-touch-icon.png">
</head>

2:CSS选择器(⭐️⭐️⭐️⭐️⭐️)

CSS语法由两部分构成:

  • 选择器:找到要添加样式的元素。
  • 声明块:设置具体的样式(声明块是由一个或多个声明组成的),声明的格式为:属性名:属性值;

所以成功给指定元素渲染样式,选择器的指定至关重要

2.1:通配选择器(*)

就是*, 可以匹配所有的HTML元素

看似鸡肋,但是在清除样式的时候,会有很大帮助

2.2:元素选择器(元素名)

无法实现差异化设置,只能对一类元素统一设置样式

css 复制代码
标签名 {
    属性名:属性值;
    属性名:属性值;
}

/* 选中所有的p元素,设置其颜色是blue, 设置其字体大小是16px */
p {
    color: blue;
    font-size: 16px;
}
2.3:类选择器(.class的值)

根据元素的class值,来选中某些元素,class就是我们给元素规定的特征

一个html标签中不可有多个class声明,但一个class属性中可以由多个值

html 复制代码
<!--该写法错误,元素的属性不能重复,后写的会失效-->
<h1 class="speak" class="big">你好啊</h1>

<!--该写法正确,class属性,能写多个值-->
<h1 class="speak big">你好啊</h1>
css 复制代码
.[class的值] {
    属性名:属性值;
    属性名:属性值;
}

/* 选中所有class值为speak的元素 */
.speak {
	color: red;
}

/* 选中所有class值为answer的元素 */
.answer {
	color: blue;
}
2.4:ID选择器(#id值)
  • 一个元素只能拥有一个id属性,多个元素的id属性值不能相同(双唯一性)
  • 一个元素可以同时拥有id和class属性。
css 复制代码
#ID值 {
	属性名:属性值;
    属性名:属性值;
}

/* 选中id值为earthy的那个元素 */
#earthy {
    color: red;
    font-size: 60px;
}
2.5:交集选择器(选择器1选择器2)

选中同时符合多个条件的元素,就是选择器和选择器之间是并且的关系

  • 有标签名,标签名必须写在前面。
  • id选择器、理论上可以作为交集的条件,但实际应用中几乎不用。因为没有意义。
  • 交集选择器中不可能出现两个元素选择器,因为一个元素,不可能即是p元素又是 span 元素。
  • 用的最多的交集选择器是:元素选择器配合类名选择器,例如:p.beauty
css 复制代码
选择器1选择器2选择器n {
    属性名:属性值;
    属性名:属性值;
}

/* 选中:类名为beauty的p元素,为此种写法用的非常多!!!!*/
p.beauty {
	color: blue;
}
/* 选中:类名包含rich和beauty的元素 */
.rich.beauty {
	color: green,
}
2.6:并集选择器(选择器1, 选择器2)

选中多个选择器对应的元素,满足选择器之一就可以,又叫分组选择器

  • 并集选择器,我们一般竖着写。逗号可以理解成或者

  • 任何形式的选择器,都可以作为并集选择器的一部分。

  • 并集选择器,通常用于集体声明,可以缩小样式表体积。

css 复制代码
选择器1, 选择器2, 选择器n {
    属性名:属性值;
    属性名:属性值;
}

/* 选中id为peiqi,或类名为rich,或类名为beauty的元素 */
#peiqi,
.rich,
.beauty {
    font-size: 40px;
    background-color: skyblue;
    width: 200px;
}
2.7:后代选择器(选择器1 选择器2)

选中指定元素中,符合要求的后代元素(儿子也算后代),只会改变最内一层(选中层)的样式

  • 选择器之间,用空格隔开,空格可以理解为:"xxx中的",其实就是后代的意思。
css 复制代码
选择器1 选择器2 选择器3 ... 选择器n {
    属性名:属性值;
    属性名:属性值;
}

/* 选中ul中的所有li,注意不会改变ul的样式 */
ul li{
    color:red;
}

/* 选中ul 中所有 li中的 a */
ul li a {
    color:orange;
}

/* 选中类名为subject(class=subject)元素中的所有li */
.subject li {
    color:blue;
}

/* 选中类名为subject元素中的所有类名为front-end的li */
.subject li.front-end {
    color:blue;
}
2.7:子选择器(父 > 子)

选中指定元素中,符合要求的子元素(儿子元素)。(先写父,再写子)

选择器之间,用>隔开,>可以理解为:"xxx 的子代",其实就是儿子的意思。

2.8:兄弟选择器(兄长+/~兄弟)

⚠️ 只能选到后面的兄弟,前面的选不到

相邻兄弟选择器 -> 相邻兄弟选择器(+)选择的是前一个元素后面紧接着的兄弟元素

css 复制代码
前一个元素 + 紧接着的兄弟元素 {
  属性: 值;
  /* 更多样式属性 */
}

通用兄弟选择器 -> 通用兄弟选择器(~)选择的是前一个元素后面所有的兄弟元素

css 复制代码
前一个元素 ~ 兄弟元素 {
  属性: 值;
  /* 更多样式属性 */
}
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
      /* + 兄弟元素, 在h2后面的第一个p标签都执行这个样式,也就是第一段 */
      div.container > h2 + p {
        color: red;
      }

      /* ~ 兄弟元素, 在class=inner的div后面的兄弟p标签都执行这个样式,也就是第二段和第三段 */
      div.inner ~ p {
        color: blue;
        margin-left: 20px;
      }
    </style>
</head>
<body>
  <div class="container">
    <h2>标题</h2>
    <p>第一段</p>
    <div class="inner">一个div</div>
    <p>第二段</p>
    <p>第三段</p>
  </div>
</body>
</html>
2.9:属性选择器([属性名])

分为考虑属性的值和不考虑属性的值,用[]包裹

  • [属性名] 选中具有某个属性的元素。
  • [属性名 = "值"] 包含某个属性,且属性值等于指定值的元素。
  • [属性名 ^= "值"] 选中包含某个属性,且属性值以指定的值开头的元素。
  • [属性名 $= "值"] 选中包含某个属性,且属性值以指定的值结尾的元素。
  • [属性名 *= "值"] 选择包含某个属性,属性值包含指定值的元素。
css 复制代码
/* 不考虑属性的值 */
[attr] {
  /* 属性名attr的样式 */
}

/*考虑属性值*/
/* 选择所有具有 "attr" 属性且值为 "value" 的元素 */
[attr="value"] {
  color: red;
}

/* 选择所有具有 "attr" 属性且值以 "value" 开头的元素 */
[attr^="value"] {
  color: green;
}

/* 选择所有具有 "attr" 属性且值以 "value" 结尾的元素 */
[attr$="value"] {
  color: orange;
}

/* 选择所有具有 "attr" 属性且值包含 "value" 的元素 */
[attr*="value"] {
  color: purple;
}
2.10:伪选择器

伪选择器分为伪类选择器伪元素选择器,下面这两个视频讲的很好:

渡一,语速有点快,但是讲的还行

木折,快速学习

注意最常用的四个伪类选择器的放置顺序LVHA -> :link :visited :hover :active

2.11:选择器的优先级

原则:越是能够精确定位元素的,优先级越高

  1. !important:无需多言,打遍天下无敌手,但是不要乱用
  2. 内联样式style
  3. id选择器
  4. 伪类选择器
  5. 属性选择器 = class选择器
  6. 元素选择器
  7. 通配选择器:非常低,因为不能够定位元素,通用配置
  8. 继承属性...CSS三大特性之一

相同的选择器,后面声明的比前面声明的优先级高,相同属性后者覆盖前者;

在VS Code或者WebStorm中,可以通过特异性查看优先级:

特异性用于判断多个 CSS 规则应用于同一个元素时,哪个规则的样式应该生效。

特异性越高,优先级越高。

特异性值是一个四元组 (a, b, c, d),但在大多数情况下,a 值通常为 0,因此通常只显示 (b, c, d)。

  • a:内联样式。直接在 HTML 元素的 style 属性中定义的样式。
  • b:ID 选择器(#id)。使用 #id 选择器。
  • c:类选择器(.class_name)、属性选择器([alt])和伪类选择器(s1:xxx)
  • d:元素选择器(tag_name)和伪元素选择器(s1::xxx)。使用 div、p::before 等选择器。

所以上面的(1, 1, 0)表示有ID选择器,有类选择器,可以说优先级非常的高了

3:CSS三大特性

层叠性,继承性和优先级

特性 核心思想 比喻
层叠性 冲突时如何解决 多人指挥时听谁的
继承性 样式自动传递 家族特征传承
优先级 权重决定胜负 身份证比学生证权威
3.1:层叠性

当多个 CSS 规则作用于同一个元素时,会根据一定的规则进行"层叠",最终确定使用哪个样式

层叠规则(按顺序判断):

  1. 来源顺序:相同权重的规则,后出现的覆盖先出现的(就近原则)
  2. 优先级:不同权重的规则,优先级高的生效(详见下文优先级部分)
  3. 重要性:!important 声明具有最高优先级
css 复制代码
/* 示例:层叠性 */
p {
  color: blue;
}

/* 后定义的相同选择器会覆盖前一个 */
p {
  color: red; /* 最终生效 */
}
3.2:继承性

某些 CSS 属性会被子元素自动继承,无需重复定义。

就像现实生活中的遗传一样,孩子自动获得父母的某些特征,但不是全部特征!

可以继承的属性一般都是文本相关的属性:font-family, color, line-height, text-align...

不可继承的属性一般都是布局和盒模型相关的属性:width, height, margin, padding, border...

使用inherit可以强制继承

css 复制代码
/* 场景1:统一网站字体 */
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto;
  /* 所有子元素都自动用这个字体,不用重复写 */
}

/* 场景2:深色模式文字颜色 */
body.dark-mode {
  color: #f0f0f0;  /* 一次设置,全局生效 */
}

/* 场景3:统一链接颜色 */
article {
  color: #333;
}

article a {
  color: inherit;  /* 继承 article 的灰色,而不是默认蓝色 */
  text-decoration: underline;
}
3.3:优先级

就是上面说的选择器的优先级,当多个选择器作用于同一元素时,通过权重计算决定哪个规则生效。

css 复制代码
/* 示例:优先级比较 */
#content p.text {      /* 权重: 0,1,0,1 (ID + 元素) */
  color: blue;
}

div#content p {        /* 权重: 0,1,0,2 (ID + 两个元素) */
  color: green;        /* 生效:0,1,0,2 > 0,1,0,1 */
}

p {                    /* 权重: 0,0,0,1 */
  color: red !important; /* !important 优先级最高 */
}

4:CSS中的颜色和长度

4.1:颜色
4.1.1:颜色标准名

CSS 定义了一系列标准的颜色名,可以直接在 CSS 代码中使用。这些颜色名是预定义的,不需要额外的解释或转换

直接参考网址:https://developer.mozilla.org/en-US/docs/Web/CSS/named-color

4.1.2:HEX,RGB,RGBA,HEXA

RGB代表"红-绿-蓝"(Red-Green-Blue),它是一种加色模型,通过混合不同强度的红色、绿色和蓝色光来创建各种颜色

在RGB模型中,每个颜色通道的值范围从0到255,其中0表示该颜色通道没有光(即最暗),255表示该颜色通道的光是最亮的

RGBA是在RGB的基础上增加了一个Alpha通道,代表"红-绿-蓝-Alpha"。Alpha通道用于控制颜色的透明度

Alpha取值范围是0.0到1.0,其中0.0表示完全透明,1.0表示完全不透明

十六进制法(HEX)和RGB同理。只不过是十六进制的,HEXA和RGBA同理。

css 复制代码
color: red;                    /* 颜色名 */
color: #FF0000;                /* 十六进制 */
color: rgb(255, 0, 0);         /* RGB */
color: rgba(255, 0, 0, 0.5);   /* RGB + 透明度 Alpha */
color: #FF000080;              /* 8位十六进制(带透明度) */
4.1.3:HSL,HSLA

HSL是一种将RGB色彩模型中的点在圆柱坐标系中的表示法。

https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl#specifications

这两种表示法试图做到比基于笛卡尔坐标系的几何结构RGB更加直观。是运用最广的颜色系统之一。

HSL 代表色调(Hue)、饱和度(Saturation)和亮度(Lightness)。

HSL 颜色模型是圆柱坐标中的一个圆锥形色彩空间,它将颜色描述为三个维度:hsl(H, S%, L%)

  • H(色调,Hue):色调是色彩的基本属性,它决定了颜色的种类,比如红色、黄色或蓝色。在 HSL 中,色调用角度来表示,范围是 0° 到 360°。其中,0° 或 360° 表示红色,120° 表示绿色,240° 表示蓝色
  • S(饱和度,Saturation):饱和度是指颜色的纯度,它描述了颜色中灰色成分的多少。饱和度的范围是 0% 到 100%,其中 0% 表示灰色(没有颜色),100% 表示完全饱和的颜色
  • L(亮度,Lightness):亮度描述了颜色的明亮程度。亮度的范围也是 0% 到 100%,其中 0% 表示黑色,50% 表示正常亮度,100% 表示白色

HSLA 是 HSL 的扩展,增加了 Alpha 通道,用于表示颜色的透明度。A介于0.0~1.0

css 复制代码
/* 语法:hsl(色相, 饱和度, 明度) */
.element {
  color: hsl(0, 100%, 50%);     /* 纯红色 */
  color: hsl(120, 100%, 50%);   /* 纯绿色 */
  color: hsl(240, 100%, 50%);   /* 纯蓝色 */
}

/* 
  色相(Hue):0-360度色轮(0红,120绿,240蓝)
  饱和度(Saturation):0%-100%(0%灰色,100%纯色)
  明度(Lightness):0%-100%(0%黑,50%正常,100%白)
*/
4.1.4:currentColor关键字

该关键字用来表示引用当前元素的 color 值

css 复制代码
/* 引用当前元素的 color 值 */
.element {
  color: #3498db;
  border: 2px solid currentColor;  /* 边框使用文字颜色 */
  box-shadow: 0 0 10px currentColor;
}
4.2:长度

像素是相对单位,就是电脑屏幕的小正方形分割,像素越高的情况下,越清晰

单位 说明
像素px 基于屏幕分辨率的固定单位,通常用于网页设计
百分比% 相对于父元素的百分比,常用于响应式设计
em 相对于当前元素的字体大小。如果当前元素的字体大小是16px,那么1em等于16px

CSS3新增了许多长度单位,这些单位提供了更多的灵活性和精确性,适用于不同的布局需求

单位 说明
rem rem是相对于根元素(通常是<html>)的字体大小。假设根元素的字体大小为16px,则1rem等于16px
vw vw是视口宽度的百分比。1vw等于视口宽度的1%
vh vh是视口高度的百分比。1vh等于视口高度的1%
vmin vmin是视口宽度和高度中较小值的百分比。1vmin等于视口较小尺寸的1%
vmax (viewport maximum) vmax是视口宽度和高度中较大值的百分比。1vmax等于视口较大尺寸的1%
4.2.1:绝对单位

像素和物理单位

css 复制代码
/* 像素(最常用) */
.element { width: 100px; }

/* 物理单位(打印时使用) */
.element {
  width: 2.54cm;    /* 厘米 */
  width: 25.4mm;    /* 毫米 */
  width: 1in;       /* 英寸 = 2.54cm */
  width: 72pt;      /* 点 = 1/72英寸 */
  width: 6pc;       /* 派卡 = 12点 */
}
4.2.2:相对单位 - 响应式

相对于字体的大小

css 复制代码
/* em:相对于当前元素的字体大小 */
.container {
  font-size: 16px;
  padding: 2em;     /* 2em = 2倍当前字体的大小 = 32px (16 × 2) */
}

.inner {
  font-size: 0.8em;  /* 相对于父元素的0.8倍字体大小 = 16 * 0.8 = 12.8px */
  margin: 1.5em;     /* 相对于自己的字体大小的1.5倍 = 12.8 * 1.5 = 19.2px */
}

/* rem:相对于根元素(html)的字体大小 */
html { font-size: 16px; }

.element {
  font-size: 1rem;     /* 16 * 1 = 16px */
  padding: 2rem;       /* 16 * 2 = 32px */
  margin: 0.5rem;      /* 16 * 0.5 = 8px */
}

/* ex:相对于当前字体的小写x高度 */
/* ch:相对于数字0的宽度 */

相对于视口(Viewport)

css 复制代码
/* vw:视口宽度的1% */
.element {
  width: 50vw;     /* 视口宽度的50% */
}

/* vh:视口高度的1% */
.element {
  height: 100vh;   /* 满屏高度 */
}

/* vmin:vw和vh中较小的那个 */
.element {
  font-size: 5vmin; /* 在手机竖屏时相对于高度 */
}

/* vmax:vw和vh中较大的那个 */
.element {
  font-size: 5vmax; /* 在手机横屏时相对于宽度 */
}
4.2.3:百分比%

是父元素的百分之多少?

css 复制代码
.parent {
  width: 500px;
  height: 300px;
}

.child {
  width: 50%;      /* 250px (父元素宽度的50%) */
  height: 50%;     /* 150px (父元素高度的50%) */
  padding: 10%;    /* 水平方向相对于父元素宽度,垂直方向相对于父元素宽度(注意!) */
}
4.2.4:calc()方法

calc() 是 CSS3 中的计算函数,允许在声明 CSS 属性值时执行数学运算

  • 混合单位计算 :如 px + %rem + vw
  • 四则运算 :支持 + - * /
  • 动态计算:运行时计算,响应视口变化
  • 任何数值属性 :可用在 widthheightmarginfont-size

常用在响应式布局中的平滑过渡

css 复制代码
.container {
  /* 宽度 = 100%视口 - 左右各20px边距 */
  width: calc(100vw - 40px);
  
  /* 高度 = 视口高度 - 头部80px - 底部60px */
  height: calc(100vh - 80px - 60px);
}


/* 字体响应式公式 */
font-size: calc([最小px] + ([最大px] - [最小px]) * ((100vw - [最小视口px]) / ([最大视口px] - [最小视口px])));

/* 示例:在 375px~1440px 视口中,字体从 16px~20px */
font-size: calc(16px + (20 - 16) * ((100vw - 375px) / (1440 - 375)));

5:CSS属性(⭐️⭐️⭐️)

CSS属性繁杂,有现成的网站已经分好类,现去搜查

菜鸟教程 - https://www.runoob.com/cssref/css-reference.html

6:定位和浮动

6.1:盒子模型

每个HTML元素都是一个"盒子",就像快递包裹一样有层层包装:

6.1.1:两种盒子模型

传统盒子模型 - content-box

width指定的是内容区的宽度,然后根据各个部分推算总宽度

css 复制代码
div {
    box-sizing: content-box; /* 默认值 */
    width: 200px;
    padding: 20px;
    border: 5px solid black;
    margin: 10px;
}
复制代码
总宽度 = width + padding左右 + border左右 + margin左右
总高度 = height + padding上下 + border上下 + margin上下

例子计算:
width: 200px
padding: 20px(左右各20,共40px)
border: 5px(左右各5,共10px)
margin: 10px(左右各10,共20px)

实际占用宽度 = 200 + 40 + 10 = 250px(不含margin)
整个盒子占位宽度 = 250 + 20 = 270px(含margin)

边框盒子(现代开发都用这个) - broder-box

width指定的是总宽度,通过padding和broder反推内容区的宽度

css 复制代码
/* 现代开发推荐用这个! */
div {
  box-sizing: border-box; /* ✅ 推荐! */
  width: 200px;
  padding: 20px;
  border: 5px solid black;
}
复制代码
width = 内容区 + padding + border
你设置的width就是最终可视宽度!

例子:
width: 200px(总宽度固定)
padding: 20px(左右各20,占40px)
border: 5px(左右各5,占10px)

内容区宽度自动计算 = 200 - 40 - 10 = 150px
6.1.2:盒子属性
  • padding:内部填充,背景色会显示
  • margin:外部间隔,完全透明
  • border:中间边界,样式丰富
  • box-sizing: border-box:现代开发必用!

尺寸相关属性

属性 作用 常用值 示例
width 设置内容区宽度 长度值、百分比、auto width: 200px;
height 设置内容区高度 长度值、百分比、auto height: 100px;
min-width 最小宽度 长度值、百分比 min-width: 300px;
max-width 最大宽度 长度值、百分比 max-width: 1200px;
min-height 最小高度 长度值、百分比 min-height: 200px;
max-height 最大高度 长度值、百分比 max-height: 500px;

内边距 Padding

值的数量 含义 示例
1个值 四边相同 padding: 20px;
2个值 上下 | 左右 padding: 10px 20px;
3个值 上 | 左右 | 下 padding: 10px 20px 15px;
4个值 上 | 右 | 下 | 左 padding: 10px 15px 20px 25px;
属性 作用 常用值 示例
padding 简写属性(四边) 1-4个长度值 padding: 20px;
padding-top 上内边距 长度值 padding-top: 10px;
padding-right 右内边距 长度值 padding-right: 15px;
padding-bottom 下内边距 长度值 padding-bottom: 10px;
padding-left 左内边距 长度值 padding-left: 15px;

边框 - border

属性 作用 常用值 示例
border 边框简写 宽度 样式 颜色 border: 2px solid red;
border-width 边框宽度 长度值 border-width: 2px;
border-style 边框样式 见下表 border-style: dashed;
border-color 边框颜色 颜色值 border-color: #333;

单边边框属性

属性 作用 示例
border-top 上边框 border-top: 1px solid red;
border-right 右边框 border-right: 2px dashed blue;
border-bottom 下边框 border-bottom: 3px dotted green;
border-left 左边框 border-left: 1px solid #ccc;
border-top-width 上边框宽度 border-top-width: 3px;
border-top-style 上边框样式 border-top-style: solid;
border-top-color 上边框颜色 border-top-color: red;

圆角边框

属性 作用 示例
border-radius 边框圆角 border-radius: 10px;
border-top-left-radius 左上圆角 border-top-left-radius: 5px;
border-top-right-radius 右上圆角 border-top-right-radius: 5px;
border-bottom-right-radius 右下圆角 border-bottom-right-radius: 5px;
border-bottom-left-radius 左下圆角 border-bottom-left-radius: 5px;

外边距 - margin

属性 作用 常用值 示例
margin 简写属性(四边) 1-4个长度值、auto margin: 20px;
margin-top 上外边距 长度值、auto margin-top: 10px;
margin-right 右外边距 长度值、auto margin-right: 15px;
margin-bottom 下外边距 长度值、auto margin-bottom: 20px;
margin-left 左外边距 长度值、auto margin-left: 15px;
值的数量 含义 示例
1个值 四边相同 margin: 20px;
2个值 上下 | 左右 margin: 10px auto;(居中)
3个值 上 | 左右 | 下 margin: 10px 20px 15px;
4个值 上 | 右 | 下 | 左 margin: 10px 15px 20px 25px;

常见样式

css 复制代码
.card {
  box-sizing: border-box;      /* 重要! */
  width: 300px;
  padding: 20px;               /* 内边距 */
  border: 1px solid #ddd;      /* 边框 */
  border-radius: 8px;          /* 圆角 */
  margin: 15px;                /* 外边距 */
  background-color: white;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.button {
  box-sizing: border-box;
  display: inline-block;
  padding: 10px 24px;          /* 上下10px,左右24px */
  border: 2px solid #007bff;
  border-radius: 4px;
  margin: 0 10px 10px 0;       /* 上0 右10 下10 左0 */
  background-color: #007bff;
  color: white;
}

/* 常用全局重置 */
* {
  box-sizing: border-box;      /* 统一盒子模型 */
  margin: 0;                   /* 清除默认外边距 */
  padding: 0;                  /* 清除默认内边距 */
}
6.2:定位position

有五种定位方式

sticky = relative + fixed = 偏移到一定位置之后固定

属性 作用
top right bottom left 定位偏移 长度、百分比
z-index 层叠顺序 整数(可正可负)
clip 裁剪定位元素 rect()
6.3:浮动float

基本被现代布局flexbox和grid替代,只有部分的文字环绕图片还在用

css 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .news {
            float: left;
            width: 800px;
            height: 200px;
            margin: 0 20px 0 20px;
        }
    </style>
</head>
<body>
    <img class="news" src="news.png" alt="新闻图片">
    <p>北京,2025年3月15日电 ------ 今天,深度求索公司正式发布了其人工智能助手DeepSeek的全新功能升级,标志着AI技术在日常生活和工作场景中的应用迈出了重要一步。此次更新不仅在技术层面实现了重大突破,更为用户带来了前所未有的智能体验。
据深度求索公司技术负责人介绍,新版DeepSeek具备更强大的多模态理解和生成能力。系统现在能够更好地理解用户的复杂需求,提供更加精准、个性化的服务。与以往版本相比,此次升级特别优化了在编程辅助、学术研究、创意写作等专业领域的表现,响应速度提升40%,准确率提高25%。
"我们致力于让人工智能技术真正惠及每一个人,"深度求索公司CEO在发布会上表示,"DeepSeek不仅仅是工具,更是用户的智能伙伴。我们相信,技术的价值在于赋能,在于让复杂变得简单,让高效成为可能。"
市场分析人士指出,此次升级正值全球AI技术快速发展期。随着算力成本的下降和算法效率的提升,AI助手正从"新奇科技"转变为"日常必需品"。DeepSeek的更新恰逢其时,有望在教育、办公、创意产业等多个领域发挥更大作用。
值得注意的是,新版DeepSeek特别强调了安全性和隐私保护。系统采用端到端加密技术,确保用户数据安全,并在设计之初就融入了伦理考量,避免可能产生的偏见和误导。公司表示,他们建立了一套完整的内容审核和安全机制,确保AI助手的输出既智能又可靠。
用户体验方面,DeepSeek新增了多项实用功能。用户现在可以通过自然对话的方式完成复杂任务规划、数据分析甚至创意构思。测试用户反馈显示,新版本在理解上下文、保持对话连贯性方面表现突出,大大提升了使用效率。
业内专家认为,DeepSeek的此次升级不仅是技术的进步,更是AI应用理念的革新。它展现了人工智能从"执行命令"到"理解意图"的转变,预示着人机交互将更加自然、更加智能。
随着人工智能技术的不断成熟,我们有理由相信,像DeepSeek这样的智能助手将在未来扮演越来越重要的角色,为社会发展注入新的动能,为人们的生活和工作带来更多可能性。
深度求索公司表示,他们将继续投入研发,推动AI技术向更智能、更安全、更普惠的方向发展,让科技创新真正服务于人类的美好生活。</p>
</body>
</html>

float有一个经典的问题就是:父元素高度塌陷!!,

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .outer {
            border: 2px solid red;
        }
        .float_inner {
            float: left;
            height: 100px;
        }
    </style>
</head>
<body>
    <!-- 红框盒子高度变成0了!(因为子元素浮起来了,不占位置) -->
    <div class="outer">
        <div class="float_inner">
            我浮起来了!
        </div>
    </div>
</body>
</html>

解决方案一:塌陷的父盒子加上撑杆

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .outer {
            border: 2px solid red;
        }
        /* 方式一:在后面加个"撑杆"
           使用伪元素::after作用在父元素, 使用clear: both清除两边浮动 
        */
        .outer::after {
            content: "";
            display: block;
            clear: both; /* 清除两边浮动 */
        }
        .float_inner {
            float: left;
            height: 100px;
        }
    </style>
</head>
<body>
    <!-- 红框盒子高度变成0了!(因为子元素浮起来了,不占位置) -->
    <div class="outer">
        <div class="float_inner">
            我浮起来了!
        </div>
    </div>
</body>
</html>

方式二:塌陷的父盒子变成不漏的容器

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .outer {
            border: 2px solid red;
            /* 方式二:让父类变成不漏的容器 */
            display: flow-root;
        }
        .float_inner {
            float: left;
            height: 100px;
        }
    </style>
</head>
<body>
    <!-- 红框盒子高度变成0了!(因为子元素浮起来了,不占位置) -->
    <div class="outer">
        <div class="float_inner">
            我浮起来了!
        </div>
    </div>
</body>
</html>

7:布局(⭐️⭐️⭐️⭐️⭐️⭐️)

7.1:弹性盒子flexbox(⭐️⭐️⭐️⭐️⭐️⭐️)

flex布局是CSS经典布局,可以通过简单的一行设置就可以对指定容器开启flex布局

css 复制代码
/* 告诉浏览器:"我要用Flex布局了!" */
.container {
  display: flex; 
}
7.1.1:flex容器和项目

flex布局中,有两个重要角色

flex容器

可以理解成"父母",管理整个容器的整体布局

css 复制代码
/* 父母管整体布局 */
.container {
  display: flex;          /* 激活Flex */
  flex-direction: row;    /* 排列方向 */
  justify-content: center; /* 水平对齐 */
  align-items: center;    /* 垂直对齐 */
}

flex项目

可以理解成为"孩子",管理自己的大小

css 复制代码
/* 孩子管自己的大小 */
.item {
  flex: 1;                /* 自动分配空间 */
  align-self: center;     /* 自己单独对齐 */
}
7.1.2:flex容器的六大权力

flex-direction -> 排列方向的选择 -> 横着摆还是竖着摆

css 复制代码
.container {
  /* 四个方向可选 */
  flex-direction: row;            /* → 默认:水平排列 */
  flex-direction: row-reverse;    /* ← 水平反方向 */
  flex-direction: column;         /* ↓ 垂直排列 */
  flex-direction: column-reverse; /* ↑ 垂直反方向 */
}

justify-content -> 主轴方向对齐策略

css 复制代码
.container {
    /* 水平对齐(如果flex-direction: row) */
    justify-content: flex-start;    /* ← 靠左 */
    justify-content: flex-end;      /* → 靠右 */
    justify-content: center;        /* 中间 */
    justify-content: space-between; /* 两端对齐,中间平均 */
    justify-content: space-around;  /* 四周有间隔 */
    justify-content: space-evenly;  /* 完全平均 */
}

align-items -> 交叉轴方向对齐策略

css 复制代码
.container {
    /* 垂直对齐(如果flex-direction: row) */
    align-items: stretch;     /* 默认:拉伸填满 */
    align-items: flex-start;  /* ↑ 顶部对齐 */
    align-items: flex-end;    /* ↓ 底部对齐 */
    align-items: center;      /* 垂直居中 */
    align-items: baseline;    /* 文字基线对齐 */
}

flex-wrap -> 是否换行

css 复制代码
.container {
    flex-wrap: nowrap;    /* 默认:不换行,挤在一起 */
    flex-wrap: wrap;      /* 换行:像书架放不下换下一层 */
    flex-wrap: wrap-reverse; /* 反向换行 */
}

flex-flow -> 方向+换行(简写)

css 复制代码
.container {
    /* 相当于:flex-direction + flex-wrap */
    flex-flow: row wrap;
}

align-content -> 多行对齐

css 复制代码
/* 当有多行时才有效 */
.container {
    align-content: flex-start;    /* 多行整体靠上 */
    align-content: center;        /* 多行整体居中 */
    align-content: space-between; /* 行间距相等 */
}
7.1.3:flex项目的三大权力

flex -> 三合一魔法属性

css 复制代码
.item {
  /* 格式:flex: 放大 缩小 基准 */
  flex: 1 1 200px;
}


.item1 { flex: 1; }           /* = 1 1 0% 平均分配 */
.item2 { flex: auto; }        /* = 1 1 auto 按内容 */
.item3 { flex: none; }        /* = 0 0 auto 不伸缩 */
.item4 { flex: 0 0 200px; }   /* 固定宽度200px */
  • flex-grow:有多余空间时,我能分多少
  • flex-shrink:空间不够时,我能缩多少
  • flex-basis:我理想的大小是多少

order -> 排队顺序

数字越小,排的越靠前

css 复制代码
/* 默认所有项目order: 0 */
.item1 { order: 1; }   /* 排到后面 */
.item2 { order: -1; }  /* 排到前面 */

align-self -> 自己单独对齐

css 复制代码
.item {
    align-self: auto;      /* 默认:听父母的 */
    align-self: flex-start; /* 我自己靠上 */
    align-self: center;     /* 我自己居中 */
    align-self: flex-end;   /* 我自己靠下 */
}
7.1.4:flex常见问题

flex: 1什么意思

flex: 1 = flex: 1 1 0%,意思是:能放大、能缩小、基准为0,平均分配剩余空间

如何让最后一个元素靠右

css 复制代码
.item:last-child {
    margin-left: auto; /* 如何让最后一个元素靠右 */
}

如何垂直居中

css 复制代码
.container {
    display: flex;
    align-items: center;      /* 垂直居中 */
    justify-content: center;  /* 水平居中 */
}
7.2:grid布局(⭐️⭐️⭐️⭐️⭐️⭐️)
7.2.1:网格编排

格子是如何画出来的,网格编排的所有的属性都是处理网格的分布

display:grid -> 容器声明网格布局

css 复制代码
.container {
    display: grid; /* 这个元素的所有直系子元素将成为网格元素 */
}

这个属性会将容器中所有的子项变成块盒

这一点非常重要,例如子项中有<span>,这个子项也会变成块盒

grid-template-columns / grid-template-rows

通过 grid-template-columns 和 grid-template-rows 属性来定义网格中的列和行。

这些属性定义了网格的轨道,一个网格轨道就是网格中任意两条线之间的空间。

grid-template-columns就是设置列的宽度,设计网格有几列就写几个宽度值。

css 复制代码
/*
	如果有12个子项,将会是3行,4列
	如果是5个子项,将会是2行,4列,第二行只有第一列有
	auto = 内容宽度 + padding + border + margin
*/
.grid-container {
  display: grid;
  grid-template-columns: auto auto auto auto; /* 定义列的个数是4 */
  /* 还可以使用repeat */
  grid-template-columns: repeat(4, auto); /*同上*/
  /* 还能够混用,下面这个是5列 */
  /* 第一列的宽度固定是100px
     后面3列的宽度根据内容而定
     最后一列的宽度占grid-container宽度的20% 
  */
  grid-template-columns: 100px repeat(3, auto) 20%;
}

fr单位的引入

网格引入了 fr 单位来帮助我们创建灵活的网格轨道。一个 fr 单位代表网格容器中可用空间的一等份。

以下实例定义了一个网格定义将创建三个相等宽度的轨道,这些轨道会随着可用空间增长和收缩。

css 复制代码
.grid-container {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr; /* 三列各占据grid-container宽度的1/3 */
    grid-template-columns: 2fr 2fr 2fr; /* 同上,三列个占据1/3 */
    grid-template-columns: 1fr 2fr 1fr; /* 第一列1/4, 第二列1/2,第三列1/4 */
}


/* 更加复杂一点 */
.container {
    display: grid;
    /* 创建自动适应的网格列:每列至少250px,有多余空间就平分,空间不够就换行 */
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    /* 自动适应列数,每列最小250px */
    gap: 20px;
}

同理,grid-template-rows声明的是每一行的高度

justify-content属性

justify-content 属性用于对齐容器内的网格

设置如何分配顺着弹性容器主轴(或者网格行轴) 的元素之间及其周围的空间。

css 复制代码
/* 对齐方式 */
justify-content: center;     /* 居中排列 */
justify-content: start;      /* 从行首开始排列 */
justify-content: end;        /* 从行尾开始排列 */
justify-content: flex-start; /* 从行首起始位置开始排列 */
justify-content: flex-end;   /* 从行尾位置开始排列 */
justify-content: left;       /* 一个挨一个在对齐容器得左边缘 */
justify-content: right;      /* 元素以容器右边缘为基准,一个挨着一个对齐, */

/* 基线对齐 */
justify-content: baseline;
justify-content: first baseline;
justify-content: last baseline;

/* 分配弹性元素方式 */
justify-content: space-between;  /* 均匀排列每个元素
                                   首个元素放置于起点,末尾元素放置于终点 */
justify-content: space-around;  /* 均匀排列每个元素
                                   每个元素周围分配相同的空间 */
justify-content: space-evenly;  /* 均匀排列每个元素
                                   每个元素之间的间隔相等 */
justify-content: stretch;       /* 均匀排列每个元素
                                   'auto'-sized 的元素会被拉伸以适应容器的大小 */

/* 溢出对齐方式 */
justify-content: safe center;
justify-content: unsafe center;

/* 全局值 */
justify-content: inherit;
justify-content: initial;
justify-content: unset;

align-content属性

用于设置垂直方向上的网格元素在容器中的对齐方式

网格元素的总高度必须小于容器的高度才能使 align-content 属性生效

同理,还是start/end/center/space-between/space-around/space-evenly/stretch等等

grid-gap / grid-row-gap / grid-column-gap

可以通过这三个属性调整网格间距。

  • grid-column-gap 属性来设置列之间的网格间距
  • grid-row-gap 属性来设置行之间的网格间距
  • grid-gap 属性是 grid-row-gap 和 the grid-column-gap 属性的简写

网格线

列与列,行与行之间的交接处就是网格线。

Grid 会为我们创建编号的网格线来让我们来定位每一个网格元素。

这个在后面子项放置非常重要,能划分出每一个子项划分的地盘。

7.2.2:子项放置

格子画好之后,html子项在格子中是如何分布的

网格容器包含了一个或多个网格元素。

默认情况下,网格容器的每一列和每一行都有一个网格元素,我们也可以设置网格元素跨越多个列或行,行和列为行号。这就用到了上面网格线的知识

grid-column / grid-column-start / grid-column-end

定义了网格元素列的开始和结束位置

css 复制代码
/* 这两个表示方式是一致的,都表明这个网格元素占据1,2,3,4列 */
.item1 {
  grid-column: 1 / 5;
}

.item1 {
    grid-column-start: 1;
    grid-column-end: 5;
}

grid-row / grid-row-start / grid-row-end

同理,定义了网格元素行的开始和结束位置

直接上一个例子:

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"> 
    <title>菜鸟教程(runoob.com)</title>
    <style>
    .grid-container {
        display: grid;
        grid-template-columns: repeat(4, auto);
        justify-content: center;
        gap: 10px 10px;
        background-color: #2196F3;
        padding: 10px;
    }
    .grid-item {
        background-color: rgba(255, 255, 255, 0.8);
        border: 1px solid rgba(0, 0, 0, 0.8);
        border-radius: 10px;
        padding: 20px;
        font-size: 30px;
        text-align: center;
    }
    /* 一号元素占据左上角的2行2列网格 */
    .item1 {
        grid-column: 1 / 3;
        grid-row: 1 / 3;
        text-align: center;
    }
    </style>
</head>
<body>
    <div class="grid-container">
        <div class="grid-item item1">1</div>
        <div class="grid-item">2</div>
        <div class="grid-item">3</div>  
        <div class="grid-item">4</div>
        <div class="grid-item">5</div>
        <div class="grid-item">6</div>  
        <div class="grid-item">7</div>
        <div class="grid-item">8</div>
        <div class="grid-item">9</div>  
    </div>
</body>
</html>

grid-area 属性是简写

css 复制代码
/*  "item8" 从第 1 行开始和第 2 列开始, 第 5 行和第 6 列结束 */
.item8 {
  grid-area: 1 / 2 / 5 / 6;
}

可以使用关键字 "span" 来定义元素将跨越的行数

css 复制代码
/*  "item8" 从第 2 行开始和第 1 列开始, 横跨 2 行 3 列。 */
/* (2, 1) -> (3, 3) */
.item8 {
  grid-area: 2 / 1 / span 2 / span 3;
}
7.3:响应式布局(⭐️⭐️⭐️⭐️⭐️⭐️)

响应式布局是设计理念,表示的是页面上的元素可以根据页面大小自动动态的调整样式。

7.3.1:流式布局

所谓流式布局,就是像水一样流动,不使用固定像素,而是使用百分比、视口单位

css 复制代码
/* 不使用固定像素,使用百分比、视口单位 */
.container {
    width: 90%;          /* 百分比宽度 */
    max-width: 1200px;   /* 最大限制 */
    min-width: 300px;    /* 最小限制 */
}

.img {
    max-width: 100%;     /* 图片自适应 */
    height: auto;        /* 保持比例 */
}

.text {
    font-size: clamp(16px, 2vw, 24px); /* 弹性字体大小 */
}
7.3.2:弹性盒子

使用上面的flexbox布局也可以满足响应式

css 复制代码
/* flex容器 */
.container {
    display: flex;
    flex-wrap: wrap;     /* 允许换行 */
    gap: 20px;           /* 间距自适应 */
}

/* flex子项 */
.item {
    flex: 1 1 300px;     /* 最小300px,可伸缩 */
}
7.3.3:网格布局

使用上面的grid布局也可以满足响应式

使用grid-template-cloumnsgrid-template-rows即可完成响应式

css 复制代码
.container {
    display: grid;
    /* 自动适应列数,每列最小250px, 最大1份 */
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 20px;
}
7.3.4:响应式技巧

@media - 精确控制

css 复制代码
/* 超小设备(手机,竖屏) */
@media (max-width: 576px) { }

/* 小设备(手机,横屏) */
@media (min-width: 577px) and (max-width: 768px) { }

/* 中等设备(平板) */
@media (min-width: 769px) and (max-width: 992px) { }

/* 大设备(电脑) */
@media (min-width: 993px) and (max-width: 1200px) { }

/* 超大设备(大屏幕) */
@media (min-width: 1201px) { }

视口单位(vw, vh, vmin, vmax)

单位 含义 基准 示例值 典型用途
vw 视口宽度百分比 窗口宽度 50vw = 窗口宽度的50% 响应式宽度
vh 视口高度百分比 窗口高度 100vh = 整个窗口高度 全屏背景
vmin 视口较小尺寸的% 宽高中较小的 50vmin = 宽高中较小的50% 正方形元素
vmax 视口较大尺寸的% 宽高中较大的 100vmax = 宽高中较大的100% 覆盖整个屏幕
css 复制代码
/* 相对于视口大小 */
.title {
    font-size: calc(16px + 1vw); /* 字体随视口变化 */
    padding: 5vh 5vw;           /* 内边距相对视口 */
    width: 80vw;                /* 宽度占视口80% */
}

clamp()智能限制

css 复制代码
/* 最小值 | 理想值 | 最大值 */
.font-responsive {
    font-size: clamp(16px, 2vw, 24px);
    /* 不小于16px,不大于24px,理想是2vw */
}

.width-responsive {
    /* 不小于300像素,不大于800像素,理想是50%宽度 */
    width: clamp(300px, 50%, 800px);
}

图片自适应

css 复制代码
img {
    max-width: 100%;  /* 关键! */
    height: auto;     /* 保持比例 */
}

/* 响应式背景图 */
.hero {
    background-image: url('small.jpg');
    background-size: cover;
}

@media (min-width: 768px) {
    .hero {
        background-image: url('large.jpg');
    }
}

响应式表格

css 复制代码
.table-responsive {
    overflow-x: auto; /* 小屏幕上可以横向滚动 */
}

8:SCSS

四:JavaScript

JS = ESMAScript + DOM + BOM

如果你掌握了Java, JS的学习将会非常的容易

1:JS概述

JS是解释型语言(不需要编译成为机器码,开发容易 + 运行缓慢),动态语言(类型动态)

类似于JAVA和Cpp的语法结构,严格区分大小写

​在项目中,可以通过两种方式使用JS:分别是标签引用和文件引用

html 复制代码
<script>
    alert("Hello,World!");
</script>

<script src="main.js"></script> <!-- 通过src属性指定js文件的位置 -->

JS的输出分成三种:页面输出,控制台输出和弹出窗口输出,其中控制台输出最为常用,用于前端调试

js 复制代码
// 页面输出
document.write("Hello,World!");

// 控制台输出
console.log("输出一条日志"); // 最常用

// 弹出窗口输出
alert("Hello,World!");

JS注释同java, 单行注释//和多行注释/* */

2:JS基础语法

如果你学习过任何一种后端语言,例如java,这部分非常好理解

2.1:JS变量

注意关键字和保留字不能作为变量名,JS命名规范还是那一套,一点说明的就是最好使用驼峰命名法

在 JavaScript 中,一般常量声明用const, 变量声明用let,es6有let之后很少用var了

js 复制代码
let a = 10

const b = 20
a = "str"
// b = 30 //  error, 因为b是常量,不能被修改
2.2:JS基本数据类型

JS有五种基本数据类型:字符串类型(String), 数值类型(Number), 布尔类型(Boolean), undefined和null

这5种之外的类型都称为Object,所以总的来看JavaScript中共有六种数据类型

可以使用typeof(变量名)的方法查看一个变量的数据类型

Number 类型用来表示整数和浮点数,-1.7976931348623157e+308 ~ +1.7976931348623157e+308, 如果超过了这个范围将会返回±Infinity。0以上的最小值是5e-324, 还有一个特殊的数字是NaN(not a number)

0b开头二进制,0开头8进制,0x开头十六进制

在使用 var/let 声明变量但未对其加以初始化时,这个变量的值就是 undefined。

js 复制代码
let b;
console.log(b + " " + typeof(b)) // undefined undefined
b = false
console.log(b + " " + typeof(b)) // false boolean

null是另一个特殊类型,表示空的Object, undefined是null衍生出来的, null的数据类型是Object

重点 - 数据类型的转换

js 复制代码
// 其他类型转成字符串
let a1 = 123;
let b1 = String(a1);
let c1 = a1 + "";
let d1 = a1.toString();

console.log(typeof(a1), typeof(b1), typeof(c1), typeof(d1)) // number string string string

// 字符串转成数字
let a2 = "123";
let b2 = Number(a2);
let c2 = +a2;
let d2 = parseInt(a2);
let e2 = parseFloat(a2);

console.log(typeof(a2), typeof(b2), typeof(c2), typeof(d2), typeof(e2)) // string number number number number

// 其他类型转成boolean
// 0, "", null, undefined, NaN 这五个转换成false, 其他都会转换成true
let a3 = null
console.log(Boolean(a3)) //  false
let b3 = 0
console.log(Boolean(b3)) //  false
2.3:运算符

算数运算符 / 关系运算符 / 赋值运算符 / 逻辑运算符 不再过多赘述,都懂

  • 算数运算符:+ - * / % ++ --
  • 关系运算符:> < >= <=
  • 赋值运算符:= += -= *= /= %=
  • 逻辑运算符:&&(全真才真,短路机制) ||(有真则真,短路机制) !(真假取反)
  • 三元表达式:exp ? ans1 : ans2,如果exp的结果为真,取ans1,否则取ans2
  • 逗号运算符:从左到右

重点说下JS的比较运算符:== != === !==,注意一点就是==!=比较的时候会进行类型转换,先将两个比较对象转换成为同一个类型,然后再比较,而===!==则不会,不一样就是不一样

js 复制代码
let c = null
let d = undefined
console.log(c == d) //  true
console.log(c === d) //  false

运算符优先级不好记,但是只要记住一点:你想要优先算的,加括号就好了,先算括号内的(仅次于创建)

2.4:控制语句

更是和Java长的几乎一样,会java就会JS的

if 条件控制语句

js 复制代码
if (exp) {
    statement of exp is true;
} else if (exp2) {
    statement of exp2 is true;
} else {
    statement of others;
}


let age = 18;
if (age < 18) {
    console.log("小于18岁了");
} else if (age == 18) {
    console.log("已经18岁了");
} else {
    console.log("大于18岁了")
}

switch...case

js 复制代码
switch (语句) {
    case 表达式1:
        语句...
    case 表达式2:
        语句...
    default:
        语句...
}
        
// 例如
let sex = '男';
switch (sex) {
    case '女':
        console.log("是女生");
        break;
    case '男':
    default:
        console.log("是男生");
}

循环

js 复制代码
while (exp) {
    statement...
}

do {
    语句...
} while (条件表达式); // 至少执行一次  
    
for(初始化表达式; 条件表达式; 更新表达式) {
    语句...
}
// 例如
for (var i = 1; i <= 10; i++) {
    console.log(i);
}

break和continue关键字

  • break:结束最近的一次循环,可以在循环和switch语句中使用。
  • continue:结束本次循环,执行下一次循环,只能在循环中使用。
2.5:函数function

函数有4种写法

js 复制代码
// 第一类:正式写法
// 可提前调用,所谓提前调用,就是调用在函数声明之前写
console.log(greet("小明")); // 你好,小明!

function greet(name) {
    return "你好," + name + "!";
}

// 第二类:函数表达式
// 像给变量赋值一个函数
const sayHello = function(name) {
    return "Hello, " + name;
};
console.log(sayHello("Tom")); // Hello, Tom

// 第三类:箭头函数
// 简洁写法,适合简单函数
const add = (a, b) => a + b;
console.log(add(2, 3)); // 5
// 多个参数用括号
const multiply = (x, y) => {
    return x * y;
};

// 第四类:定义后立刻执行,像泡面:拆开就泡
(function() {
    console.log("立即执行!");
})();

3:JS类和对象

3.1:概述

JS是面向对象的语言,所谓面向对象,就是用对象object表示现实世界中具体的事物,这点和Java理念一致,万物皆对象

对象分成属性和方法:属性就是事务的特征,方法就是事务的行为。例如手机这个对象有屏幕属性和打电话这个行为方法

类class抽象了对象的公共部分,泛指一大类,通过类的实例化得到对象。

类比一下:类是汽车的设计图纸,对象是具体的汽车🚗:设计图纸通过实例化得到具体的汽车

对象的方法就是属于某个对象的函数

js 复制代码
// 类的声明
class name {
  // class body
}

// 实例化,得到具体的对象,类必须使用 new 实例化对象
let xxx = new name()

构造函数

constructor() 方法是类的构造函数(默认方法),用于传递参数,返回实例对象。

通过 new 命令生成对象实例时,自动调用该方法。

如果没有显示定义, 类内部会自动给我们创建一个参数为空的constructor()

js 复制代码
class Person {
  constructor(name,age) {   // constructor 构造方法或者构造函数
      this.name = name;
      this.age = age;
    }
}

let ldh = new Person('刘德华', 18); 
console.log(ldh.name);

类方法

方法之间不能加逗号分隔,同时方法不需要添加 function 关键字

js 复制代码
class Person {
  constructor(name,age) {   // constructor 构造器或者构造函数
      this.name = name;
      this.age = age;
    }
   say() {
      console.log(this.name + '你好');
   }
}

let ldh = new Person('刘德华', 18); 
ldh.say() // 刘德华你好
3.2:类的继承

子类可以继承父类的一些属性和方法,extends关键字

js 复制代码
class Father {
      constructor(surname) {
        this.surname= surname;
      }
      say() {
        console.log('你的姓是' + this.surname);

       }
}
class Son extends Father{  // 这样子类就继承了父类的属性和方法

}
let damao= new Son('刘');
damao.say();

super 关键字用于子类访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数

js 复制代码
class Father {
    constructor(surname) {
        this.surname = surname;
     }
    saySurname() {
      console.log('我的姓是' + this.surname);
    }
}
class Son extends Father { // 这样子类就继承了父类的属性和方法
    constructor(surname, fristname) {
         super(surname);   // 调用父类的constructor(surname)
         this.fristname = fristname;
     }
    sayFristname() {
         super.saySurname();
         console.log("我的名字是:" + this.fristname);

    }
}

let son = new Son('王', '小王');
son.sayFristname();

this 关键字:constructor 里面的this指向实例对象, 方法里面的this 指向这个方法的调用者

3.3:构造函数和原型(⭐️⭐️⭐️⭐️⭐️⭐️)
3.3.1:构造函数 + new关键字

在JS中,构造函数有两点需要注意:首字母大写 + 和new关键字一起使用。

js 复制代码
function Star(uname, age) {
    this.uname = uname;
    this.age = age;
    this.sing = function () {
        console.log('I am singing');
    }
}

let xiaoming = new Star('xiaoming', 18);
xiaoming.sing() // I am singsing
let xiaohong = new Star('xiaohong', 19);
xiaohong.sing() // I am singsing

new会在执行的时候做四件事:面试常考

  1. 在内存中创建一个新的空对象

  2. 让 this 指向这个新的对象。

  3. 执行构造函数里面的代码,给这个新对象添加属性和方法。

  4. 返回这个新对象(所以构造函数里面不需要 return )

静态成员 & 实例成员

JS中可以在构造函数中添加一些成员,如果在构造函数本身添加,称为静态成员,反之如果加在内部的this,称为实例成员

静态成员只能由构造函数本事访问,实例成员仅能由实例化的对象访问

3.3.2:构造函数原型prototype

上面这个方法有一个十分明显的问题,就是存在浪费内存的问题,每一个对象是各自单独的函数,而构造函数通过原型分配的函数是所有对象所共享的,因此,我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。

  • 只有函数才有 prototype 属性

  • 它是给未来通过new创建的对象准备的"公共模具"

  • 所有通过该构造函数创建的对象,都共享这个模具

javascript 复制代码
// 定义一个构造函数 - 玩具生产线
function Toy(name) {
    this.name = name
}

// 给这条生产线配置"模具", 这条生产线的所有的玩具都会公用这一个模具
// 这也是原型模式的核心 - 共享属性和方法
Toy.prototype = {
    play() {
        console.log(`玩${this.name}`)
    },
    material: "塑料"
}

// 通过new 关键字创建一个玩具,生产线生产一个小汽车
// 小汽车使用模具中的模具,获得共享方法play(), 共享属性material
let toy = new Toy("小汽车")
toy.play()
console.log(toy.constructor === Toy) // false -> toy对象是由Object创建的
console.log(toy instanceof Toy) //  true -> toy对象是由Toy构造函数创建的
console.log(toy.constructor.name) // Object -> 表示toy对象是由Object创建的
3.3.3:__proto__对象属性

对象都会有一个属性 __proto__ ,他指向构造函数的 prototype 原型对象

js 复制代码
对象.__proto__  === 创建它的构造函数.prototype

__proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线

但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype

javascript 复制代码
// 定义一个构造函数 - 玩具生产线
function Toy(name) {
    this.name = name
}

// 给这条生产线配置"模具", 这条生产线的所有的玩具都会公用这一个模具
// 这也是原型模式的核心 - 共享属性和方法
Toy.prototype = {
    play() {
        console.log(`玩${this.name}`)
    },
    material: "塑料"
}

// 通过new 关键字创建一个玩具,生产线生产一个小汽车
// 小汽车使用模具中的模具,获得共享方法play(), 共享属性material
let toy = new Toy("小汽车")
toy.play()
console.log(toy.constructor === Toy) // false -> toy对象是由Object创建的
console.log(toy instanceof Toy) //  true -> toy对象是由Toy构造函数创建的
console.log(toy.constructor.name) // Object -> 表示toy对象是由Object创建的

// 可以将__proto__属性理解为产品的标签
// car.__proto__ 就是问:"小汽车,你是用哪个模具生产的?"
console.log(toy.__proto__ === Toy.prototype) // true -> toy.__proto__属性指向了Toy.prototype对象
console.log(toy.hasOwnProperty('play')); // false - play不是car自己的
console.log('play' in toy); // true - 但可以通过原型链找到
3.3.4:原型链

而原型链这个概念就是一个"找东西"的过程

  1. 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。

  2. 如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)。

  3. 如果还没有就查找原型对象的原型(Object的原型对象)。

  4. 依此类推一直找到 Object 为止(null)。

  5. __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。

javascript 复制代码
// 定义一个构造函数 - 玩具生产线
function Toy(name) {
    this.name = name
}

// 给这条生产线配置"模具", 这条生产线的所有的玩具都会公用这一个模具
// 这也是原型模式的核心 - 共享属性和方法
Toy.prototype = {
    play() {
        console.log(`玩${this.name}`)
    },
    material: "塑料"
}

// 通过new 关键字创建一个玩具,生产线生产一个小汽车
// 小汽车使用模具中的模具,获得共享方法play(), 共享属性material
let toy = new Toy("小汽车")
toy.play()

// 当访问car.play()时,JS的查找顺序:
// 1. 先看car自己有没有play属性 -> 没有
// 2. 看car.__proto__(即Toy.prototype)有没有 -> 有。找到了,结束查找
// 3. 如果还没有,继续看Toy.prototype.__proto__(Object.prototype)
// 4. 直到找到或到达null

console.log(car.__proto__.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null - 到头了


console.log(toy.constructor === Toy) // false -> toy对象是由Object创建的
console.log(toy instanceof Toy) //  true -> toy对象是由Toy构造函数创建的
console.log(toy.constructor.name) // Object -> 表示toy对象是由Object创建的
// 可以将__proto__属性理解为产品的标签
// car.__proto__ 就是问:"小汽车,你是用哪个模具生产的?"
console.log(toy.__proto__ === Toy.prototype) // true -> toy.__proto__属性指向了Toy.prototype对象
console.log(toy.hasOwnProperty('play')); // false - play不是car自己的
console.log('play' in toy); // true - 但可以通过原型链找到

/*

就是这么一个链....

toy(玩具)
  ↓ __proto__
Toy.prototype(模具)
  ↓ __proto__
Object.prototype(基础模具)
  ↓ __proto__
null
*/
特性 prototype __proto__
归属 函数独有 对象都有
作用 作为新建对象的模板 指向创建者的原型
访问 Func.prototype obj.__proto__
标准 ES标准属性 非标准,但有浏览器实现

现在都使用Object.getPrototypeOf(),因为obj.__proto__写法不规范

js 复制代码
let car = new Toy('小汽车');

// 不推荐(非标准)
console.log(car.__proto__);

// 推荐(标准方法)
console.log(Object.getPrototypeOf(car)); // 等同于car.__proto__
console.log(Object.getPrototypeOf(car) === Toy.prototype); // true
3.3.5:继承

ES6之前并没有给我们提供 extends 继承。我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承。

ES6之后使用class + extends方式实现继承和原型,非常好理解,看下面例子就知道ES6之后如何实现了

js 复制代码
class Animal {
  constructor(name) {
    this.name = name;  // 实例属性
  }
  
  // 自动添加到 Animal.prototype
  eat() {
    console.log(`${this.name}在吃东西`);
  }
}

class Dog extends Animal {
  // 子类的构造方法
  constructor(name, breed) {
    super(name);  // 相当于 Animal.call(this, name)
    this.breed = breed;
  }
  
  // 自动添加到 Dog.prototype
  bark() {
    console.log(`${this.name}在汪汪叫`);
  }
  
  // 可以重写父类方法
  eat() {
    super.eat();  // 调用父类的eat方法
    console.log('吃的是狗粮');
  }
}

const myDog = new Dog('旺财', '金毛');
myDog.eat();  // "旺财在吃东西" "吃的是狗粮"
myDog.bark(); // "旺财在汪汪叫"

由此可以总结出类class的本质

class本质还是function,ES6的类其实就是语法糖,更加面向编程。

类的所有方法都定义在类的prototype属性上

类创建的实例,里面也有__proto__ 指向类的prototype原型对象

3.4:this:当前上下文的主人

this就是当前代码执行所在的环境,就是谁调用,this就指向谁

this取决于函数的调用方式,而不是定义的位置

js 复制代码
// 示例1:全局上下文
// this指向的就是window
console.log(this); // 浏览器中指向window,Node.js中指向global


// 示例2:对象方法中的this
// this指向的就是调用这个方法的对象
const person = {
  name: "小明",
  sayName() {
    console.log(this.name); // this指向person对象
  }
};
person.sayName(); // 输出:"小明"

// 示例3:构造函数中的this
// this指定的就是新穿件的对象
function Car(brand) {
  this.brand = brand; // this指向新创建的对象
}
const myCar = new Car("Toyota");

// 示例4:箭头函数的this
const obj = {
  name: "小红",
  regularFunc: function() {
    console.log(this.name); // 正常指向obj
  },
  arrowFunc: () => {
    console.log(this.name); // 指向外层作用域,这里可能是window/undefined
  }
};

// 实例5:计时器中的this指向window
let cat = {
	name: "喵喵",
	sayName() {
		setTimeout(function(){console.log(this)}, 1000) // 指向window
	}
}
  1. 方法中的this,指向调用方法的对象
  2. 全局环境下指向全局对象
  3. 全局函数中的this,指向全局对象
  4. 内部函数中的this,指向全局对象
  5. 事件中的this,指向触发事件的DOM对象
  6. 构造函数中的this,指向new创建的对象【面试题new的作用】
  7. 箭头函数中的this,指向定义函数上下文的this。
  8. 使用闭包,var获取dom的索引。

可以通过call() / apply() / bind()方法,来改变this的指向

js 复制代码
const person = {
    name: "小明"
};

function introduce(greeting) {
    console.log(`${greeting}, 我是${this.name}`);
}

introduce("你好") //  你好, 我是undefined

// 1. call() - 强行改变this指向, this的指向就是call的第一个参数
introduce.call(person, "你好"); // 你好, 我是小明

// 2. apply() - 强行改变this指向, this的指向就是apply的第一个参数
introduce.apply(person, ["你好"]); // 你好, 我是小明

// 3. bind() - 返回新函数,稍后调用
const boundFunc = introduce.bind(person, "你好");
boundFunc(); // 你好, 我是小明
3.5:闭包和递归

闭包是指函数能够记住并访问它被创建时的词法作用域,即使函数在其作用域外执行

简单的来说就是一个函数可以访问其所在外部函数的变量,即闭包 = 内层函数 + 引用的外层函数变量。

js 复制代码
function outer() {
	// 内层函数 + 这个a变量构成闭包Closure
    let a = 100;
    function  inner() {
        console.log("我是内部函数,我能引用外部函数的变量a: " + a);
    }
}

outer()

通常使用一个函数包裹住闭包结构,以起到对变量保护的作用。

无法直接在外部访问i这个变量,完成了数据封装。

闭包使用场景:节流和防抖,vue3和react的hook

⚠️ 闭包可能会导致内存泄漏:

递归是函数直接或间接调用自身来解决问题的方法,俄罗斯套娃🪆

js 复制代码
// 经典示例:计算阶乘
// 5! = 5 × 4 × 3 × 2 × 1 = 120
function factorial(n) {
  // 终止条件:当n为1时,停止递归
  if (n === 1) {
    return 1;
  }
  
  // 递归步骤:n! = n × (n-1)!
  return n * factorial(n - 1);
}

console.log(factorial(5)); // 120

递归三大要素:终止条件(递归何时结束) + 递归步骤(如何将问题分解为小的同类问题) + 递归调用(我调我自己)

js 复制代码
// 场景1:树形结构的遍历
// 遍历DOM树
function traverseDOM(node, depth = 0) {
  // 输出当前节点
  console.log(" ".repeat(depth * 2) + node.nodeName);
  
  // 递归遍历子节点
  node.childNodes.forEach(child => {
    if (child.nodeType === 1) { // 元素节点
      traverseDOM(child, depth + 1);
    }
  });
}

// traverseDOM(document.body);

// 场景2:深拷贝
function deepClone(obj) {
  // 终止条件:不是对象或是null
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }
  
  // 创建新对象或数组
  const clone = Array.isArray(obj) ? [] : {};
  
  // 递归复制每个属性
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key]);
    }
  }
  
  return clone;
}

const original = { a: 1, b: { c: 2, d: [3, 4] } };
const cloned = deepClone(original);

⚠️ 必须有终止条件,否则会无限递归导致栈溢出

⚠️ 递归层级不宜过深(通常不超过1000层)

3.6:JS常用对象-基本对象
3.6.1:原始对象

JavaScript 中最基础的对象,所有其他对象都继承自 Object。

原始对象对于高级调试非常有用

创建方式 语法 示例 说明
字面量 {} let obj = {} 最常用方式
构造函数 new Object() let obj = new Object() 较少使用
Object.create() Object.create(proto) let obj = Object.create(null) 指定原型

属性操作

方法 描述 返回值 是否改变原对象
Object.keys() 获取自身可枚举属性名数组 Array
Object.values() 获取自身可枚举属性值数组 Array
Object.entries() 获取自身可枚举键值对数组 Array
Object.hasOwn() 检查是否拥有自身属性 boolean
Object.getOwnPropertyNames() 获取所有自身属性名 Array

对象操作

方法 描述 返回值 是否改变原对象
Object.assign() 合并对象(浅拷贝) 新对象
Object.freeze() 冻结对象 被冻结对象
Object.seal() 密封对象 被密封对象
Object.preventExtensions() 阻止扩展 对象
Object.is() 值比较(同值相等) boolean

属性描述符

方法 描述 返回值 是否改变原对象
Object.defineProperty() 定义/修改属性 对象
Object.defineProperties() 定义多个属性 对象
Object.getOwnPropertyDescriptor() 获取属性描述符 描述符对象
Object.getOwnPropertyDescriptors() 获取所有属性描述符 描述符对象

原型操作

方法 描述 返回值 是否改变原对象
Object.getPrototypeOf() 获取原型 prototype对象
Object.setPrototypeOf() 设置原型 对象
Object.isPrototypeOf() 检查是否为原型 boolean

es6新特性

方法/特性 描述 示例
扩展运算符 对象展开 {...obj1, ...obj2}
解构赋值 提取属性 const {name, age} = person
属性简写 同名属性简写 {name, age}
计算属性名 动态属性名 {[key]: value}
Object.hasOwn() 替代hasOwnProperty Object.hasOwn(obj, 'prop')
Object.fromEntries() 键值对数组转对象 Object.fromEntries([['a',1]])
3.6.2:String对象

表示和操作文本数据,字符串是不可变的。重要性不用多说

查询与访问

方法 描述 返回值 是否改变原字符串
length 字符串长度 number -
charAt() 获取指定位置字符 string
charCodeAt() 获取字符编码 number
codePointAt() 获取Unicode编码 number
[] 索引访问字符 string
indexOf() 查找子串首次位置 number
lastIndexOf() 查找子串最后位置 number
includes() 是否包含子串 boolean
startsWith() 是否以子串开头 boolean
endsWith() 是否以子串结尾 boolean
search() 正则搜索位置 number

提取与分割

方法 描述 返回值 是否改变原字符串
slice() 提取子串 string
substring() 提取子串 string
substr() 提取子串 string
split() 分割为数组 Array
match() 正则匹配 Array/null
matchAll() 正则匹配所有 Iterator

修改与转换

方法 描述 返回值 是否改变原字符串
concat() 连接字符串 string
repeat() 重复字符串 string
padStart() 开头填充 string
padEnd() 结尾填充 string
toUpperCase() 转大写 string
toLowerCase() 转小写 string
toLocaleUpperCase() 本地化转大写 string
toLocaleLowerCase() 本地化转小写 string
normalize() Unicode正规化 string

修剪与替换

方法 描述 返回值 是否改变原字符串
trim() 去除两端空格 string
trimStart() 去除开头空格 string
trimEnd() 去除结尾空格 string
replace() 替换子串 string
replaceAll() 替换所有子串 string

静态方法

方法 描述
String.fromCharCode() 编码转字符
String.fromCodePoint() Unicode转字符
String.raw() 原始模板字符串
3.6.3:number数字对象

实例方法

方法 描述 返回值
toFixed() 固定小数位数 string
toExponential() 科学计数法 string
toPrecision() 指定精度 string
toString() 转为字符串 string
valueOf() 获取原始值 number

静态属性(常量)

属性 描述
Number.MAX_VALUE 最大正数 1.7976931348623157e+308
Number.MIN_VALUE 最小正数 5e-324
Number.MAX_SAFE_INTEGER 最大安全整数 9007199254740991
Number.MIN_SAFE_INTEGER 最小安全整数 -9007199254740991
Number.POSITIVE_INFINITY 正无穷 Infinity
Number.NEGATIVE_INFINITY 负无穷 -Infinity
Number.NaN 非数字 NaN
Number.EPSILON 最小精度 2.220446049250313e-16

静态方法

方法 描述 返回值
Number.isNaN() 是否为NaN boolean
Number.isFinite() 是否为有限数 boolean
Number.isInteger() 是否为整数 boolean
Number.isSafeInteger() 是否为安全整数 boolean
Number.parseFloat() 解析浮点数 number
Number.parseInt() 解析整数 number
3.6.4:Boolean对象

以下值在布尔上下文中为 false,除了下面表格的是false,其他的全是true

类型
false Boolean
0 Number
-0 Number
0n BigInt
"" String
null Object
undefined Undefined
NaN Number
3.7:JS常用对象-核心对象
3.7.1:数组对象

数组对象可以放入不同类型的对象,可以理解为python的list

js 复制代码
let arr = new Array();
arr[0] = 1;
arr[1] = 2;
arr[2] = "2"; // 可以放入不同的类型,可以理解为python的list

// 还可以使用字面量创建
let arr = [1, 2, 3, 4, 5]
let arr = [1, "1", 2, "2"]

数组常见操作如下:非常像python的list方法

数组方法非常的重要,后面在框架实战中,对于接受到的后端数据,很多数组的处理,还有复选框的处理,一定要熟练运用

增删改方法

方法 描述 返回值 是否改变原数组 示例
push() 末尾添加一个或多个元素 新数组长度 arr.push(4,5)
pop() 删除最后一个元素 被删除的元素 arr.pop()
unshift() 开头添加一个或多个元素 新数组长度 arr.unshift(0)
shift() 删除第一个元素 被删除的元素 arr.shift()
splice() 删除/替换/添加元素 被删除的元素数组 arr.splice(1,2,'a','b')
fill() 填充数组元素 修改后的数组 arr.fill(0,1,3)

查询遍历方法

方法 描述 返回值 是否改变原数组 示例
forEach() 遍历数组执行回调 undefined arr.forEach(item => console.log(item))
map() 映射新数组 新数组 arr.map(x => x*2)
filter() 过滤满足条件的元素 新数组 arr.filter(x => x>5)
find() 查找第一个满足条件的元素 元素或undefined arr.find(x => x>5)
findIndex() 查找第一个满足条件的索引 索引或-1 arr.findIndex(x => x>5)
indexOf() 查找元素首次出现位置 索引或-1 arr.indexOf(5)
lastIndexOf() 查找元素最后出现位置 索引或-1 arr.lastIndexOf(5)
includes() 是否包含某元素 boolean arr.includes(5)
some() 是否有元素满足条件 boolean arr.some(x => x>5)
every() 是否所有元素满足条件 boolean arr.every(x => x>5)

排序转换方法

方法 描述 返回值 是否改变原数组 示例
sort() 数组排序 排序后的数组 arr.sort((a,b) => a-b)
reverse() 反转数组顺序 反转后的数组 arr.reverse()
join() 数组转字符串 字符串 arr.join('-')
toString() 数组转字符串 字符串 arr.toString()
concat() 合并多个数组 新数组 arr.concat(arr2,arr3)
slice() 截取数组部分 新数组 arr.slice(1,4)
flat() 数组扁平化 新数组 arr.flat(2)
flatMap() 映射后扁平化 新数组 arr.flatMap(x => [x, x*2])

其他实用方法

方法 描述 返回值 是否改变原数组 示例
reduce() 累计器 累计结果 arr.reduce((sum,cur) => sum+cur,0)
reduceRight() 从右累计 累计结果 arr.reduceRight(...)
keys() 返回键名迭代器 迭代器 [...arr.keys()]
values() 返回值迭代器 迭代器 [...arr.values()]
entries() 返回键值对迭代器 迭代器 [...arr.entries()]
Array.isArray() 判断是否为数组 boolean - Array.isArray(arr)
Array.from() 类数组转数组 新数组 - Array.from('hello')
Array.of() 创建数组 新数组 - Array.of(1,2,3)

ES6+新增方法

方法 描述 返回值 是否改变原数组 示例
findLast() 查找最后一个满足条件的 元素或undefined arr.findLast(x => x>5)
findLastIndex() 查找最后一个满足条件的索引 索引或-1 arr.findLastIndex(x => x>5)
toSorted() 排序(不改变原数组) 新数组 arr.toSorted()
toReversed() 反转(不改变原数组) 新数组 arr.toReversed()
toSpliced() 增删改(不改变原数组) 新数组 arr.toSpliced(1,2)
with() 修改指定位置值(不改变原数组) 新数组 arr.with(2, 100)

使用建议速查表

需求场景 推荐方法
添加元素到末尾 push()
从末尾删除元素 pop()
添加元素到开头 unshift()
从开头删除元素 shift()
在任意位置增删改 splice()
遍历数组 forEach()
创建新数组映射 map()
过滤数组 filter()
查找元素 find() / includes()
检查条件 some() / every()
数组排序 sort() / toSorted()
数组反转 reverse() / toReversed()
数组拼接 concat()
数组切片 slice()
数组转字符串 join()
数组累加 reduce()
数组扁平化 flat() / flatMap()
不改变原数组的修改 with() / toSpliced()
3.7.2:Date对象

JavaScript Date 对象用于处理日期和时间。它基于 Unix 时间戳(1970年1月1日 UTC 以来的毫秒数)

⚠️ 月份从 0 开始(0=一月,11=十二月),星期从 0 开始(0=周日,6=周六)

⚠️ 时间基于本地时区,除非指定 UTC

Data对象的创建

创建方式 语法示例 说明
当前时间 new Date() 当前日期和时间
时间戳 new Date(timestamp) 毫秒时间戳
日期字符串 new Date(dateString) 可解析的日期字符串
年月日时分秒 new Date(year, month[, day, hour, minute, second, ms]) 指定各部分
UTC时间 new Date(Date.UTC(...)) 创建UTC时间
js 复制代码
// 1. 当前时间
const now = new Date(); // 当前日期时间

// 2. 时间戳(毫秒)
const timestamp = new Date(1609459200000); // 2021-01-01 00:00:00

// 3. 日期字符串(推荐标准格式)
const dateStr = new Date('2024-12-25T10:30:00');
const dateStr2 = new Date('December 25, 2024 10:30:00');

// 4. 指定参数
const specificDate = new Date(2024, 11, 25, 10, 30, 0); // 注意:11表示12月

// 5. UTC时间
const utcDate = new Date(Date.UTC(2024, 11, 25, 10, 30, 0));

Date对象方法

时间获取方法和设置方法,分别是getxxx和setxxx,现代编译器都有代码提示,非常好理解

这里列举下格式化输出的方法,工作中操作时间对象的时候可能会遇到转化的情况:

方法 返回格式 示例(北京时间)
toString() 完整日期时间字符串 "Wed Dec 25 2024 14:30:45 GMT+0800 (中国标准时间)"
toDateString() 日期部分字符串 "Wed Dec 25 2024"
toTimeString() 时间部分字符串 "14:30:45 GMT+0800 (中国标准时间)"
toLocaleString() 本地格式日期时间 "2024/12/25 14:30:45"
toLocaleDateString() 本地格式日期 "2024/12/25"
toLocaleTimeString() 本地格式时间 "14:30:45"
toUTCString() UTC格式字符串 "Wed, 25 Dec 2024 06:30:45 GMT"
toISOString() ISO 8601格式 "2024-12-25T06:30:45.000Z"
toJSON() JSON格式(同ISO) "2024-12-25T06:30:45.000Z"

常用工具方法

js 复制代码
// 是否同一天
function isSameDay(date1, date2) {
  return date1.getFullYear() === date2.getFullYear() &&
         date1.getMonth() === date2.getMonth() &&
         date1.getDate() === date2.getDate();
}

// 加减天数
const addDays = (date, days) => {
  const result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
};

// 加减月份
const addMonths = (date, months) => {
  const result = new Date(date);
  result.setMonth(result.getMonth() + months);
  return result;
};

// 计算日期差(天数)
const dateDiffInDays = (date1, date2) => {
  const timeDiff = Math.abs(date2.getTime() - date1.getTime());
  return Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
};

// 常用格式化函数
function formatDate(date, format = 'YYYY-MM-DD') {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  const seconds = String(date.getSeconds()).padStart(2, '0');

  const formats = {
    'YYYY-MM-DD': `${year}-${month}-${day}`,
    'YYYY/MM/DD': `${year}/${month}/${day}`,
    'YYYY-MM-DD HH:mm:ss': `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`,
    'HH:mm:ss': `${hours}:${minutes}:${seconds}`,
    'MM/DD/YYYY': `${month}/${day}/${year}`,
  };

  return formats[format] || `${year}-${month}-${day}`;
}

// 星期几
function getChineseDay(date) {
  const days = ['日', '一', '二', '三', '四', '五', '六'];
  return `星期${days[date.getDay()]}`;
}

// 日期有效性验证
function isValidDate(date) {
  return date instanceof Date && !isNaN(date.getTime());
}
3.7.3:Map映射对象

键值对集合,键可以是任意类型,保持插入顺序, map一般用于缓存计算结果和数据分组,分组的依据就是Key

创建方式 语法 示例
构造函数 new Map() new Map()
带初始值 new Map(iterable) new Map([['a',1],['b',2]])
核心方法如下:
方法 描述 返回值 是否改变原Map
set(key, value) 设置键值对 Map对象
get(key) 获取键对应的值 value 或 undefined
has(key) 检查键是否存在 boolean
delete(key) 删除键值对 boolean
clear() 清空所有键值对 undefined
size 获取元素数量 number -
keys() 返回键的迭代器 Iterator
values() 返回值的迭代器 Iterator
entries() 返回键值对的迭代器 Iterator
forEach() 遍历Map undefined
3.7.4:set集合对象

存储唯一值的集合,保持插入顺序。set是特殊的map, 可以想象成map的key就是set

set一般用于数据去重(唯一性)和标签之类的存储,还有就是权限检查等等...

创建方式 语法 示例
构造函数 new Set() new Set()
带初始值 new Set(iterable) new Set([1,2,3,2,1])
核心方法如下:
方法 描述 返回值
--------------- --------------------- -----------
add(value) 添加值 Set对象
has(value) 检查值是否存在 boolean
delete(value) 删除值 boolean
clear() 清空所有值 undefined
size 获取元素数量 number
values() 返回值的迭代器 Iterator
keys() 同values() Iterator
entries() 返回[value, value]迭代器 Iterator
forEach() 遍历Set undefined
js 复制代码
// 并集
function union(setA, setB) {
  return new Set([...setA, ...setB]);
}

// 交集
function intersection(setA, setB) {
  return new Set([...setA].filter(x => setB.has(x)));
}

// 差集
function difference(setA, setB) {
  return new Set([...setA].filter(x => !setB.has(x)));
}

// 对称差集
function symmetricDifference(setA, setB) {
  return union(difference(setA, setB), difference(setB, setA));
}

// 子集检查
function isSubset(setA, setB) {
  return [...setA].every(x => setB.has(x));
}
3.7.5:Math数学对象
常量 描述 近似值
Math.PI 圆周率 3.141592653589793
Math.E 自然常数 2.718281828459045
Math.LN2 2的自然对数 0.6931471805599453
Math.LN10 10的自然对数 2.302585092994046
Math.LOG2E 以2为底E的对数 1.4426950408889634
Math.LOG10E 以10为底E的对数 0.4342944819032518
Math.SQRT2 2的平方根 1.4142135623730951
Math.SQRT1_2 1/2的平方根 0.7071067811865476

舍入方法,最大最小值啥的那一套,不再赘述列举...

js 复制代码
// 生成随机数
function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function randomFloat(min, max) {
  return Math.random() * (max - min) + min;
}

// 限制数值范围
function clamp(value, min, max) {
  return Math.max(min, Math.min(max, value));
}

// 线性插值
function lerp(start, end, t) {
  return start + (end - start) * t;
}

// 映射数值范围
function map(value, fromMin, fromMax, toMin, toMax) {
  return (value - fromMin) * (toMax - toMin) / (fromMax - fromMin) + toMin;
}

// 计算两点距离
function distance(x1, y1, x2, y2) {
  return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}

// 角度与弧度转换
function toRadians(degrees) {
  return degrees * Math.PI / 180;
}

function toDegrees(radians) {
  return radians * 180 / Math.PI;
}

// 概率相关
function probability(percent) {
  return Math.random() < percent / 100;
}

function weightedRandom(weights) {
  const total = weights.reduce((sum, weight) => sum + weight, 0);
  const random = Math.random() * total;
  let sum = 0;
  for (let i = 0; i < weights.length; i++) {
    sum += weights[i];
    if (random < sum) return i;
  }
  return weights.length - 1;
}
3.7.6:Reg正则对象

正则语法不再赘述,这里只说明js中正则对象相关的方法

方法 描述 返回值 是否改变原对象
test(string) 测试是否匹配 boolean
exec(string) 执行匹配搜索 Array/null
String.match(regexp) 字符串匹配 Array/null
String.matchAll(regexp) 匹配所有 Iterator
String.replace(regexp, replacement) 替换匹配文本 string
String.replaceAll(regexp, replacement) 替换所有匹配 string
String.search(regexp) 搜索匹配位置 number
String.split(regexp) 使用正则分割 Array
js 复制代码
// 常用验证正则
const patterns = {
  email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
  phoneCN: /^1[3-9]\d{9}$/,
  phoneUS: /^\+1\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/,
  url: /^(https?:\/\/)?([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?$/,
  ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
  strongPassword: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
  dateYYYYMMDD: /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/,
  hexColor: /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/,
  username: /^[a-zA-Z0-9_]{3,20}$/,
};

// 正则工具函数
function testPattern(pattern, text) {
  return pattern.test(text);
}

function extractMatches(pattern, text) {
  const matches = [];
  let match;
  while ((match = pattern.exec(text)) !== null) {
    matches.push(match[0]);
  }
  return matches;
}

function replaceWithCallback(pattern, text, callback) {
  return text.replace(pattern, callback);
}

// 复杂正则示例:提取CSS颜色值
function extractCSSColors(css) {
  const colorPattern = /#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})|rgb\((\d+),\s*(\d+),\s*(\d+)\)|rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)/g;
  return css.match(colorPattern) || [];
}

// 正则构建器(动态创建正则)
function buildRegex(patterns, flags = 'i') {
  const escapedPatterns = patterns.map(p => 
    p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
  );
  return new RegExp(`(?:${escapedPatterns.join('|')})`, flags);
}
3.7.7:Error错误对象

表示运行时错误,用于异常处理

先了解下错误的类型:

类型 描述 触发场景
Error 通用错误 自定义错误
SyntaxError 语法错误 代码语法问题
TypeError 类型错误 类型不匹配
ReferenceError 引用错误 未定义变量
RangeError 范围错误 数值超出范围
URIError URI错误 URI处理错误
EvalError eval错误 eval函数错误
AggregateError 聚合错误 多个错误集合
下面的都是Error的子对象类型

核心属性:name / message / stack / cause

看了下面的使用例子就知道如何处理错误对象了,要么就是throw出去,要么就是try...catch住,然后对catch块处理

js 复制代码
// 基础错误处理
try {
  // 可能出错的代码
  throw new Error('Something went wrong');
} catch (error) {
  console.error('错误名称:', error.name);
  console.error('错误信息:', error.message);
  console.error('堆栈跟踪:', error.stack);
  // 处理错误
} finally {
  // 无论是否出错都会执行
  console.log('清理工作');
}

// 自定义错误类型
class ValidationError extends Error {
  constructor(message, field) {
    super(message);
    this.name = 'ValidationError';
    this.field = field;
    this.timestamp = new Date().toISOString();
  }
  
  // 原型方法
  toJSON() {
    return {
      name: this.name,
      message: this.message,
      field: this.field,
      timestamp: this.timestamp,
      stack: this.stack
    };
  }
}

// 使用自定义错误
function validateUser(user) {
  if (!user.name) {
    throw new ValidationError('姓名不能为空', 'name');
  }
  if (user.age < 0) {
    throw new ValidationError('年龄不能为负数', 'age');
  }
}

// 错误链(ES2022)
function processData(data) {
  try {
    return JSON.parse(data);
  } catch (error) {
    throw new Error('数据处理失败', { cause: error });
  }
}

// 异步错误处理
async function fetchData(url) {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    console.error('获取数据失败:', error);
    throw error; // 重新抛出
  }
}

// Promise错误处理
fetchData('/api/data')
  .then(data => console.log(data))
  .catch(error => console.error('Promise错误:', error));

// 全局错误处理
window.addEventListener('error', (event) => {
  console.error('全局错误:', event.error);
  // 可以发送到错误监控服务
  sendToErrorMonitoring(event.error);
});

// 未处理的Promise拒绝
window.addEventListener('unhandledrejection', (event) => {
  console.error('未处理的Promise拒绝:', event.reason);
});

3.7.8:Json对象

处理JSON结构,非常的简单,核心方法就是两个

方法 描述 返回值
JSON.parse(text[, reviver]) 解析JSON字符串 JavaScript值
JSON.stringify(value[, replacer[, space]]) 转为JSON字符串 string

4:DOM(⭐️⭐️⭐️⭐️⭐️⭐️)

当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。HTML DOM 模型被结构化为 对象树

通过DOM树,JS获得创建动态 HTML 的所有力量

4.1:元素定位(⭐️⭐️⭐️⭐️⭐️⭐️)

只有定位到元素,才能对元素进行操作,因此DOM提供了一系列选择器相关的方法定位HTML元素

方法 描述
document.getElementById(id) 通过元素 id 来查找元素。
document.getElementsByTagName(name) 通过标签名来查找元素
document.getElementsByClassName(name) 通过类名来查找元素
document.querySelector(CSS选择器) 通过CSS选择器选择一个元素
document.querySelectorAll(CSS选择器) 通过CSS选择器选择多个元素
4.2:元素操作(⭐️⭐️)

定位到元素之后,就可以对元素的内容和属性进行操作了

获取HTML元素的值和属性

方法 描述
元素节点.innerText 获取 HTML 元素的 inner Text。
元素节点.innerHTML 获取 HTML 元素的 inner HTML。
元素节点.属性 获取 HTML 元素的属性值。
元素节点.getAttribute([attribute]) 获取 HTML 元素的属性值。
元素节点.style.样式 获取 HTML 元素的行内样式值。

更改HTML元素的值和属性

方法 描述
元素节点.innerText = new text content 改变元素的 inner Text
元素节点.innerHTML = new html content 改变元素的 inner HTML
元素节点.属性 = new value 改变 HTML 元素的属性值
元素节点.setAttribute(attribute, value) 改变 HTML 元素的属性值
元素节点.style.样式 = new style 改变 HTML 元素的行内样式值

增、删、替换HTML元素

方法 描述
document.createElement(element) 创建 HTML 元素节点。
document.createAttribute(attribute) 创建 HTML 属性节点。
document.createTextNode(text) 创建 HTML 文本节点。
元素节点.removeChild(element) 删除 HTML 元素。
元素节点.appendChild(element) 添加 HTML 元素。
元素节点.replaceChild(element) 替换 HTML 元素。
元素节点.insertBefore(element) 在指定的子节点前面插入新的子节点。

定位关联元素

方法 描述
元素节点.parentNode 返回元素的父节点。
元素节点.parentElement 返回元素的父元素。
元素节点.childNodes 返回元素的一个子节点的数组(包含空白文本Text节点)。
元素节点.children 返回元素的一个子元素的集合(不包含空白文本Text节点)。
元素节点.firstChild 返回元素的第一个子节点(包含空白文本Text节点)。
元素节点.firstElementChild 返回元素的第一个子元素(不包含空白文本Text节点)。
元素节点.lastChild 返回元素的最后一个子节点(包含空白文本Text节点)。
元素节点.lastElementChild 返回元素的最后一个子元素(不包含空白文本Text节点)。
元素节点.previousSibling 返回某个元素紧接之前节点(包含空白文本Text节点)。
元素节点.previousElementSibling 返回指定元素的前一个兄弟元素(相同节点树层中的前一个元素节点)。
元素节点.nextSibling 返回某个元素紧接之后节点(包含空白文本Text节点)。
元素节点.nextElementSibling 返回指定元素的后一个兄弟元素(相同节点树层中的下一个元素节点)。
js 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="box">
    <ul id="ul">
        <li><a href="https://www.baidu.com">我是超链接1</a></li>
        <li id="two"><a href="https://www.baidu.com">我是超链接2</a></li>
        <li><a href="https://www.baidu.com">我是超链接3</a></li>
        <li><a href="https://www.baidu.com">我是超链接4</a></li>
    </ul>
</div>

<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
    var box = document.getElementById("box");
    var ul = document.getElementById("ul");
    var two = document.getElementById("two");

    console.log(ul.parentNode);
    console.log(ul.parentElement);
    console.log("===============");

    console.log(box.childNodes);
    console.log(box.children);
    console.log("===============");

    console.log(ul.firstChild);
    console.log(ul.firstElementChild);
    console.log(ul.lastChild);
    console.log(ul.lastElementChild);
    console.log("===============");

    console.log(two.previousSibling);
    console.log(two.previousElementSibling);
    console.log(two.nextSibling);
    console.log(two.nextElementSibling);
</script>
</body>
</html>
4.3:事件响应(⭐️⭐️⭐️⭐️⭐️⭐️)

HTML事件可以触发浏览器中的行为,比方说当用户点击某个 HTML 元素时启动一段 JavaScript。

这个才是实际开发中经常使用的!!!

4.3.1:窗口事件

由窗口触发该事件 (同样适用于 <body> 标签):

属性 描述
onblur 当窗口失去焦点时运行脚本。
onfocus 当窗口获得焦点时运行脚本。
onload 当文档加载之后运行脚本。
onresize 当调整窗口大小时运行脚本。
onstorage 当 Web Storage 区域更新时(存储空间中的数据发生变化时)运行脚本。
4.3.2:表单事件(⭐️⭐️⭐️⭐️⭐️)

单事件在HTML表单中触发 (适用于所有 HTML 元素,但该HTML元素需在form表单内):

属性 描述
onblur 当元素失去焦点时运行脚本。
onfocus 当元素获得焦点时运行脚本。
onchange 当元素改变时运行脚本。
oninput 当元素获得用户输入时运行脚本。
oninvalid 当元素无效时运行脚本。
onselect 当选取元素时运行脚本。
onsubmit 当提交表单时运行脚本。
html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<form>
    <input type="text" id="text">
</form>

<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
    var textInput = document.getElementById("text");

    /* 当文本框获取焦点,文本框背景为红色 */
    textInput.onfocus = function () {
        this.style.background = "red";
    };

    /* 当文本框失去焦点,文本框背景为绿色 */
    textInput.onblur = function () {
        this.style.background = "green";
    };
</script>
</body>
</html>
4.3.3:键盘事件
属性 描述
onkeydown 当按下按键时运行脚本。
onkeyup 当松开按键时运行脚本。
onkeypress 当按下并松开按键时运行脚本。
html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
    /* 当键盘按下判断当前的按键是不是 a ,如果是就输出true,否则输出false */
    window.onkeydown = function (event) {
        /* 解决兼容性问题 */
        event = event || window.event;

        if (event.keyCode == 65) {
            console.log("true");
        } else {
            console.log("false");
        }
    };
</script>
</body>
</html>
4.3.4:事件对象event(⭐️⭐️⭐️⭐️⭐️⭐️)

概述

Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标的状态

事件对象 (event):在事件处理程序中传递的参数,包含与事件相关的所有信息。

主要用途:

  • 获取事件类型、目标元素、鼠标位置、键盘按键等。
  • 控制事件的传播和默认行为。

常见属性:

  • event.type:事件类型。
  • event.targetevent.currentTarget:事件目标。
  • event.clientXevent.clientY:鼠标位置。
  • event.button:鼠标按钮。
  • event.keyevent.code:键盘按键。
  • event.stopPropagation()event.preventDefault():控制事件传播和默认行为。

在IE8中,响应函数被触发时,浏览器不会传递事件对象,在IE8及以下的浏览器中,是将事件对象作为window对象的属性保存的。

解决事件对象的兼容性问题:event = event || window.event;

事件冒泡

事件的冒泡(Bubble):所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发,在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡。

js 复制代码
function stopBubble(event) {
        // 如果提供了事件对象,则这是一个非IE浏览器
        if (event && event.stopPropagation) {
            // 因此它支持W3C的stopPropagation()方法
            event.stopPropagation();
        } else {
            // 否则,我们需要使用IE的方式来取消事件冒泡
            window.event.cancelBubble = true;
        }
    }
html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        #div1 {
            width: 200px;
            height: 200px;
            background: pink;
        }

        #div2 {
            width: 100px;
            height: 100px;
            background: coral;
        }
    </style>
</head>
<body>
<div id="div1">
    我是DIV1
    <div id="div2">
        我是DIV2
    </div>
</div>

<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
    var div1 = document.getElementById("div1");
    var div2 = document.getElementById("div2");

    // 为div1绑定单击事件
    div1.onclick = function () {
        console.log("div1 的单击事件触发了!");
        stopBubble();
    };

    // 为div2绑定单击事件
    div2.onclick = function () {
        console.log("div2 的单击事件触发了!");
        stopBubble();
    };

    // 取消事件冒泡
    function stopBubble(event) {
        // 如果提供了事件对象,则这是一个非IE浏览器
        if (event && event.stopPropagation) {
            // 因此它支持W3C的stopPropagation()方法
            event.stopPropagation();
        } else {
            // 否则,我们需要使用IE的方式来取消事件冒泡
            window.event.cancelBubble = true;
        }
    }
</script>
</body>
</html>

事件委派

反之,我们可以利用事件的冒泡,完成事件的委派

所谓事件的委派,是指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件。

当我们希望只绑定一次事件,即可应用到多个的元素上,即使元素是后添加的,我们可以尝试将其绑定给元素的共同的祖先元素,这样通过冒泡到祖先元素,就可以通过祖先元素的响应函数来处理事件

事件委派是利用了事件冒泡,通过委派可以减少事件绑定的次数,提高程序的性能。

js 复制代码
<!-- 为ul列表中的所有a标签都绑定单击事件 -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<ul id="u1">
    <li><a href="javascript:;" class="link">超链接一</a></li>
    <li><a href="javascript:;" class="link">超链接二</a></li>
    <li><a href="javascript:;" class="link">超链接三</a></li>
</ul>

<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
    var u1 = document.getElementById("u1");

    // 为ul绑定一个单击响应函数
    u1.onclick = function (event) {
        event = event || window.event;
        // 如果触发事件的对象是我们期望的元素,则执行,否则不执行
        if (event.target.className == "link") {
            console.log("我是ul的单击响应函数");
        }
    };
</script>
</body>
</html>

事件解绑

我们以前绑定事件代码只能一个事件绑定一个函数,那我们要是想一个事件对应多个函数,并且不存在兼容性的问题该如何解决呢?

此时就可以写两个公共方法,一个用于事件的绑定,一个用于事件的解绑

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<button id="btn1">按钮1</button>
<button id="btn2">按钮2</button>

<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
    function f1() {
        console.log("output1 ...");
    };

    function f2() {
        console.log("output2 ...");
    };

    // 为按钮1的单击事件绑定两个函数
    addEventListener(document.getElementById("btn1"), "click", f1);
    addEventListener(document.getElementById("btn1"), "click", f2);

    // 点击按钮2取消按钮1的单机事件绑定函数f1
    document.getElementById("btn2").onclick = function () {
        removeEventListener(document.getElementById("btn1"), "click", f1);
    };

    /*为元素绑定事件兼容性代码*/
    function addEventListener(element, type, fn) {
        if (element.addEventListener) {
			 // 如果希望在捕获阶段就触发事件,这里的第三个参数设置为true
            element.addEventListener(type, fn, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, fn);
        } else {
            element["on" + type] = fn;
        }
    }

    /*为元素解绑事件兼容性代码*/
    function removeEventListener(element, type, fnName) {
        if (element.removeEventListener) {
            element.removeEventListener(type, fnName, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, fnName);
        } else {
            element["on" + type] = null;
        }
    }
</script>
</body>
</html>

事件传播

W3C将事件传播分成了三个阶段:

  • 捕获阶段:在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
  • 目标阶段:事件捕获到目标元素,捕获结束开始在目标元素上触发事件
  • 冒泡阶段:事件从目标元素向它的祖先元素传递,依次触发祖先元素上的事件

如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true

一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false

4.3.5:鼠标事件(⭐️⭐️⭐️⭐️⭐️⭐️)
属性 描述
onclick 当单击鼠标时运行脚本
ondblclick 当双击鼠标时运行脚本。
onmousedown 当按下鼠标按钮时运行脚本。
onmouseup 当松开鼠标按钮时运行脚本。
onmousemove 当鼠标指针移动时运行脚本。
onmouseover 当鼠标指针移至元素之上时运行脚本,不可以阻止冒泡。
onmouseout 当鼠标指针移出元素时运行脚本,不可以阻止冒泡。
onmouseenter 当鼠标指针移至元素之上时运行脚本,可以阻止冒泡。
onmouseleave 当鼠标指针移出元素时运行脚本,可以阻止冒泡。
onmousewheel 当转动鼠标滚轮时运行脚本。
onscroll 当滚动元素的滚动条时运行脚本。
4.3.6:媒体事件

通过视频(videos),图像(images)或音频(audio) 触发该事件。

事件名称 触发时机 使用场景
onplay(⭐️) 媒体开始播放时触发 播放状态跟踪,记录播放开始时间
onpause(⭐️) 媒体暂停时触发 暂停状态跟踪,暂停时保存播放位置
onended(⭐️) 媒体播放到结尾时触发 播放结束时自动播放下一个或显示结束界面
ontimeupdate(⭐️) 媒体当前播放位置改变时触发(每秒触发4-10次) 更新进度条、显示当前播放时间
onloadedmetadata(⭐️) 媒体元数据(时长、尺寸等)加载完成时触发 获取视频/音频总时长、分辨率等信息
onloadeddata 当前帧的媒体数据加载完成时触发 媒体可以开始播放时初始化播放器
oncanplay 媒体可以开始播放时触发(可能有缓冲) 启用播放按钮,或触发自动播放
onvolumechange 媒体音量改变或被设置为静音时触发 更新音量控制UI,同步静音状态
onerror(⭐️) 媒体加载或播放过程中发生错误时触发 错误处理,显示错误提示信息
onwaiting 媒体因缓冲而暂停播放(等待数据)时触发 显示加载动画,提示用户正在缓冲
onplaying 媒体实际开始播放时触发 与onplay配合,确认媒体正在播放
onseeking 用户开始手动跳转播放位置时触发 显示跳转中的状态提示
onseeked 用户跳转播放位置完成时触发 隐藏跳转提示,恢复播放
js 复制代码
const video = document.getElementById('myVideo');

video.onplay = () => console.log('开始播放');
video.onpause = () => console.log('已暂停');
video.onended = () => console.log('播放结束');

// 进度条更新(核心功能)
video.ontimeupdate = () => {
  const progress = (video.currentTime / video.duration) * 100;
  progressBar.style.width = `${progress}%`;
};

// 获取视频信息
video.onloadedmetadata = () => {
  console.log(`时长: ${video.duration}秒`);
  console.log(`分辨率: ${video.videoWidth}x${video.videoHeight}`);
};

5:BOM

浏览器对象模型(BOM)可以使我们通过JS来操作浏览器,在BOM中为我们提供了一组对象,用来完成对浏览器的操作

这些BOM对象在浏览器中都是作为window对象的属性保存的,可以通过window对象来使用,也可以直接使用

5.1:全局对象window

弹出框,警告框和提示框

  • 警告框 -> window.alert(警告信息)
  • 确认框 -> window.confirm(确认信息)
  • 提示框 -> window.prompt("提示信息", 默认值)

定时事件(⭐️⭐️⭐️⭐️⭐️)

JavaScript 可以在时间间隔内执行,这就是所谓的定时事件(Timing Events)。

window 对象允许以指定的时间间隔执行代码,这些时间间隔称为定时事件。

js 复制代码
setTimeout(function, milliseconds) // 在等待指定的毫秒数后执行函数。
setInterval(function, milliseconds) // 等同于 setTimeout(),但持续重复执行该函数。


// 例如
// 在按钮按下之后3s控制台打印Hello
btn.onclick = function () {
        // 创建延时器
        var timer = setTimeout(function () {
            console.log("Hello");
        }, 3000);
}

// 在按钮按下之后每过1s控制台打印Hello
btn.onclick = function () {
    // 创建定时器
    var timer = setInterval(function () {
        console.log("Hello");
    }, 1000);

    // 清除定时器
    // clearInterval(timer);
};

其他常用属性和方法

属性、方法 说明
window.innerHeight/window.innerWidth 浏览器窗口的内高度/宽度
window.open(url, name, specs, replace) 打开新的窗口
window.close() 关闭当前的窗口
window.removeTo(x, y) 移动当前的窗口到(x, y)
window.resizeTo(w, h) 调整当前窗口
5.2:浏览器信息

Navigator对象中的大部分属性都已经不能帮助我们识别浏览器了,一般我们只会使用userAgent来判断浏览器的信息

js 复制代码
let ua = navigator.userAgent;
5.3:地址栏信息

Location对象中封装了浏览器的地址栏的信息,如果直接打印location,则可以获取到地址栏的信息

js 复制代码
console.log(location);          //输出location对象
console.log(location.href);     //输出当前地址的全路径地址
console.log(location.origin);   //输出当前地址的来源
console.log(location.protocol); //输出当前地址的协议
console.log(location.hostname); //输出当前地址的主机名
console.log(location.host);     //输出当前地址的主机
console.log(location.port);     //输出当前地址的端口号
console.log(location.pathname); //输出当前地址的路径部分
console.log(location.search);   //输出当前地址的?后边的参数部分

// assign():用来跳转到其它的页面,作用和直接修改location一样
location.assign("https://www.baidu.com");

// reload():用于重新加载当前页面,作用和刷新按钮一样
// 如果在方法中传递一个true,作为参数,则会强制清空缓存刷新页面
location.reload(true);

// replace():可以使用一个新的页面替换当前页面,调用完毕也会跳转页面
// 它不会生成历史记录,不能使用回退按钮回退
location.replace("https://www.baidu.com")
5.4:历史信息

主要是对历史信息向前翻页,向后翻页,跳转到某一个历史记录

js 复制代码
// back():可以回退到上一个页面,作用和浏览器的回退按钮一样
history.back();

// forward():可以跳转到下一个页面,作用和浏览器的前进按钮一样
history.forward();

// go():可以用来跳转到指定的页面,它需要一个整数作为参数
// 1:表示向前跳转一个页面,相当于forward()
// 2:表示向前跳转两个页面
// -1:表示向后跳转一个页面,相当于back()
// -2:表示向后跳转两个页面
history.go(3);

6:存储部分

6.1:cookie

Cookie 是一些数据,存储于你电脑上的文本文件中,当 web 服务器向浏览器发送 web 页面时,在连接关闭后,服务端不会记录用户的信息,Cookie 的作用就是用于解决 "如何记录客户端的用户信息":

  • 当用户访问 web 页面时,它的名字可以记录在 cookie 中。
  • 在用户下一次访问该页面时,可以在 cookie 中读取用户访问记录。

JavaScript 可以使用 document.cookie 属性来创建 、读取、及删除 Cookie。

js 复制代码
// 设置和读取
document.cookie = "username=zhangsan";
let cookies = document.cookie; // 拿到cookie
console.log(cookies);

// 修改,同名key覆盖
document.cookie = "username=zhangsan";
document.cookie = "username=lisi"; // 同名key覆盖,value变成lisi
var cookies = document.cookie;
console.log(cookies);
js 复制代码
/**
 * Cookie值设置函数
 * @param cname     cookie名称
 * @param cvalue    cookie值
 * @param exdays    过期天数
 */
function setCookie(cname, cvalue, exdays) {
    // 创建一个时间对象并设置值
    var d = new Date();
    d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
    // 过期时间就是这个时间对象的GMT格式
    var expires = "expires=" + d.toGMTString();
    // 设置cookie
    document.cookie = cname + "=" + cvalue + "; " + expires;
}


/**
 * Cookie值获取函数
 * @param cname     cookie名称
 * @returns {string}
 */
function getCookie(cname) {
    var name = cname + "=";
    // 将cookie通过;分割,得到每一个cookie
    var ca = document.cookie.split(';');
    // 遍历所有的cookie
    for (var i = 0; i < ca.length; i++) {
        // 前后去除空格
        var c = ca[i].trim();
        // 如果找到了对应的key
        if (c.indexOf(name) == 0) {
            // 通过截取,拿到value
            return c.substring(name.length, c.length);
        }
    }
    // 否则返回空串
    return "";
}
6.2:webStorage

虽然WebStorage是HTML5新增的本地存储解决方案之一,但并不是为了取代Cookie而制定的标准

Cookie作为HTTP协议的一部分用来处理客户端和服务器通信是不可或缺的,session正是依赖于实现的客户端状态保持。

WebStorage的意图在于解决本来不应该Cookie做,却不得不用Cookie的本地存储的应用场景。

localStorage和sessionStorage只能存储字符串类型

localStorage在本地永久性存储数据,除非显式将其删除或清空。

方法 说明
localStorage.setItem(key,value); 保存单个数据
localStorage.getItem(key); 读取单个数据
localStorage.removeItem(key); 删除单个数据
localStorage.clear(); 删除所有数据
localStorage.key(index); 获取某个索引的key
js 复制代码
// 保存数据
localStorage.setItem("username", "zhangsan");

// 读取单个数据
console.log(localStorage.getItem("username")); // zhangsan
console.log("===============");

// 删除单个数据
localStorage.removeItem("username");
console.log(localStorage.getItem("username")); // null
console.log("===============");

// 保存两个数据
localStorage.setItem("age", 18);
localStorage.setItem("sex", "男");
console.log("age=" + localStorage.getItem("age")); // 18
console.log("sex=" + localStorage.getItem("sex")); // 男
console.log("===============");

// 使用for-in循环来迭代localStorage中的键值对、属性和方法:
for (let key in localStorage) {
    console.log(key + "=" + localStorage[key]);
}
console.log("===============");

// 使用for循环来迭代localStorage中的键值对:
for (let i = 0; i < localStorage.length; i++) {
    let key = localStorage.key(i);
    let value = localStorage.getItem(key);
    console.log(key + "=" + value);
}
console.log("===============");

// 删除所有数据
localStorage.clear();

7:其他新特性说明

7.1:变量解构赋值
js 复制代码
//数组的解构赋值
const arr = ["张学友", "刘德华", "黎明", "郭富城"];
let [zhang, liu, li, guo] = arr; // 取了个别名
console.log(zhang); // "张学友"
console.log(liu); // "刘德华"
console.log(li); // "黎明"
console.log(guo); // "郭富城"

//对象的解构赋值
const lin = {
    name: "林志颖",
    tags: ["车手", "歌手", "小旋风", "演员"]
};
let {name, tags} = lin;
console.log(name); // 林志颖
console.log(tags); // ["车手", "歌手", "小旋风", "演员"]
7.2:箭头函数

箭头函数的注意点:

  • 如果形参只有一个,则小括号可以省略
  • 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果
  • 箭头函数 this 指向声明时所在作用域下 this 的值,箭头函数不会更改 this 指向,用来指定回调函数会非常合适
  • 箭头函数不能作为构造函数实例化
  • 不能使用 arguments 实参
js 复制代码
let fn = (arg1, arg2, arg3) => {
    return arg1 + arg2 + arg3;
}

// this 指向声明时所在作用域中 this 的值
let fn = () => {
    console.log(this); // window
}
fn();

let school = {
    name: "张三",
    getName() {
        let subFun = () => {
            console.log(this); // {name: "张三", getName: f}
        }
        subFun();
    }
};
school.getName(); 
7.3:rest参数和spread扩展运算符

rest 参数非常适合不定个数参数函数的场景

js 复制代码
// 作用与 arguments 类似
function add(...args) {
    console.log(args); // [1, 2, 3, 4, 5]
}
add(1, 2, 3, 4, 5);

// rest 参数必须是最后一个形参
function minus(a, b, ...args) {
    console.log(a, b, args); // 100 1 [2, 3, 4, 5, 19]
}

minus(100, 1, 2, 3, 4, 5, 19);

扩展运算符(spread)也是三个点(...)

它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。

js 复制代码
// 展开数组
let tfboys = ["德玛西亚之力", "德玛西亚之翼", "德玛西亚皇子"];
function fn() {
    console.log(arguments);
}
fn(...tfboys);
7.4:Symbol唯一性值

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值

它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型,Symbol 特点如下:

  • Symbol 的值是唯一的,用来解决命名冲突的问题
  • Symbol 值不能与其它数据进行运算
  • Symbol 定义的对象属性不能使用 for...in 循环遍 历 ,但是可以使用 Reflect.ownKeys 来获取对象的所有键名
js 复制代码
//创建 Symbol
let s1 = Symbol();
console.log(s1); // Symbol()
console.log(typeof s1); // symbol

//添加标识的 Symbol
let s2 = Symbol("张三");
let s2_2 = Symbol("张三");
console.log(s2); // Symbol(张三)
console.log(s2_2); // Symbol(张三)
console.log(s2 === s2_2); // false

//使用 Symbol for 定义
let s3 = Symbol.for("张三");
let s3_2 = Symbol.for("张三");
console.log(s3); //Symbol(张三)
console.log(s3_2); // Symbol(张三)
console.log(s3 === s3_2); // true

//在方法中使用 Symbol
let game = {
    name: "狼人杀",
    [Symbol('say')]: function () {
        console.log("我可以发言")
    },
    [Symbol('zibao')]: function () {
        console.log('我可以自爆');
    }
};
console.log(game);
7.5:Promise异步(⭐️⭐️⭐️⭐️)

语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果

常用于调用后端接口

js 复制代码
// 模拟调用后端接口的函数,返回一个 Promise
function fetchDataFromAPI(url) {
  return new Promise((resolve, reject) => {
    // 模拟异步请求
    setTimeout(() => {
      const mockResponse = {
        status: 200,
        data: {
          id: 1,
          name: '张三',
          email: 'zhangsan@example.com'
        }
      };
      
      // 模拟成功响应
      if (url === '/api/user') {
        resolve(mockResponse); // 状态变为 Fulfilled
      } else {
        // 模拟错误
        reject(new Error('404: 接口未找到')); // 状态变为 Rejected
      }
    }, 1000); // 模拟网络延迟
  });
}

// 使用 Promise 调用接口
fetchDataFromAPI('/api/user')
  // fulfilled状态下的入口,参数是resolve中的参数mockResponse
  .then((response) => {
    console.log('请求成功:', response);
    
    // 处理响应数据
    const userData = response.data;
    console.log('用户数据:', userData);
    console.log(`用户名: ${userData.name}, 邮箱: ${userData.email}`);
    
    // 返回处理后的数据,供下一个 then 使用
    return userData;
  })
  // 链式调用,参数是上一个then的return
  .then((userData) => {
    // 链式调用,进一步处理数据
    console.log('数据进一步处理完成:', userData);
  })
  // rejected状态下的入口,参数是reject的参数
  .catch((error) => {
    // 捕获所有错误
    console.error('请求失败:', error.message);
  })
  .finally(() => {
    // 无论成功或失败都会执行
    console.log('请求结束,清理工作...');
  });

调用 then 方法,then 方法的返回结果是 Promise 对象,对象状态由回调函数的执行结果决定,如果回调函数中返回的结果是 非 promise 类型的属性,状态为成功,返回值为对象的成功的值

如果只想处理错误状态,我们可以使用 catch 方法

Promise的静态方法

  • Promise.all() - 等待所有 Promise 完成
  • Promise.race() - 竞速,第一个完成或失败的
  • Promise.allSettled() - 等待所有 Promise 完成(无论成功失败)
  • Promise.any() - 第一个成功的 Promise
  • Promise.resolve() 和 Promise.reject()
js 复制代码
// 同时调用多个接口,等待所有都完成
const promise1 = fetch('/api/user');
const promise2 = fetch('/api/orders');
const promise3 = fetch('/api/settings');

Promise.all([promise1, promise2, promise3])
  .then(([userData, ordersData, settingsData]) => {
    console.log('所有数据加载完成');
    console.log('用户:', userData);
    console.log('订单:', ordersData);
    console.log('设置:', settingsData);
  })
  .catch(error => {
    console.error('有一个请求失败了:', error);
    // 只要有一个失败,整个 Promise.all 就失败
  });

// 实际示例
const userId = 1;
Promise.all([
  getUserInfo(userId),
  getUserOrders(userId),
  getUserMessages(userId)
])
.then(([info, orders, messages]) => {
    // 所有数据都已获取
    renderUserProfile(info, orders, messages);
});
7.6:模块化(export / import)

想象一下你的代码是一个工具箱:

  • export = 把工具放到工具箱外面让别人用
  • import = 从别人的工具箱里拿工具用
  • 以前所有工具堆在一起,现在分门别类放好,用的时候再拿
js 复制代码
// math.js - 导出模块
// 方式1:命名导出(可以导出多个)
export const PI = 3.14159;
export function add(a, b) {
  return a + b;
}
export function multiply(a, b) {
  return a * b;
}

// 方式2:默认导出(一个文件只能有一个)
const calculator = {
  add,
  multiply,
  PI
};
export default calculator;

// main.js - 导入模块
// 导入命名导出
import { PI, add } from './math.js';
console.log(PI); // 3.14159
console.log(add(2, 3)); // 5

// 导入默认导出
import calc from './math.js';
console.log(calc.multiply(2, 3)); // 6

// 导入全部
import * as MathUtils from './math.js';
console.log(MathUtils.PI); // 3.14159
7.7:async和await
  • 异步 = "你先忙,我继续干别的,你好了叫我"
  • async/await = "我先暂停,等你好了我再继续"(代码看起来像同步,实际是异步)
  • 让异步代码读起来像同步代码一样简单
js 复制代码
// 传统 Promise 写法(回调地狱的解决方案)
function fetchData() {
  return fetch('https://api.example.com/data')
    .then(response => response.json())
    .then(data => {
      console.log(data);
      return data;
    })
    .catch(error => {
      console.error('Error:', error);
    });
}

// async/await 写法(更直观)
async function fetchDataWithAsync() {
  try {
    // await = "等待这个操作完成"
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    console.log(data);
    return data;
  } catch (error) {
    console.error('Error:', error);
  }
}

// 实际使用示例
async function getUserAndPosts(userId) {
  // 顺序执行,第二个等第一个完成
  const user = await fetch(`/api/users/${userId}`);
  const posts = await fetch(`/api/users/${userId}/posts`);
  
  // 并行执行,同时发起请求
  const [userData, postsData] = await Promise.all([
    user.json(),
    posts.json()
  ]);
  
  return { user: userData, posts: postsData };
}

// async 函数总是返回 Promise
fetchDataWithAsync().then(result => {
  console.log('Got result:', result);
});

8:后端交互axios

  • axios = 专业的快递小哥,专门帮你发送和接收数据
  • 比浏览器自带的 fetch 更好用(自动转换JSON、错误处理等)
  • 可以设置统一的规则(比如所有请求都带上认证信息)
8.1:axios请求方式((⭐️⭐️⭐️⭐️⭐️)
js 复制代码
import axios from 'axios';

// 1. GET 请求(获取数据)
axios.get('https://api.example.com/users')
  .then(response => {
    console.log(response.data); // 服务器返回的数据
  })
  .catch(error => {
    console.error('请求失败:', error);
  });

// 2. POST 请求(提交数据)
axios.post('https://api.example.com/users', {
  name: '张三',
  age: 25
})
  .then(response => {
    console.log('创建成功:', response.data);
  });

// 3. PUT 请求(更新整个资源)
axios.put('https://api.example.com/users/1', {
  name: '张三',
  age: 26  // 更新年龄
});

// 4. PATCH 请求(更新部分资源)
axios.patch('https://api.example.com/users/1', {
  age: 26  // 只更新年龄字段
});

// 5. DELETE 请求(删除数据)
axios.delete('https://api.example.com/users/1');

// 6. 并发请求(同时发送多个请求)
axios.all([
  axios.get('/api/users'),
  axios.get('/api/posts')
])
  .then(axios.spread((usersRes, postsRes) => {
    console.log('Users:', usersRes.data);
    console.log('Posts:', postsRes.data);
  }));
8.2:axios实例
js 复制代码
// 创建自定义实例(统一配置)
const apiClient = axios.create({
  baseURL: 'https://api.example.com',  // 基础URL
  timeout: 5000,  // 5秒超时
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer your-token-here'
  }
});

// 使用实例发送请求
apiClient.get('/users');  // 实际请求:https://api.example.com/users
apiClient.post('/login', {
  username: 'admin',
  password: '123456'
});

// 不同API使用不同实例
const authApi = axios.create({
  baseURL: 'https://auth.example.com',
  timeout: 3000
});

const dataApi = axios.create({
  baseURL: 'https://data.example.com',
  timeout: 10000
});
8.3:拦截器
js 复制代码
// 请求拦截器(发送请求前做点什么)
axios.interceptors.request.use(
  config => {
    // 在发送请求前
    console.log('正在发送请求:', config.url);
    
    // 添加token到请求头
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    
    // 可以修改请求配置
    config.headers['X-Custom-Header'] = 'custom-value';
    
    return config;  // 必须返回配置
  },
  error => {
    // 请求错误处理
    console.error('请求出错:', error);
    return Promise.reject(error);
  }
);

// 响应拦截器(收到响应后做点什么)
axios.interceptors.response.use(
  response => {
    // 2xx 状态码触发
    console.log('收到响应:', response.status);
    
    // 统一处理数据格式
    if (response.data.code === 0) {
      return response.data.data;  // 直接返回业务数据
    } else {
      // 业务错误
      return Promise.reject(new Error(response.data.message));
    }
  },
  error => {
    // 超出 2xx 状态码触发
    console.error('响应错误:', error.response?.status);
    
    // 统一错误处理
    if (error.response?.status === 401) {
      // token过期,跳转到登录页
      window.location.href = '/login';
    } else if (error.response?.status === 404) {
      console.error('接口不存在');
    } else if (error.response?.status === 500) {
      console.error('服务器错误');
    }
    
    return Promise.reject(error);
  }
);

// 移除拦截器
const requestInterceptor = axios.interceptors.request.use(config => config);
axios.interceptors.request.eject(requestInterceptor);
相关推荐
人工智能训练4 小时前
【极速部署】Ubuntu24.04+CUDA13.0 玩转 VLLM 0.15.0:预编译 Wheel 包 GPU 版安装全攻略
运维·前端·人工智能·python·ai编程·cuda·vllm
会跑的葫芦怪5 小时前
若依Vue 项目多子路径配置
前端·javascript·vue.js
pas1368 小时前
40-mini-vue 实现三种联合类型
前端·javascript·vue.js
摇滚侠8 小时前
2 小时快速入门 ES6 基础视频教程
前端·ecmascript·es6
珑墨8 小时前
【Turbo】使用介绍
前端
军军君019 小时前
Three.js基础功能学习十三:太阳系实例上
前端·javascript·vue.js·学习·3d·前端框架·three
打小就很皮...10 小时前
Tesseract.js OCR 中文识别
前端·react.js·ocr
wuhen_n10 小时前
JavaScript内存管理与执行上下文
前端·javascript
Hi_kenyon11 小时前
理解vue中的ref
前端·javascript·vue.js
落霞的思绪12 小时前
配置React和React-dom为CDN引入
前端·react.js·前端框架