Web三件套学习笔记
<!-- HTML -->
HTML是超文本标记语言
1、html
常用标签
块级标签
-
独占一行
-
可以设置宽度,高度,margin,padding
-
宽度默认所在容器的宽度
标签 | 作用 |
---|---|
table | 定义表格 |
h1 ~ h6 | 定义标题 |
hr | 定义一条水平线 |
p | 定义段落 |
li | 标签定义列表项目 |
ul | 定义无序列表 |
ol | 定义有序列表 |
div | 定义文档中的分区或节 |
form | 创建 HTML 表单 |
table标签
<table border="1" cellpadding="0" cellspacing="0" width="500" height="249"> <thead > <tr> <th>序号</th> <th>name</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>枫枫</td> </tr> <tr> <td>2</td> <td>张三</td> </tr> </tbody> </table> <!--align属性名,属性值为left center right,规定表格相对周围元素的对齐方式--> <!--border属性名,属性值1或"",规定表格是否有边框,默认为"",表示没有边框--> <!--cellpadding属性名,属性值像素值,单元格内容和边框之间的空白,默认为1--> <!--cellspacing属性名,属性值像素值,单元格和单元格之间的距离,默认为2--> <!--width属性名,属性值像素值或百分比,规定表格的宽度--> <!--height属性名,属性值像素值或百分比,规定表格的高度-->
列表标签
有缩进 有序标签可以通过type属性设置
<!-- 可以选择:i A 1 a I --> <ol type="I"><li>有序</li><li>标签</li></ol>
form标签
<form action="/xxx" method="get" name="form1"> <!-- action提交地址 method提交方式--> <input name="name"> <input value="提交" type="submit"/> <input type="submit">提交</form> <input value="重置" type="reset"/> </form>
属性 | 描述 |
---|---|
accept-charset | 规定在被提交表单中使用的字符集(默认:页面字符集) |
action | 规定向何处提交表单的地址(URL)(提交页面) |
autocomplete | 规定浏览器应该自动完成表单(默认:开启) |
enctype | 规定被提交数据的编码(默认:url-encoded ) |
method | 规定在提交表单时所用的 HTTP 方法(默认:GET) |
name | 规定识别表单的名称(对于 DOM 使用:document.forms.name ) |
novalidate | 规定浏览器不验证表单 |
target | 规定 action 属性中地址的目标(默认:_self) |
行内标签
-
与其他行内元素并排
-
设置宽高无效
-
默认的宽度就是文本内容的宽度
-
水平方向的 padding 和 margin 属性可以使用。
-
只能容纳文本级元素和内联元素
标签 | 作用 |
---|---|
a | 标签定义超链接 |
span | 组合文档中的行内元素 |
br | 定义换行 |
b | 定义字体缩写 |
label | 标签 |
表单标签 | input textarea select |
img | 图片 |
a标签
<a href="" target="_blank">新标签页打开</a> <a href="" download>下载</a> <a href="" download="a1.png">会用a1.png作为名字进行下载</a>
target
:
-
_blank
表示在新标签页中打开目标网页 -
_self
表示在当前标签页中打开目标网页
download
:用于下载
input标签
type属性值 | 表现形式 | 对应代码 |
---|---|---|
text | 单行输入文本 | <input type=text" /> |
password | 密码输入框 | |
date | 日期输入框 | |
checkbox | 复选框 | <input type="checkbox" name="sg1" value="pg">苹果 |
radio | 单选框 | <input type="radio" name="sg" value="pg">苹果 |
submit | 提交按钮 | |
reset | 重置按钮 | |
button | 普通按钮 | |
hidden | 隐藏输入框 | |
file | 文本选择框 |
属性说明:
-
name:表单提交时的 键,注意和id的区别
-
value:表单提交时对应项的值
-
type="button", "reset", "submit"时,为按钮上显示的文本内容
-
type="text","password","hidden"时,为输入框的初始值
-
type="
checkbox
", "radio", "file",为输入相关联的值
-
-
checked
:radio
和checkbox
默认被选中的项 -
readonly
:text
和password设置只读 -
disabled:禁用,所有input均适用
label标签中的for属性会和input中的id关联
<label for="user">用户名</label> <input type="text" placeholder="请输入" value="zard" name="name"> <input placeholder="请输入用户名" id="user"> <input type="password"> <label for="file">选择文件</label> <input id="file" style="dispaly: none" type="file">
select(下拉)标签
<select name="user"> <option value="1">枫枫</option> <option value="2">张三</option> <option value="3">王五</option> </select>
可设置 multiple 表示可多选
img
标签
<img src="图片的路径" alt="图片未加载成功时的提示" title="鼠标悬浮时提示信息" width="宽" height="高(宽高两个属性只用一个会自动等比缩放)">
span和div
span是行内标签中的默认标签
div是块级标签中的默认标签
方便去通过css
设置样式
2、相对路径与绝对路径
文件的相对路径和绝对路径
相对路径 <img src="./avatar.png" alt=""> <img src="avatar.png" alt=""> 绝对路径 <img src="G:\IT\前端项目\qianduan_study\html\avatar.png" alt="">
web中相对路径和绝对路径
相对路径 <form action="xxx"> <input type="submit" value="提交"> </form> 绝对路径 <form action="/xxx"> <input type="submit" value="提交"> </form>
// 相对路径 http://localhost:63342/qianduan_study/html/4.%E7%9B%B8%E5%AF%B9%E8%B7%AF%E5%BE%84%E5%92%8C%E7%BB%9D%E5%AF%B9%E8%B7%AF%E5%BE%84.html 提交 地址 变成了 http://localhost:63342/qianduan_study/html/xxx?
// 绝对路径 http://localhost:63342/qianduan_study/html/4.%E7%9B%B8%E5%AF%B9%E8%B7%AF%E5%BE%84%E5%92%8C%E7%BB%9D%E5%AF%B9%E8%B7%AF%E5%BE%84.html 提交 地址 变成了 http://localhost:63342/xxx?
<!-- css -->
css
引入方式
-
外部引入
-
<link rel="stylesheet" href="index.css">
-
-
内部样式
-
行内样式
层叠样式表
-
优先级(权重最重要)
-
同级后面的会覆盖前面的
1、css
选择器
id选择器
特点:id是唯一的,不能重复
<div id="box"></div> #box{}
类选择器
<div class="box"></div> .box{}
标签选择器
<div id="box"></div> div{}
属性选择器 []
<div id="box" ></div> <a href="https://www.baidu.com"></a> div[id="box"]{} a[href]{} a[href="https://www.baidu.com"]{}
通用选择器
给网页元素做一些通用的样式,margin:0
和padding:0
用来清除自带网页的内外间距。
*{ margin: 0; padding: 0; }
并集选择器 ,
#box,#xxx{}
交集选择器
<div id="box" class="xxx"></div> #box.xxx{}
后代选择器
<div id="box"> <div class="sub"> <div class="s1"> </div> </div> </div> .box .s1 {}
子选择器
<div id="box"> <div class="sub"> <div class="s1"> </div> </div> </div> .box>.sub>.s1{}
相邻兄弟选择器 -
兄弟只能从上往下选
<div class="s1"></div> <div class="s2"></div> <div class="s3"></div> .s1+.s2{}
普通兄弟选择器 ~
<div class="s1"></div> <div class="s2"></div> <div class="s3"></div> .s1~.s3{}
伪类选择器
-
hover
-
nth-child()
-
<style> ul li:nth-child(2){ color: red; } /* 参数edd是奇数行,even是偶数行 还可以写表达式2n+1 */ </style> <ul> <li>1</li> <li>2</li> </ul>
-
-
first-child
-
last-child
否定伪类选择器
-
:not()
-
<style> .not>div:not(.n){ font-size:30px; } </style> <div class="not"> <div class="n">123</div> <div>123</div> </div>
-
伪元素选择器
-
before
-
after
-
<!-- 加的伪元素不能被选中 --> <style> .mys::after{ content: ""; width: 20px; height: 20px; background: blue; display: block; /*inline-block*/ } .mys::before{ content: "之前"; } </style> <div class="mys"> 这是微元素 </div>
-
优先级
!important
> 内联选择器 > ID选择器 > 类选择器 > 属性选择器 > 伪类 > 元素选择器 > 通配符选择器 > 继承选择器
/* !important 可以更改内联样式 */ .li{ color: green!important; }
2、css
盒模型
*盒子宽度模式
*{ box-sizing: border-box; /* 盒子的宽度模式content-box */ }
*display
-
none:不显示
-
block:块盒,上下的margin会合并
-
inline
:行盒,设置之后width、height变成无效 -
inline-block
:行内块,设置后和inline
一样不过可设置宽高 -
flex
布局 -
grid
布局
padding
padding-left: 20px; padding-top: 10px; padding-right: 20px; padding-bottom: 10px; /*四个就是 上 右 下 左;三个就是 上 左右 下;两个就是 上下 左右 */ padding: 20 10 30 40;
margin
基本设置同padding类似
但是margin有auto属性 学flex的时候再说
块盒,上下的margin会合并
border
border-width border-style /* solid实线;dashed虚线;dotted点线;double双实线 */ border-color border-left-color: blue; border: 10px solid red; border-radius: 5px; /* 圆角上右下左 */ border-radius: 50%; /* 圆形 */
设置三角形
只需要给盒子的宽度设置为零,然后设置某一个边的宽度和颜色即可
.box{ width: 0; height: 0; border-width: 20px; border-style: solid; border-bottom-color: aqua; border-right-color: aquamarine; border-top-color: antiquewhite; border-left-color: blueviolet; /* 需要什么样的三角形,就让其他的三角形颜色是透明的 transparent; 透明色 */ }
outline 设置
轮廓线,属性和border类似
-
不占用盒子的宽度
-
只能设置整个的,没有单个方向的
3、css
定位
值 | 描述 |
---|---|
absolute | 生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。元素的位置通过 left, top, right 以及 bottom 属性进行规定 |
fixed | 生成固定定位的元素,相对于浏览器窗口进行定位。元素的位置通过 left, top, right以及 bottom属性进行规定 |
relative | 生成相对定位的元素,相对于其正常位置进行定位。因此,left:20 会向元素的 LEFT 位置添加 20 像素 |
static | 默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明) |
sticky | 粘性定位。根据用户的滚动位置进行定位 |
相对定位 relative
-
相对元素之前的位置
-
之前的位置还在文档流中
<style> .box{ display: inline-block; width: 100px; height: 100px; background: aquamarine; position: relative; left: 100px; top: 100px; } .sub{ width: 40px; height: 40px; background: red; position: relative; left: 70px; top: 60px; } </style> <body> 相对定位相对定位 <div class="box"> <div class="sub"></div> </div> 相对定位相对定位相对定位 </body>
绝对定位 absolute
-
脱离文档流
-
找父级非
static
的元素进行偏移,找不到就层层往上,直到body
<style> .box{ display: inline-block; width: 100px; height: 100px; background: aquamarine; position: absolute; right: 100px; top: 100px; } .sub{ width: 40px; height: 40px; background: red; position: absolute; left: 70px; top: 60px; } </style> <body> 相对定位相对定位 <div class="box"> <div class="sub"></div> 1234 </div> 相对定位相对定位相对定位 </body>
固定定位 fixed
-
脱离文档流
-
以浏览器为参照
<style> .box{ display: inline-block; width: 100%; height: 60px; background: rgba(0,0,0, 0.5); position: fixed; top: 0; left: 0; } body{ height: 2000px; } </style> <body> 相对定位相对定位 <div class="box"></div> 相对定位相对定位相对定位 </body>
粘性定位 sticky
粘性定位的元素是依赖于用户的滚动,它的行为就像 position:relative;
而当页面滚动超出目标区域时,它的表现就像 position:fixed;
,它会固定在目标位置,元素定位表现为在跨越特定阈值前为相对定位,之后为固定定位
-
占据原来的位置
-
以浏览器为参考
<style> .d1{ height: 40px; width: 40px; background: #b81cc9; position: sticky; top: 100px; } </style> <body> <div class="d1"></div> </body>
z-index
图层概念
-
只能在定位元素上生效
-
父子关系z-index不生效
.c1{ position: relative; width: 100px; height: 100px; background-color: blueviolet; top: 50px; z-index: 1; } .c2{ position: relative; width: 100px; height: 100px; background-color: #2be274; left: 50px; }
4、css
背景设置
背景图片
.bg { width: 100%; height: 200px; background-image: url("https://profile-avatar.csdnimg.cn/392dc034291241239877635a77987f39_m0_65534674.jpg!1"); background-size: 50px; /* cover占满、contain保证图片一定在盒子里面 */ }
背景尺寸
background-size: contain; /* 保证图片一定在盒子里面 */ background-size: cover; /* 占满 */ background-size: 100% 50%; /* 背景图像宽度为元素宽度,高度为元素高度的一半 */ background-size: 300px auto; /* 背景图像宽度固定为300px,高度自动调整 */
背景平铺
background-repeat: no-repeat /*不平铺*/ background-repeat: repeat-x /*横向平铺*/ background-repeat: repeat-y /*纵向平铺*/ background-repeat: repeat /*双向平铺,默认*/
图片位置
background-position: left bottom; /* 左上,右上,右下,中心 */ background-position: 10px 20px; /* 从左上角开始算 */
雪碧图
把多个小图片合到一个大图片里面,然后通过css
图片定位方式,把图片显示出来 哔哩哔哩
.bg { width: 40px; height: 40px; background-image: url("https://image.fengfengzhidao.com/rj_0731/20240618113057.png"); background-position: -10px -266px; background-repeat: no-repeat; }
渐变
好看的渐变色网站
线性渐变
body{ width: 100%; height: 100hv; margin: 0; background-image: linear-gradient(to top, #a18cd1 0%, #fbc2eb 100%); }
表示方位
to top /* 从下往上进行渐变 */ to bottom /* 从上往下进行渐变 */ to right /* 从左往右进行渐变 */ to left /* 从右往左进行渐变 */ to top left /* 从右下向左上进行渐变(top和left可以交换位置,下同) */ to top right /* 从左下向右上进行渐变 */ to bottom left /* 从右上向左下进行渐变 */ to bottom right /* 从左上向右下进行渐变 */ 60peg /* 使用角度表示, 90deg等同于to right */
径向渐变
.radial{ width: 300px; height: 300px; background-image: radial-gradient(#a18cd1 0%, #fbc2eb 100%); }
/* 圆形 */ background-image: radial-gradient(circle, red, blue); /* 椭圆形 */ background-image: radial-gradient(ellipse, red, blue);
/* 重复 */ background-image: repeating-radial-gradient(red, yellow 10%, green 20%);
边框渐变
.border{ width: 300px; height: 300px; border: 20px solid; border-image: linear-gradient(to bottom right, yellow, green) 1 1 1 1; /* 内向偏移量 上右下左1110>左边没边框 */ }
文字渐变
display: inline-block; /* 宽度变成文字宽度 */ font-size: 30px; background-image: linear-gradient(to top, #fbc2eb 0%, #a6c1ee 100%); background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;
5、css
文字设置
字体样式
font-style 可继承
font-style: italic /* 显示一个斜体的字体样式 */ font-style: oblique /* 显示一个倾斜的字体样式 */ font-style: normal /* 默认值, 正常字体 */
text-decoration 文本的划线 可继承
text-decoration: none /* 不画线,并删除任何现有的装饰 */ text-decoration: underline /* 下划线 */ text-decoration: line-through /* 中划线 */ text-decoration: overline /* 上划线 */
/* 也可以设置宽度和颜色 */ text-decoration: underline 10px coral;
font-weight 可继承
font-weight:bold;
text-indent 文本缩进 可继承
/* 首行缩进2字符 */ text-indent: 2rem;
text-transform 大小写控制 可继承
text-transform: capitalize /* 首字母大写 */ text-transform: uppercase /* 大写 */ text-transform: lowercase /* 小写 */ text-transform: none /* 正常 */
间距
line-height 行间距 可继承
/*1.5倍行距*/ line-height: 1.5rem;
letter-spacing 字符间距 可继承
letter-spacing: 2rem;
word-spacing 单词间距 可继承
word-spacing: 1rem;
空白处理
white-space 可继承
white-space: nowrap; /* 强制在一行中显示 会出现横向滚动条 */ white-space: pre /* 换行和空格保留 */ white-space: normal /* 自动换行 */
超出显示省略号
单行超出显示省略号
/*不换行*/ white-space: nowrap; /*溢出隐藏*/ overflow: hidden; /*显示省略号*/ text-overflow: ellipsis;
多行超出显示省略号
/*溢出隐藏*/ overflow: hidden; /*显示省略号*/ text-overflow: ellipsis; display: -webkit-box; -webkit-box-orient: vertical; /*设置显示文本的行数*/ -webkit-line-clamp: 4;
文本对齐
text-align 水平对齐 可继承 对行内元素无效,行内块需要设置宽度
text-align: left /* 左对齐 */ text-align: center /* 居中对齐 */ text-align: right /* 右对齐 */
vertical-align 垂直对齐 对行内元素或者行内块元素有效
vertical-align: bottom /* sub设置文本为下标,super设置文本为上标 , top与顶端对齐 ,text-bottom与低端对齐 */
经常用于设置图片或者表单(行内块元素)和文字垂直对齐
<div class="line"> <span>这是文字</span> <img width="100" src="https://img0.baidu.com/it/u=2426072799,1960439289&fm=253&app=120&size=w931&n=0&f=JPEG&fmt=auto?sec=1718816400&t=94b5bbee4836daa4206bfecc6c0baf4b" alt=""> <span>这是文字</span> </div>
vertical-align: bottom;
字体设置
font-family 可继承
/* 可以设置多个字体,第一个没有就找后面的 */ font-family: "宋体", "方正舒体";
导入字体
用 @font-face 导入
@font-face { src: url("./ZiXiaoHunLiLiangCuHeiTi(ShangYongXuShouQuan)-2.ttf"); font-family: "xxx"; } .line { font-family: "xxx"; }
6、css
变换与动画
变换 transform
使用变换之后,这个原来的位置还在文档流里
只作用于块和行内块,可以多个属性共存
平移 translate
transform: translate(x, y);
旋转 rotate
transform: rotate(60deg);
缩放 scale
transform: scale(1.2); /* 缩放,可以破除浏览器12px最小字体大小的限制 */
锚点
主要这对于缩放和旋转
transform-origin: left top;
过渡
transition
属性包括以下几个子属性:
-
transition-property
:指定要过渡的CSS
属性名称,可以使用通配符all
表示所有属性都要过渡 -
transition-duration
:指定过渡的持续时间,单位可以是秒(s)或毫秒(ms) -
transition-timing-function
:指定过渡的时间函数,用于控制过渡的速度曲线,常见的值有ease
、linear
、ease-in
、ease-out
、ease-in-out
等 -
transition-delay
:指定过渡的延迟时间,即过渡开始前等待的时间,单位可以是秒(s)或毫秒(ms)
.line{ display: inline-block; transition: transform 1s; /* all 1s; */ transform-origin: right top; } .line:hover{ transform: scale(1.2); }
动画
创建动画序列,需要使用 animation
属性或其子属性,该属性允许配置动画时间、时长以及其他动画细节,但该属性不能配置动画的实际表现,动画的实际表现是由 @keyframes
规则实现
属性 | 描述 |
---|---|
animation-name | 指定由 @keyframes 描述的关键帧名称 |
animation-duration | 设置动画一个周期的时长 |
animation-delay | 设置延时 |
animation-direction | 设置动画在每次运行完后是反向运行还是重新回到开始位置重复运行 |
animation-iteration-count | 设置动画重复次数, 可以指定 infinite 无限次重复动画 |
animation-play-state | 允许暂停和恢复动画 |
animation-timing-function | 设置动画速度, 即通过建立加速度曲线,设置动画在关键帧之间是如何变化 |
animation-fill-mode | 规定元素在不播放动画时的样式(在开始前、结束后,或两者同时) |
/* <div class="tags"> <div class="box"></div> </div> */ .tags { position: relative; width: 400px; height: 400px; background: rosybrown; } .box { position: absolute; width: 20px; height: 20px; background: blue; animation-name: move_box; /* 指定由@keyframes描述的关键帧名称 */ animation-duration: 5s; /* 执行一次动画的时长 */ animation-iteration-count: infinite; /* 循环播放 */ } .tags:hover .box{ animation-play-state: paused; /* 允许暂停和恢复动画 */ } @keyframes move_box { 0% { left: 0; top: 0; } 25% { left: calc(100% - 20px); top: 0; } 50% { left: calc(100% - 20px); top: calc(100% - 20px); } 75% { left: 0; top: calc(100% - 20px); } 100% { left: 0; top: 0; } }
/* <div class="box"></div> */ @keyframes box_move { 0% { transfrom: translate(0, 0); } 100% { transfrom: translate(1000px, 0); } } .box{ width: 40px; height: 40px; background-color: #800e0e; animation-name: move_box; /* 指定由@keyframes描述的关键帧名称 */ animation-duration: 5s; /* 执行一次动画的时长 */ animation-iteration-count: infinite; /* 循环播放 */ }
7、css
中的flex布局
Flexbox
布局也叫 Flex 布局,弹性盒子布局
它决定了元素如何在页面上排列,使它们能在不同的屏幕尺寸和设备下可预测地展现出来,更简便、完整、响应式地实现各种页面布局
它的主要思想是使父元素能够调整子元素的宽度、高度、排列方式,从而更好的适应可用的布局空间
采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"
它的所有 子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"
容器属性
flex-direction
主轴方向
决定主轴的方向(即项目的排列方向)
属性值 | 含义 |
---|---|
row | 默认值,主轴为水平方向(水平布局),起点在左端,从左向右排列 |
row-reverse | 主轴为水平方向(水平布局),起点在右端,从右向左排列 |
column | 主轴为垂直方向(垂直布局),起点在上沿,从上往下排列 |
column-reverse | 主轴为垂直方向(垂直布局),起点在下沿,从下往上排列 |
justify-content
对齐方式
定义了项目在主轴上的对齐方式
属性值 | 含义 |
---|---|
flex-start | 默认值,左对齐 |
flex-end | 右对齐 |
center | 居中 |
space-between | 两端对齐,项目之间的间隔都相等 |
space-around | 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍 |
space-evenly | 均匀排列每个元素 |
align-items 交叉轴对齐方式
定义项目在交叉轴的对齐方式
属性值 | 含义 |
---|---|
flex-start | 交叉轴的起点对齐 |
flex-end | 交叉轴的终点对齐 |
center | 交叉轴的中点对齐 |
baseline | 项目的第一行文字的基线对齐 |
stretch | (默认值) 如果项目未设置高度或设为auto,将占满整个容器的高度 |
flex-wrap 换行
默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap
属性定义,如果一条轴线排不下,如何换行
属性值 | 含义 |
---|---|
nowrap | 默认值,表示不换行 |
wrap | 换行 |
wrap-reverse | 换行,第一行在下方 |
flex-flow
flex-flow 属性是 flex-direction 和 flex-wrap 主轴方向和换行的复合属性
flex-flow: row wrap;
align-content
属性和align-items交叉轴对齐方式一样,但是多了space-的设置
align-content适用于多行情况
项目属性
order 排序
order
属性用来定义项目的排列顺序。数值越小,排列越靠前,默认为 0
<style> .flex1{ margin-top: 20px; width: 400px; background-color: #f6bcbe; display: flex; } .flex1 .item{ order: 10; } </style> <div class="flex1"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> <div class="item" style="order: 1">4</div> </div>
flex-grow 放大比例
flex-grow
属性定义项目的放大比例,默认为 0 ,即如果存在剩余空间,也不放大
<style> .flex1{ margin-top: 20px; width: 400px; background-color: #f6bcbe; display: flex; } .flex1 .item{ margin: 1px; } </style> <div class="flex1"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> <div class="item" style="flex-grow: 2">4</div> <!-- 按剩余空间大小侵占 --> </div>
flex-shrink
flex-shrink
属性定义了项目的缩小比例,默认为 1 ,即如果空间不足,该项目将缩小
<style> .flex1{ margin-top: 20px; background-color: #f6bcbe; display: flex; } .flex1 .item{ width: 100px; margin: 1px; } </style> <div class="flex1"> <div class="item" style="flex-shrink: 0">1</div> <!-- 缩小到一定程度就不缩小了 --> <div class="item">2</div> <div class="item">3</div> <div class="item" style="flex-grow: 2">4</div> <!-- 按剩余空间大小侵占 --> </div>
flex-basis 设置宽
如果 flex-basis 的值不是 auto,width 属性会被忽略
flex-basis
属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto
,即项目的本来大小
它的初始值是 auto,此时浏览器会检查元素是否设置了 width 属性值
如果有,则使用 width 的值作为 flex-basis 的值;
如果没有,则用元素内容自身的大小
如果 flex-basis 的值不是 auto,width 属性会被忽略
flex
flex
属性是flex-grow
, flex-shrink
和 flex-basis
的简写,默认值为0 1 auto
。后两个属性可选
.item { flex:0 1 auto; } .item { flex-grow: 0; flex-shrink: 1; flex-basis: auto; }
align-self
align-self
属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items
属性。默认值为auto
,表示继承父元素的align-items
属性,如果没有父元素,则等同于stretch
<style> .flex1{ margin-top: 20px; background-color: #f6bcbe; display: flex; } .flex1 .item{ width: 100px; margin: 1px; } </style> <div class="flex1"> <div class="item" style="flex-shrink: 0">1</div> <!-- 缩小到一定程度就不缩小了 --> <div class="item" style="align-self: center">2</div> <div class="item">3</div> <div class="item" style="flex-grow: 2">4</div> <!-- 按剩余空间大小侵占 --> </div>
flex与margin auto
之前埋了一个关子,在学习margin的时候。它有一个auto属性需要到flex才能用到
<style> .flex1{ margin-top: 20px; width: 400px; background-color: #f6bcbe; display: flex; /* justify-content: space-between; */ } .flex1 .item:nth-child(2){ margin: 0 auto; } </style> <div class="flex1"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div>
8、css
中的grid布局
Flex 布局是轴线布局,只能指定“项目”针对轴线的位置,可以看作是一维布局
Grid 布局则是将容器划分成“行”和“列”,产生单元格,然后指定"项目所在"的单元格,可以看作是二维布局。Grid 布局远比 Flex 布局强大
一般情况下,在处理某一行的元素的布局时使用flex
布局;在处理多行的元素布局时使用grid
布局
grid解决
如果使用flex要实现类似这样的布局,是很麻烦的
需要去算盒子的宽度和中间的间隔
<style> body { margin: 0; } .flex { background-color: #f0eeee; width: 600px; display: flex; flex-wrap: wrap; /* justify-content: space-between; */ } .flex .item{ width: 135px; height: 40px; background-color: #3be598; margin-bottom: 20px; } .flex .item:nth-child(4n+1), .flex .item:nth-child(4n+2), .flex .item:nth-child(4n+3){ margin-right: 20px; /* margin-right: auto; */ } </style> </head> <body> <div class="flex"> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div> </body>
如果不用flex会更复杂,但是也是可以实现的
注意空白折叠!
<style> body { margin: 0; } .box { background-color: #f0eeee; width: 600px; margin-top: 20px; } .box .item{ width: 135px; height: 40px; background-color: #3be598; display: inline-block; margin-bottom: 20px; } .box .item:nth-child(4n+1), .box .item:nth-child(4n+2), .box .item:nth-child(4n+3){ margin-right: 15.2px; /* margin-right: calc((100%-1200px)/3); */ } </style> </head> <body> <div class="box"> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div> </body>
但是,如果使用grid,将会超级简单
<style> body { margin: 0; } .grid { background-color: #f0eeee; width: 600px; margin-top: 20px; display: grid; grid-template-columns: repeat(4, 1fr); /* grid-row-gap: 20px; */ row-gap: 20px; column-gap: 20px; } .grid .item{ width: 100%; height: 40px; background-color: #3be598; } </style> </head> <body> <div class="grid"> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div> </body>
grid容器属性
grid-template-columns
划分列数
固定宽度
grid-template-columns: 40px 40px;
百分比
grid-template-columns: 40% 60%;
比例
grid-template-columns: 1fr 2fr;
重复
grid-template-columns: repeat(5, 1fr); /*5列,每列等宽*/
自动计算列
grid-template-columns: repeat(auto-fill, 600px); /*每列固定600px,自动算多少列*/ grid-template-columns: repeat(auto-fit, 600px); /*每列固定600px,自动算多少列*/
auto
grid-template-columns: 100px auto 100px;
grid-template-rows
划分行数
行列间距
grid-template-columns: repeat(3,1fr); /*grid-template-rows: repeat(3,1fr);*/ row-gap: 20px; column-gap: 20px;
gap是row-gap和column-gap是简写
容器对齐方式
justify-content 水平对齐方式
justify-content: center; /* 属性和之前一样 */
align-content 垂直对齐方式
align-content: center;
place-content 是align-content
属性和justify-content
属性的合并简写形式
place-content: end end;
单元格对齐方式
justify-items
align-items
place-items
是align-items
属性和justify-items
属性的合并简写形式。
justify-items: end; align-items: end;
项目内单元格对齐方式
用法和justify-items类似,但是是在项目属性上写的
<div class="item" style="place-self: end end">1</div>
grid项目属性
合并单元格
.item-8{ grid-column-start: 2; grid-column-end: 4; }
.item-5{ grid-column-start: 2; grid-column-end: 4; grid-row-start: 2; grid-row-end: 4; }
可简写为
grid-row: 2/4; grid-column: 2/4;
9、css
栅格化
css
栅格化
UI
组件库的基石,整个css
布局的核心知识
.row { display: flex; height: 100px; } .col { height: 100%; } .col-1 { flex: 0 0 10%; } .col-2 { flex: 0 0 20%; } .col-3 { flex: 0 0 30%; } .col-4 { flex: 0 0 40%; } .col-5 { flex: 0 0 50%; } .col-6 { flex: 0 0 60%; } .col-7 { flex: 0 0 70%; } .col-8 { flex: 0 0 80%; } .col-9 { flex: 0 0 90%; } .col-10 { flex: 0 0 100%; }
Bootstrap
-
比较早使用css栅格化的ui组件库
-
它可以单独使用,不挑前端框架
官方文档
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous"> <!-- 建议下载下来 --> https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css
10、css
实战布局
枫枫博客后台布局
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>博客后台框架</title> <style> * { box-sizing: border-box; } body { margin: 0; } .admin { display: flex; } .admin > aside { width: 240px; height: 100vh; background-color: white; border-right: 1px solid #f0eeee; } .admin > aside > .logo { height: 90px; border-bottom: 1px solid #f0eeee; } .admin > main { width: calc(100% - 240px); height: 100vh; background-color: white; } .admin > main > .head { height: 60px; } .admin > main > .tabs { height: 30px; border-top: 1px solid #f0eeee; border-bottom: 1px solid #f0eeee; /* 下划边框线 */ } .admin > main > .container { height: calc(100vh - 90px); overflow-y: auto; /* 控制滚动条出现的样式 */ background-color: #f0eeee; padding: 20px; } .default_main { width: 100%; height: 100%; background-color: white; border-radius: 5px; } </style> </head> <body> <div class="admin"> <aside> <div class="logo"> </div> <div class="menu"> </div> </aside> <main> <div class="head"> </div> <div class="tabs"> </div> <div class="container"> <div class="default_main"> </div> </div> </main> </div> </body> </html>
枫枫博客前台布局
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>博客前台</title> <style> body { margin: 0; } * { box-sizing: border-box; } a { color: #333; text-decoration: none; } .blog { } .blog .nav { width: 100%; height: 60px; background-color: rgba(255, 255, 255, 0.8); position: fixed; top: 0; display: flex; justify-content: center; z-index: 100; } .blog .nav .container { align-items: center; } .blog .nav .left { width: 10%; } .blog .nav .left div:nth-child(1) { font-size: 22px; } .blog .nav .left div:nth-child(2) { font-size: 12px; } .blog .nav .center { width: 70%; } .blog .nav .center a { margin-left: 20px; } .blog .nav .right { width: 20%; text-align: right; } .blog .banner { height: 600px; position: relative; } .blog .banner img { width: 100%; height: 100%; object-fit: cover; /* 自适应 */ } .blog .banner .slogan { position: absolute; left: 50%; top: 50%; color: white; transform: translate(-50%, -50%); /* 偏移50% */ } .blog .banner .slogan div { text-align: center; } .blog .banner .slogan div:nth-child(1) { font-size: 26px; } .blog .banner .slogan div:nth-child(2) { font-size: 18px; margin-top: 10px; } .container { width: 1200px; display: flex; } .blog main { background-color: #f0eeee; display: flex; justify-content: center; padding: 20px 0; } .blog main .container > .left { width: calc(100% - 300px - 20px); margin-right: 20px; } .blog main .container > .right { width: 300px; } .blog main .news { margin-bottom: 20px; } .blog main .tags { margin-bottom: 20px; } .blog .footer{ height: 50px; background-color: white; justify-content: center; align-items: center; display: flex; } .card { background-color: white; border-radius: 5px; } .card .head { padding: 20px 20px 10px 20px; border-bottom: 1px solid #f0eeee; } .card .head .title { font-size: 18px; font-weight: 600; } .card .body{ padding: 10px 20px 20px 20px; } </style> </head> <body> <div class="blog"> <div class="nav"> <div class="container"> <div class="left"> <div>枫枫知道</div> <div>FFENGZHIDAO</div> </div> <div class="center"> <a href="">首页</a> <a href="">搜索</a> <a href="">聊天室</a> </div> <div class="right"> <a href="">登录</a> </div> </div> </div> <div class="banner"> <img src="http://image.fengfengzhidao.com/gvb_1009/20231123092743__1123-e.png" alt=""> <div class="slogan"> <div>枫枫知道个人博客九代</div> <div>我的九代博客</div> </div> </div> <main> <div class="container"> <div class="left"> <div class="card news"> <div class="head"> <div class="title">今日热搜</div> </div> <div class="body"> </div> </div> <div class="card article"> <div class="head"> <div class="title">文章列表</div> </div> <div class="body"> </div> </div> </div> <div class="right"> <div class="card tags"> <div class="head"> <div class="title">标签云</div> </div> <div class="body"> </div> </div> <div class="card user_info"> <div class="head"> <div class="title">个人信息</div> </div> <div class="body"> </div> </div> </div> </div> </main> <div class="footer"> 建站日期:2023-02-15网站已运行: 493天15时32分45秒 </div> </div> </body> </html>
<!-- JavaScript -->
-
前端所使用的编程语言
-
弱类型动态语言
1、使用js
的三种方式
-
行内
<button οnclick="alert('你点到我了')">点我</button>
-
外部引入
<script src="index.js"></script>
-
内嵌 可以在任何地方引入
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>引入js</title> <script> console.log("hello world head里面") </script> </head> <body> <script> console.log("hello world body里面") </script> </body> <script> console.log("hello world body外面") </script> </html> <script> console.log("hello world html的外面") </script>
2、变量与基本数据类型
变量声明
var
-
函数作用域
-
作用域提升
console.log(name) { var name = "xiaojin" }
-
全局变量可以被挂载到window上
let
-
块级作用域
-
暂时性死区
const
-
常量,声明就需要初始化
-
通常用于声明数组和对象
==和===
==是值判断,不会去判断类型
===是值和类型一起判断
console.log(12 == "12") // true console.log(12 === "12") // false
基本数据类型
八种基本数据类型
Number、String、Boolean、Null、undefined、object、symbol、bigInt
number
const a = 123 const a1 = Number(123) console.log(a, typeof a) console.log(a1, typeof a1) const a2 = 0b110 // 6 console.log(a2) const a3 = 0o11 // 9 console.log(a3) // 0 1 2 3 4 5 6 7 8 9 a b c d e f const a4 = 0xa1 // 10 * 16 + 1 = 161 console.log(a4) // 最终打印都是十进制
保留小数 toFixed
const a5 = 3.14159265354 console.log(a5) console.log(a5.toFixed(2)) // 3.14 console.log(a5.toFixed(0)) // 3
转整数 Number.parseInt()
console.log(Number.parseInt(3.14)) // 3 console.log(Number.parseInt("5")) // 5 console.log(Number.parseInt("5.256")) // 5
是否为整数Number.isInteger()
console.log(Number.isInteger(1)) // true console.log(Number.isInteger(1.2)) // false console.log(Number.isInteger("1.2")) // false console.log(Number.isInteger("1")) // false console.log(Number.isInteger(-3)) // true
取整
console.log(Math.round(3.5)) // 四舍五入 4 console.log(Math.round(3.4)) // 四舍五入 3 console.log(Math.ceil(1.0000001)) // 向上取整 2 console.log(Math.ceil(1.9)) // 向上取整 2 console.log(Math.floor(1.9)) // 向下取整 1 console.log(Math.floor(1.001)) // 向下取整 1
string
字符串
const s1 = "ffzd" console.log(s1, typeof s1) const s2 = String("枫枫") console.log(s2, typeof s2) console.log(s1[0]) // f console.log(s1[2]) // z
indexOf()
根据字符找编号
const s1 = "ffzd" console.log(s1.indexOf('z')) // 2 console.log(s1.indexOf('1')) // -1 // 如果有多个字符匹配,返回最开始那个字符的编号 console.log(s1.indexOf('zd')) // 2
split()
按照特点的分隔符切割字符串
const s3 = "枫枫,zhangsan,lisi" const a = s3.split(",") console.log(a[0], a[1])
slice()
切片,返回值也是一个字符串
const s4 = "枫枫,zhangsan,lisi" console.log(s4.slice(3, 11)) // 前闭后开 zhangsan
includes()
包含,判断是否有子串包含
const s5 = "枫枫,zhangsan,lisi" console.log(s5.includes("lisi")) // true console.log(s5.indexOf("lisi") !== -1) // true
trim()
去空格
const s6 = " 我的名字是枫枫 " console.log(s6) console.log(s6.trim())
boolean
-
false、0、""、null、undefined、
NaN
转为 布尔值 为 false -
其他所有值 转为布尔值 为 true
const b1 = true const b2 = false console.log(Boolean(0)) console.log(Boolean('')) // 空字符串 false console.log(Boolean(' ')) // 空格字符串 true console.log(Boolean(null)) console.log(Boolean(undefined)) console.log(Boolean(false)) console.log(Boolean(NaN))
object
增删改查
const lyf = { "name": "lyf", "age": 18 } const lyf1 = { name: "lyf", age: 18 } console.log(lyf, typeof lyf) console.log(lyf1, typeof lyf1) console.log(lyf.name) console.log(lyf["name"]) lyf.addr = "湖南" lyf["xxx"] = "yyy" console.log(lyf) lyf.age = 19 console.log(lyf) delete lyf.addr delete lyf["xxx"] console.log(lyf) const name = "fengfeng" const obj = { [name]: "" } console.log(obj)
null
null表示一个空值或没有对象值。它是一个表示空对象指针的特殊关键字
null的用法:
-
作为函数的参数,表示该函数的参数不是对象
-
作为对象原型链的终点
undefined
undefined的用法
-
变量被声明了,但没有赋值时,就等于undefined
-
调用函数时,应该提供的参数没有提供,该参数等于undefined
-
对象没有赋值的属性,该属性的值为undefined
-
函数没有返回值时,默认返回undefined
为啥要用null和undefined
symbol 唯一值
js对象属性名都是字符串,这容易造成属性名冲突的问题
const name = Symbol("name") const age = Symbol("age") const symObj = { [name]: "张三", [age]: "14", } symObj["name"] = "枫枫" // 不会替换那个name console.log(symObj) console.log(symObj[name])
bigInt
可以安全地存储和操作大整数,即使这个数已经超出了Number类型能够表示的安全整数范围。
在 JavaScript 中,普通的数字(Number 类型)只能安全地表示 -9007199254740991(即 -(2^53 - 1))到 9007199254740991(即 2^53 - 1)之间的整数。超出这个范围的整数在表示时可能会失去精度。因此,BigInt
解决了之前Number整数溢出的问题。
const b1 = BigInt(123) console.log(typeof b1, b1) console.log(b1 + BigInt(10086)) // 必须都是bigint才行 const b2 = 12345678910n // bigint类型 console.log(typeof b2, b2)
3、数组与数组方法
数组
数组创建
const a1 = ["fengfeng", "zhangsan", "lisi"] console.log(a1[0]) // 获取数组的第一个元素 console.log(a1.length) // 获取数组的长度=数组中元素的个数 console.log(a1[a1.length - 1]) // 获取数组的最后一个元素 const a2 = Array("fengfeng", "zhangsan", "lisi") console.log(a2)
遍历数组
for i
for (let i = 0; i < a1.length; i++) { console.log(i, a1[i]) }
for of
遍历数组最常用方法
for (const value of a2) { console.log(value) }
判断一个对象是不是数组
typeof(数组)
得到的结果是object。因为数组本质就是对象
Array.isArray()
console.log(Array.isArray(a1)) // true console.log(Array.isArray(1)) // false
instanceof
console.log(a1 instanceof Array) // true
数组方法
push()、pop()方法
push()
数组末端添加一个或多个元素,返回添加之后数组的长度
const a1 = ["fengfeng", "zhangsan", "lisi"] a1.push("王五") const l = a1.push("z1", "z2") console.log(l, a1)
pop()
移除数组末端的元素,并返回
const a2 = ["fengfeng", "zhangsan", "lisi"] const item = a2.pop() console.log(item, a2)
shift()、unshift()方法
shift()
从数组最左端移出元素,并返回移出的元素
const a3 = ["fengfeng", "zhangsan", "lisi"] const fi = a3.shift() console.log(fi, a3)
unshift()
在数组的开头插入新元素,并返回数组的新长度
const a4 = ["fengfeng", "zhangsan", "lisi"] const l1 = a4.unshift("小红") console.log(l1, a4)
join()方法
将数组内所有元素按join()
内的参数为分割添加到字符串中
const a5 = ["fengfeng", "zhangsan", "lisi"] const s = a5.join(",") console.log(s) // fengfeng,zhangsan,lisi console.log(a5.join()) // 默认就是, console.log(a5.join("|")) // fengfeng|zhangsan|lisi
sort()方法 默认升序
const a6 = [4, 2, 1, 5] console.log(a6.sort()) // 升序
可以通过reverse()反转得到降序
const a6 = [4, 2, 1, 5] console.log(a6.sort()) // 升序 console.log(a6.reverse()) // 反转
高级用法 (后一个元素,当前元素)
return 正值和0不变 return 负值就交换
const a6 = [0, 2, 1, 5] a6.sort(function (a, b){ console.log(a, b) return b-a }) console.log(a6)
a-b 升序后一个比当前元素大 b-a 降序 当前元素比后一个大
splice()方法
用于删除数组中的元素,并且返回被删除的数组
const a7 = ["fengfeng", "zhangsan", "lisi"] const a8 = a7.splice(1, 1) // (索引, 要删除的个数) console.log(a8) // 被删除的数组 ["zhangsan"] console.log(a7) // 原位删除 ["fengfeng","lisi"]
以下是ES6
新增的数组方法
forEach()
循环
-
中途不能退出
const a1 = ["fengfeng", "zhangsan", "lisi"] a1.forEach(function (value, index, array){ console.log(value, index, array) })
map() 迭代
迭代每一个元素,去进行操作
const a2 = a1.map(function (value, index, array){ return value + "@qq.com" }) console.log(a2) // ['fengfeng@qq.com', 'zhangsan@qq.com', 'lisi@qq.com'] 不会原位修改
filter() 过滤
const a3 = a1.filter(function (value, index, array){ if (value === "zhangsan"){ return true } }) console.log(a3) // ['zhangsan']
every()方法、some()方法
every:判断数组中是不是 每一个 都满足条件
some:判断数组中 其中一个 满足条件
const a4 = [5, 1, 0, -1, 2] console.log(a4.every(function (value){ if (value >= 0){ return true } })) // false console.log(a4.some(function (value){ if (value >= 0){ return true } })) // true
find()方法
获取数组中满足条件的数据,如果有 就是满足条件的第一个数据;如果没有就是undefined
const a5 = [5, 1, 0, -1, 2] const item = a5.find(function (value, index, obj){ if (value >= 5){ return true } }) console.log(item) // 5 找不到就是undefined const index = a5.findIndex(function (value, index, obj){ if (value >= 5){ return true } }) console.log(index) // 0 找不到就是-1
4、流程控制
逻辑运算符
流程控制的关键,掌管进退的神
一般用于编写复合逻辑
与 &&
const name = "fengfeng" const age = 12 console.log(age >= 18 && name.startsWith("f"))
或 &&
const name = "fengfeng" const age = 12 console.log(age >= 18 || name.startsWith("f"))
非 !
console.log(!(age >= 18) )
逻辑短路
&&: 如果前面的条件是false,那就不会去判断后面的条件了
||:如果前端的条件是true,那就不会去判断后面的条件了
如何验证
function t(){ console.log("t") return true } console.log(-1>0 && t()) // 不会执行t console.log(1>0 || t()) // 不会执行t
判断语句
if语句
单分支
const name = "fengfeng" if (name === "fengfeng") { console.log("去度假") } // 如果代码语句只有一行,可以省略{} if (name === "fengfeng") console.log("去度假") console.log("不管什么我都会执行")
双分支
if (name === "fengfeng"){ console.log("fengfeng去度假") }else { console.log("fengfeng继续搬砖") }
多分支
const scope = 90 if (scope >= 90) { console.log("A") } else if (scope >= 80) { console.log("B") } else if (scope >= 60) { console.log("C") } else { console.log("D") }
分支嵌套
if (scope >= 80){ if (scope >= 90){ console.log("A") }else { console.log("B") } }else { if (scope >= 60){ console.log("C") }else { console.log("D") } }
分支优化
function get_scope(scope){ if (scope >= 90){ console.log("A") return; } if (scope >= 80){ console.log("B") return; } if (scope >= 60){ console.log("C") return; } console.log("D") }
switch语句
注意: 执行case 里面的语句时,如果没有break,则继续执行下一个case里面的语句
const day = 7 switch (day) { case 1: console.log("周一") break case 2: console.log("周二") break case 3: console.log("周三") break case 4: console.log("周四") break case 5: console.log("周五") break case 6: console.log("周六") break case 7: console.log("周天") break default: console.log("错误") }
循环语句
传统for循环
let sum = 0 for (let i = 1; i <= 100; i++) { sum += i } console.log(sum)
for in循环 遍历对象
for...in循环可以用来遍历对象的可枚举属性列表(包括原型链上的属性)
const obj = { name:"枫枫", age: 21 } for (const objKey in obj) { console.log(objKey) }
for of循环 遍历数组
用于遍历数组
const array = ["枫枫", "张三"] for (const item of array) { console.log(item) }
while循环
let i = 1 let r = 0 while (i <= 100){ // 循环体 r += i i ++ } console.log(r)
do while循环
先执行一次循环体,再进行条件判断
let o = 1 let r = 0 do { r += o o ++ }while (o <= 100) console.log(r)
continue
例如,吃5个包子,吃到第3个发现里面有半个虫子,这个包子就不吃了,继续吃下一个。
for (let j = 1; j <= 10; j++) { if (j === 3){ console.log(`吃到第${j}个包子,发现虫子,这个包子我不吃了`) continue } console.log(`吃到第${j}个包子`) }
break
跳出整个循环
例如,吃5个包子,吃到第3个发现里面有半个虫子,这盘都不吃了。
for (let j = 1; j <= 10; j++) { if (j === 3){ console.log(`吃到第${j}个包子,发现虫子,我都不吃了`) break } console.log(`吃到第${j}个包子`) }
5、js
函数
函数是一种可重复使用的代码块
函数是一种非常重要和常用的语言特性,可以用于封装代码、抽象功能、提高代码的可读性和可维护性等
例如经常使用的 console.log函数,它的功能就是将变量打印到控制台上,我们只需要调用这个函数即可,而log函数考虑的就很多了
函数声明和调用
-
function声明
function hello() { console.log("hello") } hello()
-
匿名函数
const say = function (){ console.log("say") } say()
-
箭头函数
const eat = ()=>{ console.log("eat") } eat()
-
立即执行函数
(function (){ console.log("立即执行") })()
函数参数
声明是形参,调用是实参
function add(a, b){ // a,b是形参 return a + b } console.log(add(1,2)) // 1,2是实参
默认参数
如果对应的参数没有被赋值,那么对应的参数就是undefined
function getName(name="feng"){ // if (name === undefined){ // return "feng" // } // name = name || "feng" return name }
参数列表
形参和实参的传递是一一对应的,剩余的被参数列表接收
// function sum(a, ...list) {} function sum(...list) { let res = 0 for (const item of list) { res += item } return res } console.log(sum(2, 3)) console.log(sum(2, 3, 2, 3, 45))
arguments
完整的参数列表,是一个类数组
function sum1() { let res = 0 for (const item of arguments) { res += item } return res } console.log(sum1(2, 3)) console.log(sum1(2, 3, 2, 3, 45))
函数返回值
-
没有显式return等于return undefined
function set(){ } console.log(set()) // undefined
函数作为变量
函数自身也可以作为参数,放入对象、数组中
function getName(){ return "fengfeng" } const lis = [1,"sss", getName] console.log(lis[2]())
如果函数在对象中,此时它就叫方法
const obj = { name: "fengfeng", eat: function (){ return `${this.name}在吃饭` }, say: ()=>{ // 箭头函数中不能用this console.log("在说话") }, study(){ console.log(`${this.name}在学习`) } } console.log(obj.name) console.log(obj.eat()) obj.say() obj.study()
递归函数
在函数中调用自身
一定要设置退出条件
示例:展开所有的数组,变成一维数组
const list = [ "你好", "吃饭了吗", [ "好", [ [ "abc" ] ] ] ]
写法1
const a1 = [] function oneArray(array){ for (const arrayElement of array) { if (arrayElement instanceof Array){ oneArray(arrayElement) continue } a1.push(arrayElement) } } oneArray(list) console.log(a1)
写法2
function oneArray1(array){ const a2 = [] function oneArray(array){ for (const arrayElement of array) { if (arrayElement instanceof Array){ oneArray(arrayElement) continue } a2.push(arrayElement) } } oneArray(array) return a2 } console.log(oneArray1(list))
有非常多的方法
function oneArray2(array){ const a3 = [] for (const arrayElement of array) { if (arrayElement instanceof Array){ a3.push(...oneArray2(arrayElement)) continue } a3.push(arrayElement) } return a3 } console.log(oneArray2(list))
this问题
this指向
-
函数外:window
-
函数内:函数中的this指向谁,取决于这个函数是怎么调用的
-
箭头函数没有this或者this是window
this指向修改
function.call()
function.call(this指向谁, 函数参数1,参数2...) // 调用函数,并修改函数中的this指向;
function.apply()
function.apply(this指向谁, [参数1, 参数2...]) // 调用函数,并修改函数中的this指向
function.bind()
function.bind(指向,参数1,参数2,...) // 绑定this指向
箭头函数的this不能修改
function get() { console.log("get", this, arguments) } const set = ()=>{ console.log("set", this) } const obj = { name: "fengfeng", get: get, set: set, } get() obj.get() set() obj.set() // 改变this get.call(obj, 1,2,3) get.apply(obj, [1,2,3]) get.bind(obj, 1,2,3)(4,5,6) // 箭头函数的this指向不能修改
6、js
的对象
创建对象
字面量
const obj = { name: "枫枫" }
new一个对象
const o2 = new Object({})
原型对象
function People(name, age){ this.name = name this.age = age } People.prototype.eat = function (){ console.log(`${this.name}在吃饭`) } const o2 = new People("枫枫", 21) console.log(o2) o2.eat()
create方法
继承
// 其中的name和age属性 是在原型上 const o3 = Object.create({name: "枫枫", age: 21}) console.log(o3) console.log(o3.name) o3.name = "lisi" // 给自己加了一个name属性 console.log(o3.name) // 如果自己有这个属性,就用自己的,没有就去原型上去找
属性操作
查询,通过点或者方括号获取
console.log(o3.name) console.log(o3["name"])
删除属性 delete,只能删除自身的,继承来的不能删
delete o3.name // 只能删自己身上的属性 delete o3.age // 原型上的name和age还在
检测属性
"属性名" in object
, 可以自己+检测继承来的属性
const o3 = Object.create({name: "枫枫", age: 21, eat: function (){}}) o3.addr = "长沙市" console.log("age" in o3) // true console.log("addr" in o3) // true console.log("eat" in o3) // true 方法就是特殊的属性
object.hasOwnPreperty("属性名")
检测自身的属性
const o3 = Object.create({name: "枫枫", age: 21, eat: function (){}}) o3.addr = "长沙市" console.log(o3.hasOwnProperty("addr")) // true console.log(o3.hasOwnProperty("age")) // false
属性枚举
for-in
,继承+自身的属性
const o3 = Object.create({name: "枫枫", age: 21, eat: function (){}}) o3.addr = "长沙市" for (const o3Key in o3) { console.log(o3Key) }
Object.keys()
自己的属性
const o3 = Object.create({name: "枫枫", age: 21, eat: function (){}}) o3.addr = "长沙市" console.log(Object.keys(o3)) // ["addr"]
Object常用的API
Object.assign()
浅拷贝
Object.assign(target, ...sources) // 参数:target 目标参数,sources源对象 返回值:目标对象
-
如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖
Object.assign
方法只会拷贝源对象自身的并且可枚举的属性到目标对象 -
assign
其实是浅拷贝而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。同名属性会替换
const obj = {name: "王五", addr: "长沙"} const source = { name: "枫枫", info: { age: 21 }, likes: [] } Object.assign(obj, source) source.info.age = 22 // 最终会影响到 obj里面的age source.name = "zhangsan" // 外层的不会影响 source.likes.push("篮球") // 最终会影响到 obj里面的likes console.log(obj)
Object.keys()
一个表示给定对象的所有可枚举属性的字符串数组
const o3 = Object.create({name: "枫枫", age: 21, eat: function (){}}) o3.addr = "长沙市" console.log(Object.keys(o3)) // ["addr"]
Object.defineProperty()
定义对象属性
Object.defineProperty(obj, "name", { value: 101, // 属性的值 writable: true, // 是否允许修改 enumerable: true, // 是否允许枚举 configurable: true, // 是否允许删除 });
Object.getOwnPropertyNames()
Object.getOwnPropertyNames()
返回一个数组,该数组对元素是对象自身拥有的枚举或不可枚举属性名称字符串。
const o1 = {name: "枫枫"} Object.defineProperty(o1, "age", { value: 21, writable: true, // 是否可修改 enumerable: false, // 是否可枚举 configurable: true, // 是否可删除 }) console.log("Object.keys", Object.keys(o1)) // 获取可枚举的属性列表 console.log("Object.getOwnPropertyNames", Object.getOwnPropertyNames(o1)) // 获取属性列表 // delete o1.age
原型与原型链
原型在JavaScript是一个很重要的概念,它是面向对象可以继承的基础
原型链是原型的查找机制,是一条寻址链。其实原型上的方法或属性查找,都是按照一定的顺序沿着原型链进行查找的。如果查找到最后仍然没有找到这个原型和方法,那么就真的没有了
原型链的尽头是null
给构造函数添加原型
// Object.prototype.字段名 const obj = {} console.log(obj) const o1 = new Object({}) Object.prototype.name = "枫枫" console.log(o1)
修改现有对象的原型
找这个现有对象的父级的构造函数
比如{}的原型是Object的实例
const obj = {} Object.prototype.toString = function (){ return "这是对象的toString方法" } console.log(obj + "") console.log(obj.toString())
Object.create()设置原型方法
const o2 = Object.create({ eat(){ console.log("吃饭") } }) console.log(o2)
使用proto属性
可以通过设置对象的 __proto__
属性来改变其原型
const o2 = Object.create({ eat(){ console.log("吃饭") } }) o2.__proto__.study = function (){ console.log("在学习") } console.log(o2)
new的过程
-
创建一个新的对象
-
把该对象的
__proto__
属性设置为构造函数的prototype属性,即完成原型链 -
执行构造函数中的代码,构造函数中的this指向该对象(obj)
-
返回该对象obj
function People(name){ this.name = name } function _new(fn, ...args){ // 1. 创建一个新的对象 const o = {} // 2. 把该对象的__proto__属性设置为构造函数的prototype属性,即完成原型链 o.__proto__ = fn.prototype // 3. 执行构造函数中的代码,构造函数中的this指向该对象(obj) fn.apply(o, args) // 4. 返回对象 return o } const o3 = new People("枫枫") console.log(o3) const o4 = _new(People, "枫枫") console.log(o4)
7、js
时间库
在JavaScript中,时间戳(timestamp
)是一种表示特定时刻距离某个固定时间点的毫秒数。通常这个固定时间点是指 1970年1月1日00:00:00(UTC)
,即Unix纪元
时间戳
获取当前时间戳
console.log(new Date().getTime()) // 获取毫秒级时间戳 13位
将时间戳转换为时间对象
console.log(new Date(1719414979389))
日期对象
格式化日期对象
const date = new Date() console.log(date.getFullYear()) console.log(date.getMonth() + 1) // 月是从0开始的 console.log(date.getDate()) console.log(date.getHours()) console.log(date.getMinutes()) console.log(date.getSeconds())
把时间变成 2024-06-26 15:04:05这样的格式
可以使用字符串的padStart()
方法,把格式变成两位不够的用第二个参数补
function parseDate(dateString){ let date if (dateString){ date = new Date(dateString) }else { date = new Date() } const y = date.getFullYear().toString() const M = (date.getMonth() + 1).toString().padStart(2, "0") const d = date.getDate().toString().padStart(2, "0") const h = date.getHours().toString().padStart(2, "0") const m = date.getMinutes().toString().padStart(2, "0") const s = date.getSeconds().toString().padStart(2, "0") return `${y}-${M}-${d} ${h}:${m}:${s}` } console.log(parseDate("2022-12-12 15:04:05")) console.log(parseDate())
字符串转换为时间对象
new Date("2022-12-12 15:04:05")
日期计算
在一个日期上加减一个时间
调用setXXX
方法,重新设置一个时间
const d1 = new Date() console.log(parseDate(d1)) // 七天前 d1.setDate(d1.getDate() - 7) // 5小时后 d1.setHours(d1.getHours() + 5) console.log(parseDate(d1))
一个未来的时间距离现在还剩多久 时间戳相减
得到一个毫秒的时间,然后算出秒数、分钟、小时、天
function timeUntil(timeStr) { const now = new Date(); const then = new Date(timeStr); const diff = then - now; // 如果给定时间已经过去,返回过去的时间 if (diff < 0) { return '时间已经过去'; } // 将毫秒转换为秒 const seconds = Math.floor(diff / 1000); // 向下取整 const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); const days = Math.floor(hours / 24); if (days > 0) { return `${days} 天 ${hours % 24} 小时 ${minutes % 60} 分钟 ${seconds % 60} 秒`; } else if (hours > 0) { return `${hours} 小时 ${minutes % 60} 分钟 ${seconds % 60} 秒`; } else if (minutes > 0) { return `${minutes} 分钟 ${seconds % 60} 秒`; } else { return `${seconds} 秒`; } }
一个过去的时间距离现在过了多久
也是算时间的差值,直接除以大的年,大于0就直接返回,以此类推
function getDateDiff(dateTimeStamp) { // 时间字符串转时间戳 const timestamp = new Date(dateTimeStamp).getTime(); const minute = 1000 * 60; const hour = minute * 60; const day = hour * 24; const month = day * 30; const year = day * 365; const now = new Date().getTime(); const diffValue = now - timestamp; let result; if (diffValue < 0) { return; } const yearC = diffValue / year; const monthC = diffValue / month; const weekC = diffValue / (7 * day); const dayC = diffValue / day; const hourC = diffValue / hour; const minC = diffValue / minute; if (yearC >= 1) { result = "" + parseInt(yearC) + "年前"; } else if (monthC >= 1) { result = "" + parseInt(monthC) + "月前"; } else if (weekC >= 1) { result = "" + parseInt(weekC) + "周前"; } else if (dayC >= 1) { result = "" + parseInt(dayC) + "天前"; } else if (hourC >= 1) { result = "" + parseInt(hourC) + "小时前"; } else if (minC >= 1) { result = "" + parseInt(minC) + "分钟前"; } else result = "刚刚"; return result; }
8、正则表达式
正则表达式(Regular Expression,在代码中常简写为regex
、regexp
或RE)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。搜索模式可用于文本搜索和文本替换
各个编程语言中都支持正则表达式
正则表达式的用途有很多,比如:
-
表单输入验证
-
搜索和替换
-
过滤大量文本文件(如日志)中的信息
-
读取配置文件
-
网页抓取
-
处理具有一致语法的文本文件,例如
CSV
在线正则表达式
/[ab012]/g
字符集合
使用“[]” 里面属于||的关系
/[az012]/g // []中是||的关系
字符范围
使用“-”
/[a-z]/g /[\u4e00-\u9fa5]/g // 匹配中文
数量字符
{m,n}
最少匹配m个,最多匹配n个
/[\u4e00-\u9fa5]{2,3}/g // 匹配中文 /* {m,n} 最少匹配m个,最多匹配n个 */
+:匹配前面一个表达式一次或者多次,相当于{1,}。
/a[bc]+a/g // 相当于{1,}
*:匹配前面一个表达式0次或者多次,相当于{0,}。
/a[bc]*a/g // 相当于{0,}
?:单独使用匹配前面一个表达式零次或者一次,相当于{0,1},
/https?:\/\//g // 相当于{0,1}
贪婪模式
正则会尽可能的匹配多的字符
/a[ab]*a/g // 贪婪模式,正则会尽可能的匹配多的字符
非贪婪模式
尽可能匹配少的
/a[ab]?a/g // 非贪婪模式,尽可能匹配少的
元字符
元字符 | 说明 |
---|---|
\d | 匹配数字 [0-9] |
\D | 匹配非数字 |
\w | 匹配数字、字母、下划线 |
\W | 匹配非数字、字母、下划线 |
\s | 匹配任意的空白字符 |
\S | 匹配任意的非空白符 |
. | 匹配除换行符之外的任意字符 |
特殊字符
特殊字符 | 说明 |
---|---|
. | 匹配除了换行符之外的任何单个字符 |
\ | 转义字符 |
| | 逻辑或操作符 |
[^] | 取非,匹配未包含的任意字符 [^0-9] |
位置匹配
位置字符 | 说明 |
---|---|
\b | 匹配一个单词边界,也就是指单词和空格间的位置 \s空格也可 |
\B | 匹配非单词边界 |
^ | 匹配开头,在多行匹配中匹配行开头 |
$ | 匹配结尾,在多行匹配中匹配行结尾 |
分组
使用小括号
捕获分组
/\d{4}-(\d{2})-d{2}-(\d{2}):\d{2}:\d{2}/g 月:$1 小时:$2
无捕获分组
有些时候,使用小括号只是希望把它当做一个整体,不希望分组
/(\d+\.){3}\d+/g $1 /?:(\d+\.){3}\d+/g $1
修饰符
修饰符 | 说明 |
---|---|
g | 表示全局匹配,即在整个字符串中搜索所有匹配项,而不仅仅是第一个匹配项 //g |
i | 表示在匹配时忽略大小写 //gi |
m | 表示多行模式,在这种模式下,正则表达式可以同时匹配每一行的内容,而不仅仅是整个字符串 /^python/gim |
u | 表示在匹配时进行完全递归,这样可以处理一些较为复杂和嵌套的情况 |
s | 在默认情况下,.元字符匹配除了换行符之外的任意字符。但是在设置了s修饰符后,.元字符也会匹配换行符 /<a.*?>(.*?)<\/a>/gims |
m模式
主要影响^和$符合的行为
s模式
点号可以匹配换行
js
中的正则表达式
定义正则表达式
const re = /1\d{10}/g const re1 = new RegExp("1\d{10}", "g")
字符串的正则方法
通过字符串调用的方法
search() 被匹配的最开始索引
没有匹配到就返回-1
const re = /1\d{10}/g const s = "我的手机号是 15254586535" console.log(s.search(re)) // 7最开始匹配到的索引
match() 正则匹配
console.log(s.match(re))
replace()
正则替换
console.log("大傻春,你要干什么!你是大傻叉吗".replace("傻", "*")) console.log("大傻春,你要干什么!你是大傻叉吗".replaceAll("傻", "*")) console.log("大傻春,你要干什么!你是大傻叉吗".replace(/[傻叉]/g, "*"))
使用分组替换
const r = /(1\d{10}).*?([\w-]+@\w+\.\w+)/g const str = "my phone is : 15252523256, my email is: 525416@qq.com" concole.log(str.replace(r, "我的手机号, $1, 邮箱: $2"))
正则表达式函数
const r = /(1\d{10}).*?([\w-]+@\w+\.\w+)/g const str = "my phone is : 15252523256, my email is: 525416@qq.com" concole.log(str.replace(r, function(data, g1, g2){ // (data, ...args) console.log(data, args) console.log(data, args) return `我的手机号, ${g1}, 邮箱: ${g2}` })
concole.log(str.replace(r, function(data, g1, g2){ const tel = Number(g1)+1 return `我的手机号, ${tel.toString()}, 邮箱: ${g2}` })
正则方法
通过正则对象调用的方法
test() 是否匹配
console.log(/abc/.test("abcd")) // true console.log(/abc/.test("abd")) // false
execl()
方法
可以使用分组,第一个参数就是正则表达式匹配的内容
后面的参数就是分组匹配的内容
const r = /'(1\d{10})'/g console.log(r.exec("my phone is: '15252523256'")) console.log(res[1]) // 第一个分组
具名分组
const r = /(?<phone>1\d{10}).*?(?<email>[\w-]+@\w+\.\w+)/g res = r.exec("my phone is : 15252523256, my email is: 525416@qq.com")) console.log(res.groups.phone)
9、class
在过去,JavaScript 是一门基于原型的面向对象编程语言,没有 Class 和模块化的概念。这导致了代码的组织结构混乱,难以维护和扩展
类和对象
我们生活中有很多的车,小车,汽车,自行车,火车,摩托车,电动车
他们都是属于“车”这么一类
具体的一辆你在2024年买的一辆四个轮子的小车,这就叫对象
class定义
class Animal{ name age class1 constructor(name, age) { // 传参 this.name = name this.age = age class1 = "碳基生物" } eat(){ console.log(`${this.name}在吃饭`) } } const cat = new Animal("加菲猫", 5) console.log(cat) cat.eat()
其中的constructor属于构造方法,name、age属于对象属性,eat属于对象方法
其中的eat方法是在原型上的
*继承
使用class之后就能很方便的使用继承功能
使用 extends
继承父类,super()
用于实例化继承的类
class Animal{ name constructor(name) { this.name = name } eat(){ console.log(`${this.name}在吃饭`) } } // 猫继承动物的属性或方法 class Cat extends Animal{ color constructor(name, color) { super(name); this.color = color } running(){ console.log("猫在行走") } } const cat = new Cat("加菲猫", "白色") console.log(cat)
静态属性和方法
只能由类去调用
// 只能由类去调用 class Animal{ static name = "动物" static eat(){ console.log(`在吃饭`) } } Animal.eat() console.log(Animal.name)
10、js
模块化
模块化是指将一个复杂的程序依据一定的规则(规范)封装成几个块(文件),并进行组合在一起
最早我们开发将所有的代码写在一个js
文件中,随着需求越来越复杂,代码量越来越大,如果仍然把所有代码写在一个js
文件中,那么代码耦合度过高不方便后期维护,也不方便程序员找到某一个功能点的代码
模块化将一个复杂的js
文件按共同或类似的逻辑拆分成多个js
文件,拆封的文件内部数据是私有的,只是向外部暴露一些接口(方法)与其他模块通信,不仅方便找到某一块功能点的代码,也可以达到复用的效果
ES6
实现模块化
重点是引入js
的地方,必须要有一个 type="module"
<script src="module/index.js" type="module"></script>
然后子模块可以使用 export
将成员抛出
父模块使用 import
将子模块的成员导入
导入的时候,把
js
文件的后缀写完
export 具体成员
// ./module/m1.js export function add(x, y){ return x+y } export const name = "枫枫" export const obj = { name: "fengfeng" }
<script type="module"> import {add, name, obj} from "./module/m1.js"; </script>
export default
export default { obj: { name: "张三" }, add, // add: add, }
<script type="module"> import m1 from "./module/m1.js"; import {add, name, obj} from "./module/m1.js"; </script>
立即执行函数实现模块化
除了可以用使用对象进行成员隔离
还可以使用立即执行函数创造一个封闭的代码空间
const m1 = (function (){ function add(a, b){ return a+b } return { add: add, } }()) const m2 = (function (){ function add(){ return "this is m2 add" } return { add: add, } }()) console.log(m1.add(1,2)) console.log(m2.add())
模块化实现
-
IIFE
,就是匿名函数自执行的方式(闭包)
<!-- 向window对象上添加全局属性,也有的把这种方法叫做添加命名空间 --> <!-- 目的就是向外暴露方法(接口),方法很好,但是多个模块之间有相互依赖关系就不好办了 --> <script type="text/javascript"> (function(win){ function aFn(){ // ... } function bFn(){ // ... } // 向外暴露方法,es6的写法 win.myMethod = {aFn, bFn} })(window) </script>
-
IIFE
,模式增强:向入口中传入依赖的模块
<!-- 假设依赖jq,这种方式引入的js文件、模块,必须有一定的先后顺序,否则报错undefined --> <script type="text/javascript"> (function(win){ function aFn(){ $(body).css(...) } function bFn(){ // ... } // 向外暴露方法,es6的写法 win.myMethod = {aFn, bFn} })(window,jQuery); </script>
模块化的好处
<!-- 在面试时背下来就好 -->
-
避免命名冲突(减少命名空间污染)
-
更好的分离,按需加载
-
更高的复用性、高可维护性
引入多个script后会出现的问题
引入多个script之后,会不可避免的出现请求的交叉
-
请求过多
-
依赖会乱掉,依赖模糊
-
难以维护,各种调用交织在一起
这也就促使真正上的模块化的出现,就是后来的common.js,AMD,es6,CMD
// sum.js function sum(a,b){ return a+b }
<scrtpt src="./sum.js"></scrtpt> <!-- 全局污染 --> <scrtpt src="./sum.js" type="module"></scrtpt>
导出
// sum.js function sum(a,b){ return a+b } export default sum; /* 不会污染全局 */
// main.js import sum from './sum.js'; console.log(sum);
<scrtpt src="./main.js" type="module"></scrtpt>
官方包管理 npm
dd
社区包管理 yarn
pnpm
cnpm
npm i jquery npm i jquery@1 // 安装版本1 npm uninstall jquery
11、BOM
浏览器对象模型
BOM
(Browser Object Model):浏览器对象模型
-
BOM
的核心就是window对象 -
window是浏览器内置的一个对象,里面包含着操作浏览器的方法
History 浏览器记录
history.back
(上一页)相当于浏览器上的返回按钮
history.forword
(下一页)相当于浏览器上的前进按钮
history.go(n)
n为正时向前n页,n为负时后退n页
<button οnclick="forword()">前进</button> <button οnclick="back()">后退</button> <button οnclick="go(1)">前进1页</button> <button οnclick="go(-1)">后退1页</button> <script> function forword(){ history.forward() } function back(){ history.back() } function go(n){ history.go(n) } </script>
Location 浏览器地址
以http://do.com:3000/xx/yy?name=ff为例,除了源地址其他属性可以重新赋值
属性 | 值 | 说明 |
---|---|---|
location.portocol | http: | 页面使用的协议,通常是http: 或https: |
location.hostname | do.com | 服务器域名 |
location.port | 3000 | 请求的端口号 |
location.host | do.com:3000 | 服务器名及端口号 |
location.origin | http://do.com:3000 | url 的源地址,只读 |
location.href | 完整的url 地址 | 等价于window.location |
location.pathname | / (这里指的是3000后面的/ ) | url 中的路径和文件名,不会返回hash和search后面的内容,只有当打开的页面是一个文件时才会生效 |
location.search | ?name=ff | 查询参数 |
location.reload()
刷新页面
location.replace()
替换页面
-
不会保留当前页面的历史记录,因此用户无法通过浏览器的后退按钮返回到之前的页面
对话框
alert 提示框
console.log(alert("这是一个提示信息"))
confirm 询问框
console.log(confirm("确定要删除吗?")) // 阻塞代码
可以获取到用户点击的确定和取消的操作,确定就是true,取消就是false
prompt 输入框
console.log(prompt("今天晚上吃什么?", "西北风")) // 阻塞代码
定时器
setTimeout
-
倒计时多少时间以后执行函数
-
语法:
setTimeout(要执行的函数,多少时间以后执行)
-
单位是毫秒,返回值是当前这个定时器是页面中的第几个定时器
-
可以使用
clearTimeout
关闭定时器
function handler(){ console.log("handler") } setTimeout(handler, 3000) const timer = setTimeout(handler, 3000) // 页面中的第几个定时器 console.log(timer) clearTimeout(timer) // 关闭定时器
setInterval
-
每隔多少时间执行一次函数
-
语法:
setInterval(要执行的函数,间隔多少时间)
-
只要不关闭,会一直执行
-
可以使用
clearInterval
关闭定时器
let count = 0; const timer1 = setInterval(()=>{ if (count === 3){ clearInterval(timer1) return } console.log(new Date().toLocaleString()) count ++ }, 1000) // 间隔执行,第一个参数是函数,第二个是间隔时间 console.log(timer1)
防抖和节流
用户点击按钮的时候,点太快了点了两下,那么这个函数就会被执行两次
debounce
、throttle
防抖
在事件被触发n秒后执行回调,如果在这n秒内事件又被触发,则重新计时
类似于回城,被打断就要重新开始(重新计时)
<button οnclick="newHandler('hello')">1</button> <script> function handler(name){ console.log("被点击了", name) } function debounce(fn, delay) { // 函数,防抖时间 let timer = null; return function() { clearTimeout(timer); // 之前如果有计时器要清除 timer = setTimeout(() => { fn.apply(this, arguments); }, delay); } } </script> const newHandler = debounce(handler, 300)
节流
在规定的单位时间内,只能有一次触发事件的回调函数执行,如果在同一时间内被触发多次,只会生效一次
类似于技能CD,CD没好,你用不了技能
节流的逻辑要稍微复杂一点,首先事件触发之后是要立即执行的,后续再触发时间则要看看是不是在设定的时间阈值内,在的话就不执行,不在就立即执行
<button οnclick="throttleHandler('hello')">1</button> <script> function throttle(fn, delay) { let timer = null; let startTime = Date.now(); // new Date().getTime() return function () { // 判断现在的时间 const curTime = Date.now(); // 节流时间-两个时间的时间戳 const remaining = delay - (curTime - startTime); // 清除定时器 clearTimeout(timer); // 已经超过时间差了,直接执行 if (remaining <= 0) { fn.apply(this, arguments); startTime = Date.now(); } else { // 还没到时间差,设置一个定时器去执行 timer = setTimeout(() => { fn.apply(this, arguments); startTime = Date.now(); }, remaining); } }; } </script> const throttleHandler = throttle(handler, 300)
window界面属性
屏幕,窗口,视口
console.log("视口", window.innerWidth, window.innerHeight) console.log("窗口", window.outerWidth, window.outerHeight) console.log("屏幕", window.screen.width, window.screen.height)
滚动相关
文档向右或者向下滚动的距离
scrollX
scrollY
只针对body的滚动条才有效
定位:scrollTo
(绝对)scrollBy
(相对)
// 滚动到页面左上角 window.scrollTo(0,0) // 滚动到页面左边100像素和顶部200像素的位置 window.scrollTo(100,200) // 当前视口向下滚动100像素 window.scrollBy(0,100) // 当前视口向右滚动40像素 window.scrollBy(40,0)
平滑滚动
// 平滑滚动 window.scrollTo({top: 1200, behavior: "smooth"})
Navigator(浏览器信息)
属性 | 描述 |
---|---|
navigator.userAgent | 获取浏览器的整体信息 |
navigator.appName | 获取浏览器名称 |
navigator.appVersion | 获取浏览器的版本号 |
navigator.platform | 获取当前计算机的操作系统 |
12、DOM文档对象模型
DOM是“Document Object Model”的首字母缩写,即文档对象模型。用来描绘一个层次化的节点树,允许开发人员获取、添加、移除和修改页面的某一部分元素
获取元素
通过id获取
const dom = document.getElementById("box1") console.log(dom)
通过css
选择器获取
// console.log(document.getElementsByClassName("name"))用的很少 console.log(document.querySelector(".name")) console.log(document.querySelector("#name")) console.log(document.querySelectorAll(".name"))
Element元素对象
元素tag 标签名
dom.tagName // 获取标签名
属性
// 属性操作 const a = document.getElementById("a") // 获取属性 console.log(a.getAttribute("href")) // 设置、修改属性 a.setAttribute("href", "https://www.fengfengzhidao.com") // 删除属性 a.removeAttribute("xxx")
dataset 标签属性
可以以对象的形式获取、设置标签属性
<div id="box" data-name="枫枫"> <!-- 必须带上data- --> 这是一个盒子 </div> <script> const dom = document.getElementById("box") // 获取 console.log(dom.dataset.name) console.log(dom.dataset["name"]) console.log(dom.dataset) // 设置 dom.dataset.addr = "长沙市" // 删除 delete dom.dataset.name // 可以使用自定义属性的方式 console.log(dom.getAttribute("data-addr")) </script>
classList
class名
以数组的形式获取、操作标签的class
<div class="box"> </div> <script> const box = document.querySelector(".box") console.log(box.classList) // 添加标签类名 box.classList.add("head") // 是否包含 console.log(box.classList.contains("head")) // 有就删除,没有就创建 box.classList.toggle("footer") box.classList.toggle("footer") // 删除 box.classList.remove("head") // 替换 box.classList.replace("box", "box1") </script>
outerHTML
、innerHTML
、innerText
<div id="box"> <a href="htt://www.fengfengzhidao.com">点我</a> <span>你好</span> </div> <script> const box = document.getElementById("box") console.log(box.innerText) console.log(box.innerHTML) console.log(box.outerHTML) // box.innerText = "<a>xxx</a>" // box.innerHTML = `<div><span>234</span></div>` // box.outerHTML = "<a>xxx</a>" </script>
style 样式
设置或读取css
样式
如果通过 style
属性去获取样式,则只能获取行内样式,不能获取其他地方的样式
对于
-
相连的css
属性名,要么使用[]
来调用属性,要么转换成小驼峰命名的方式
<div class="name" style="font-size: 20px; background-color: #800e0e; color: white">枫枫知道</div> <script> const dom = document.querySelector(".name") // 获取样式 console.log(dom.style.fontSize) console.log(dom.style.backgroundColor) console.log(dom.style.color) console.log(dom.style.textAlign) // 只能获取行内的,其他地方的获取不到 // 设置样式 dom.style.fontSize = "30px" dom.style.padding = "30px" </script>
可以通过 getComputedStyle
可以获取到的元素的计算之后的样式信息
console.log(getComputedStyle(dom).textAlign) // 获取计算后的style样式
节点操作
节点的操作主要就是增删改查
创建节点
document.createElement
// 创建节点 const dom = document.createElement("a") dom.setAttribute("href", "https://www.fengfengzhidao.com") dom.innerText = "枫枫知道"
插入子节点
给一个已知的节点去插入一个新的节点
appendChild
,在父节点的最后一个子节点后插入一个节点
append
,在父节点的最后一个子节点后插入多个不同的节点
insertBefore
,在父节点的子节点之前插入节点,第二个参数为null就是append
// 插入子节点 const box = document.getElementById("box") // box.appendChild(dom) // box.append(dom) // 在任意位置之前插入 // box.insertBefore(dom, null) // 在末尾插入 // box.insertBefore(dom, box.children[1]) // 在第二个元素前插入 // box.insertBefore(dom, document.querySelector(".d2"))
添加兄弟节点
after 在后面插入
before 在前面插入
const d1 = document.querySelector(".d1") // d1.before(dom) // 在d1的前面插入 d1.after(dom) // 在d1的后面插入
删除节点
node.removeChild()
从DOM中删除一个子节点。返回删除的节点
node.remove()
删除自身,没有返回值
const d2 = document.querySelector(".d2") console.log(d2.removeChild(d2.querySelector(".dd2"))) // 删除子节点,并返回被删除的子节点 d2.remove() // 删除自己
父子节点
const d2 = document.querySelector(".d2") console.log(d2.children) // 获取它的子节点列表 console.log(d2.parentNode) // 获取它的父亲节点
事件
JS
事件,就是用户或浏览器本身的某种行为,一般是用户对页面的一些动作引起的
例如,单击某个链接或按钮、在文本框中输入文本、按下键盘上的某个按键、移动鼠标等等
当事件发生时,您可以使用 JavaScript 中的事件处理程序(也可称为事件监听器)来检测并执行某些特定的程序。
一般情况下事件的名称都是以单词on开头的,例如点击事件 onclick
、页面加载事件 onload
等
事件有三种绑定方式,分别是:
在标签上绑定事件
<input placeholder="用户名" οninput="input(event)"> <button>点我</button> <script> function input(e){ console.log(e.target.value) } </script>
在dom中绑定事件
const btn = document.querySelector(".btn") btn.onclick = function (e){ console.log(e.target) // 获取被点击的dom对象 }
添加事件监听
function click(e){ console.log(e.target) } btn.addEventListener("click", click) // btn.addEventListener("click", function (e){ // console.log(2, e.target) // }) // 移除事件 const removeEvent = document.querySelector(".remove_event") removeEvent.onclick = function (){ btn.removeEventListener("click", click) }
需要记住的一些事件
load 加载完成 resize 窗口大小变化 scroll 滚动事件 blur 失去焦点 focus 获得焦点 click 用户单击鼠标左键或按下回车键触发 dbclick 用户双击鼠标左键触发。 mousedown 在用户按下了任意鼠标按钮时触发 mouseenter 在鼠标光标从元素外部首次移动到元素范围内时触发。此事件不冒泡 mouseleave 元素上方的光标移动到元素范围之外时触发。不冒泡 mousemove 光标在元素的内部不断的移动时触发 mouseover 鼠标指针位于一个元素外部,然后用户将首次移动到另一个元素边界之内时触发 mouseout 用户将光标从一个元素上方移动到另一个元素时触发 mouseup 在用户释放鼠标按钮时触发 keydown 当用户按下键盘上的任意键时触发。按住不放,会重复触发 keypress 当用户按下键盘上的字符键时触发。按住不放,会重复触发 keyup 当用户释放键盘上的键时触发 textInput 这是唯一的文本事件,用意是将文本显示给用户之前更容易拦截文本
事件 | 描述 |
---|---|
onchange | HTML 元素改变 |
onclick | 用户点击 HTML 元素 |
onmouseover | 鼠标指针移动到指定的元素上时发生 |
onmouseout | 用户从一个 HTML 元素上移开鼠标时发生 |
onkeydown | 用户按下键盘按键 |
onload | 浏览器已完成页面的加载 |
事件冒泡
当一个事件被触发时,它首先在最内层的元素(也称为目标元素或事件源)上发生
然后,这个事件会向上冒泡,依次触发其父元素上的同一类型事件,一直冒泡到最外层元素,通常是document对象
这种冒泡机制允许我们在父元素上设置事件处理器,以便在子元素的事件发生时执行特定的操作
<style> .p2{ display: flex; justify-content: center; align-items: center; } </style> <div class="p1"> <div class="p2"> <div class="p3">我是p3</div> </div> </div> <script> const p1 = document.querySelector(".p1") const p2 = document.querySelector(".p2") const p3 = document.querySelector(".p3") p3.onclick = function (e){ console.log("p3", e.target) } p2.onclick = function (e){ console.log("p2", e.target) // event.stopPropagation() // 阻止冒泡 } p1.onclick = function (e){ console.log("p1", e.target) } </script>
阻止冒泡
event.stopPropagation()
阻止事件的默认行为
常规情况下点击a标签会自动跳转至页面这是事件的默认行为,若不想要这个效果,即可使用阻止事件的默认行为即可实现
<a href="baidu.com">百度</a> <script> const a = document.querySelector("a") a.onclick = function(e){ console.log(e.target) e.preventDefault() // 阻止事件的默认行为 } </script>
很多网站都有,点击外部链接会有安全提示
const a = document.querySelector("a") a.onclick = function (e){ const ok = confirm(`你确定要访问 ${e.target.getAttribute("href")}吗`) if (!ok){ e.preventDefault() // 取消标签的默认行为 } }
事件委托
事件委托,又叫事件代理。事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件
比如说有100个子节点,像实现点击子节点执行某个函数,给100个子节点去绑定事件明显不划算,就可以通过事件委托来实现
<div class="box"> <div class="s s1">s1</div> <div class="s s2">s2</div> <div class="s s3">s3</div> <div class="s s4">s4</div> <div class="s s5">s5</div> </div> <script> const box = document.querySelector(".box") box.onclick = function (e){ console.log(e.target) } </script>
事件循环
JavaScript事件循环是一种机制,用于处理异步事件和回调函数。它是JavaScript运行时环境的一部分,负责管理事件队列和调用栈
事件循环的基本原理是事件循环的核心是一个事件队列,所有的事件都被放入这个队列中,然后按照顺序依次执行。如果队列为空,JavaScript会等待新的任务加入队列。当JavaScript代码执行时,所有同步任务都会被立即执行,而异步任务则会被放入事件队列中
当所有同步任务执行完毕后,事件循环会从事件队列中取出一个任务,并将其放入调用栈中执行。当该任务执行完毕后,事件循环会再次从事件队列中取出下一个任务,并重复这个过程
// 什么是异步任务 console.log(1) setTimeout(() => { console.log(3) }, 0) console.log(2) // 顺序 1 2 3 // 当同步任务执行完之后,才会从任务队列中执行异步任务
宏任务和微任务
异步任务也分宏任务和微任务
宏任务包括setTimeout
、setInterval
、I/O操作等
微任务包括Promise
、MutationObserver
等
当事件循环从事件队列中取出一个任务时,它会先执行所有微任务,然后再执行一个宏任务。这个过程会一直重复,直到事件队列中的所有任务都被执行完毕
console.log('1'); setTimeout(function() { console.log('2'); Promise.resolve().then(function() { console.log('3'); }); }, 0); Promise.resolve().then(function() { console.log('4'); }); console.log('5'); // 输出结果为: 1 5 4 2 3
执行顺序:
-
执行第一个
console.log
,输出1。 -
执行
setTimeout
,将其回调函数放入宏任务队列中。 -
执行
Promise.resolve().then
,将其回调函数放入微任务队列中。 -
执行第二个
console.log
,输出5。 -
当前任务执行结束,执行微任务队列中的所有任务,输出4。
-
执行宏任务队列中的第一个任务,即
setTimeout
的回调函数,输出2。 -
执行
Promise.resolve().then
的回调函数,输出3。
需要注意的是,微任务和宏任务的执行顺序是固定的,即先执行所有微任务,再执行宏任务。因此,如果在一个宏任务中产生了新的微任务,那么这些微任务会在下一个宏任务执行之前执行。
console.log('1'); setTimeout(function() { console.log('2'); Promise.resolve().then(function() { console.log('3'); }); }, 0); Promise.resolve().then(function() { console.log('4'); setTimeout(function() { console.log('5'); }, 0); }); console.log('6'); // 输出结果为:1 6 4 2 3 5
执行顺序:
-
执行第一个
console.log
,输出1。 -
执行
setTimeout
,将其回调函数放入宏任务队列中。 -
执行
Promise.resolve().then
,将其回调函数放入微任务队列中。 -
执行第三个
console.log
,输出6。 -
当前任务执行结束,执行微任务队列中的所有任务,输出4。
-
执行宏任务队列中的第一个任务,即
setTimeout
的回调函数,输出2。 -
执行
Promise.resolve().then
的回调函数,将setTimeout的回调函数放入宏任务队列中。 -
当前任务执行结束,执行微任务队列中的所有任务,输出3。
-
执行宏任务队列中的第一个任务,即
setTimeout
的回调函数,输出5
<!-- -->
es6
解构赋值
// 一般用常量const声明,需要改的时候在改成变量let const [a, b, c] = [1, 2, 3] const str = `abc${a}` const { username, age:userAge, ...otherInfo } = { username: '杨小槿', age: 18, gender: 'male', category: 'user' } console.log(username, userAge, otherInfo)
数组和对象的扩展
const arr1 = [1, 2, 3] const arr2 = [4, 5, 6] const arr3 = [...arr1, ...arr2, 10] const obj1 = { a:1 } const obj2 = { b:2, ...obj1 }
// 数组方法 Array.from() arguments打印实参 function fn(){ console.log(arguments) arguments.push(1) } fn(1,2,3,4) // ------------ function fn(){ Array.from(arguments).forEach(function(item){ console.log(item) }) } fn(1,2,3,4)
// 对象方法 Object.assign() const objA = { name: '杨小槿', age: 18 } const objB = Object.assign({}, objA) // Object.assign({},objA,objB,objC) objB.name='a' console.log(objA,objB)
Class
class A{ constructor (name, age) { this.name = name this.age = age } introduce(){ console.log(`我的名字是${this.name},年龄${this.age}`) } } const a1 = new A('杨小槿', 18) a1.introduce() class B extends A { constructor (name, age, gender) { super(name, age) this.gender = gender } sayHello(){ console.log('泥蒿'+this.name) } } const b1 = new B('小李', 19, '女') b1.introduce() b1.sayHello()
箭头函数
const getSum1 = function(n){ return n+3 } const getSum1 = n => n + 3 console.log(getSum1(10)) const getSum2 = (n1, n2) => n1 + n2 const getSum3 = (n1, n2, ...other) => console.log(n1, n2, other) getSum3(10, 20, 100, 200, 300) const getSum1 = n => { return n + 3 }
异步处理
promise解决异步写法中的嵌套问题
const p1 = new Promise((resolve, reject)=>{ resolve('任务成功得到的数据') //reject() }) p1.then(data = >{ console.log(data) })
const p1 = new Promise((resolve, reject)=>{ // resolve('任务成功得到的数据') reject('任务失败得到的数据') }) p1.then(data = >{ console.log(data) return new Promise((resolve, reject)=>{ // resolve('任务成功得到的数据') reject('任务失败得到的数据') }) }) .catch(err => { console,log(err) })
// Async await function asyncTask(){ return new Promise((resolve, reject)=>{ const isSuccess = true if (isSuccess){ resolve('任务二的成功处理结果') } else { reject('任务二的失败处理结果') } }) } async function main(){ console.log('任务一') cost data = await asyncTask() console.log(data) console.log('任务三') } main()
// Proxy代理对象 const obj = {name:'杨小槿', age:18} const container = document.getElementById('container') container.textContent = obj.name obj.name = 'abc'
......